[cfe] Use i2b at the end of function call inference

Closes #45598.

Bug: https://github.com/dart-lang/sdk/issues/45598
Change-Id: I37430faf057e3559ad6aefaa59d83d8a14320c54
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/194764
Commit-Queue: Dmitry Stefantsov <dmitryas@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
index bdf54c8..5e8e77f 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_schema_environment.dart
@@ -10,10 +10,13 @@
 
 import 'package:kernel/core_types.dart' show CoreTypes;
 
-import 'package:kernel/type_algebra.dart' show Substitution;
+import 'package:kernel/type_algebra.dart'
+    show FreshTypeParameters, Substitution, getFreshTypeParameters, substitute;
 
 import 'package:kernel/type_environment.dart';
 
+import 'package:kernel/src/bounds_checks.dart' show calculateBounds;
+
 import 'package:kernel/src/hierarchy_based_type_environment.dart'
     show HierarchyBasedTypeEnvironment;
 
@@ -357,6 +360,42 @@
             preferUpwardsInference: !typeParam.isLegacyCovariant);
       }
     }
+
+    if (!downwardsInferPhase) {
+      assert(typeParametersToInfer.length == inferredTypes.length);
+      FreshTypeParameters freshTypeParameters =
+          getFreshTypeParameters(typeParametersToInfer);
+      List<TypeParameter> helperTypeParameters =
+          freshTypeParameters.freshTypeParameters;
+
+      Map<TypeParameter, DartType> inferredSubstitution =
+          <TypeParameter, DartType>{};
+      for (int i = 0; i < helperTypeParameters.length; ++i) {
+        if (inferredTypes[i] is UnknownType) {
+          inferredSubstitution[helperTypeParameters[i]] =
+              new TypeParameterType.forAlphaRenaming(
+                  helperTypeParameters[i], helperTypeParameters[i]);
+        } else {
+          assert(isKnown(inferredTypes[i]));
+          inferredSubstitution[helperTypeParameters[i]] = inferredTypes[i];
+        }
+      }
+      for (int i = 0; i < helperTypeParameters.length; ++i) {
+        if (inferredTypes[i] is UnknownType) {
+          helperTypeParameters[i].bound =
+              substitute(helperTypeParameters[i].bound, inferredSubstitution);
+        } else {
+          helperTypeParameters[i].bound = inferredTypes[i];
+        }
+      }
+      List<DartType> instantiatedTypes = calculateBounds(
+          helperTypeParameters, coreTypes.objectClass, clientLibrary);
+      for (int i = 0; i < instantiatedTypes.length; ++i) {
+        if (inferredTypes[i] is UnknownType) {
+          inferredTypes[i] = instantiatedTypes[i];
+        }
+      }
+    }
   }
 
   @override
@@ -423,7 +462,9 @@
   /// of constraints.
   ///
   /// If [grounded] is `true`, then the returned type is guaranteed to be a
-  /// known type (i.e. it will not contain any instances of `?`).
+  /// known type (i.e. it will not contain any instances of `?`) if it is
+  /// constrained at all.  The returned type for unconstrained variables is
+  /// [UnknownType].
   ///
   /// If [isContravariant] is `true`, then we are solving for a contravariant
   /// type parameter which means we choose the upper bound rather than the
@@ -449,7 +490,7 @@
             ? greatestClosure(constraint.upper, topType, bottomType)
             : constraint.upper;
       } else {
-        return grounded ? const DynamicType() : const UnknownType();
+        return const UnknownType();
       }
     } else {
       // Prefer the known bound, if any.
@@ -467,7 +508,7 @@
             ? leastClosure(constraint.lower, topType, bottomType)
             : constraint.lower;
       } else {
-        return grounded ? bottomType : const UnknownType();
+        return const UnknownType();
       }
     }
   }
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
index 67cfacc..a1448b7 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_nnbd_test.dart
@@ -1403,8 +1403,10 @@
     // Solve(? <: T <: ?) => ?
     checkConstraintSolving("", "UNKNOWN", grounded: false);
 
-    // Solve(? <: T <: ?, grounded) => dynamic
-    checkConstraintSolving("", "dynamic", grounded: true);
+    // Solve(? <: T <: ?, grounded) => ?
+    // Fully unconstrained variables are inferred via instantiate-to-bounds
+    // rather than constraint solving.
+    checkConstraintSolving("", "UNKNOWN", grounded: true);
 
     // Solve(A <: T <: ?) => A
     checkConstraintSolving(":> A<dynamic>*", "A<dynamic>*", grounded: false);
diff --git a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
index ba48bb9..027bac2 100644
--- a/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
+++ b/pkg/front_end/test/fasta/type_inference/type_schema_environment_test.dart
@@ -493,8 +493,10 @@
     // Solve(? <: T <: ?) => ?
     checkConstraintSolving("", "UNKNOWN", grounded: false);
 
-    // Solve(? <: T <: ?, grounded) => dynamic
-    checkConstraintSolving("", "dynamic", grounded: true);
+    // Solve(? <: T <: ?, grounded) => ?
+    // Fully unconstrained variables are inferred via instantiate-to-bounds
+    // rather than constraint solving.
+    checkConstraintSolving("", "UNKNOWN", grounded: true);
 
     // Solve(A <: T <: ?) => A
     checkConstraintSolving(":> A*", "A*", grounded: false);
diff --git a/pkg/front_end/testcases/general/issue45598.dart b/pkg/front_end/testcases/general/issue45598.dart
new file mode 100644
index 0000000..ad18575
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {
+  bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect
new file mode 100644
index 0000000..734e138
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..734e138
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.expect
new file mode 100644
index 0000000..fc68d7b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic {
+  bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect
new file mode 100644
index 0000000..829a44c
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect
new file mode 100644
index 0000000..fc68d7b
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598.dart.weak.transformed.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({m: core::Map<Y*, Z*>*}) →* dynamic bar, core::Map<core::String*, core::String*>* m) → dynamic {
+  bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart b/pkg/front_end/testcases/general/issue45598_2.dart
new file mode 100644
index 0000000..61a731e
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// @dart=2.9
+
+foo(Map<String, String> m) {
+  void bar<X extends Z, Y, Z>({Map<Y, Z> m}) {}
+  bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect
new file mode 100644
index 0000000..983b1d0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..983b1d0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,3 @@
+// @dart = 2.9
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect
new file mode 100644
index 0000000..d8d1fd0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic {
+  function bar<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({core::Map<Y*, Z*>* m = #C1}) → void {}
+  bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect
new file mode 100644
index 0000000..9efffa9a
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect b/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..d8d1fd0
--- /dev/null
+++ b/pkg/front_end/testcases/general/issue45598_2.dart.weak.transformed.expect
@@ -0,0 +1,13 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String*, core::String*>* m) → dynamic {
+  function bar<X extends Z* = dynamic, Y extends core::Object* = dynamic, Z extends core::Object* = dynamic>({core::Map<Y*, Z*>* m = #C1}) → void {}
+  bar.call<core::String*, core::String*, core::String*>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart b/pkg/front_end/testcases/nnbd/issue45598.dart
new file mode 100644
index 0000000..8c8267e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {
+  bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.strong.transformed.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect
new file mode 100644
index 0000000..50b6ae2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..50b6ae2
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+foo(Function<X extends Z, Y, Z>({Map<Y, Z> m}) bar, Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect
new file mode 100644
index 0000000..9ad166e
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect
new file mode 100644
index 0000000..a1055bf
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598.dart.weak.transformed.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({m: core::Map<Y%, Z%>}) → dynamic bar, core::Map<core::String, core::String> m) → dynamic {
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart b/pkg/front_end/testcases/nnbd/issue45598_2.dart
new file mode 100644
index 0000000..49350a9
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+foo(Map<String, String> m) {
+  void bar<X extends Z, Y, Z>({required Map<Y, Z> m}) {}
+  bar(m: m);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+  function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.strong.transformed.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+  function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect
new file mode 100644
index 0000000..853274f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline.expect
@@ -0,0 +1,2 @@
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..853274f
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.textual_outline_modelled.expect
@@ -0,0 +1,2 @@
+foo(Map<String, String> m) {}
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+  function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect
new file mode 100644
index 0000000..1e7263b
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.outline.expect
@@ -0,0 +1,8 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic
+  ;
+static method main() → dynamic
+  ;
diff --git a/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect
new file mode 100644
index 0000000..9c145d3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue45598_2.dart.weak.transformed.expect
@@ -0,0 +1,13 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+static method foo(core::Map<core::String, core::String> m) → dynamic {
+  function bar<X extends Z% = dynamic, Y extends core::Object? = dynamic, Z extends core::Object? = dynamic>({required core::Map<Y%, Z%> m = #C1}) → void {}
+  bar.call<core::String, core::String, core::String>(m: m);
+}
+static method main() → dynamic {}
+
+constants  {
+  #C1 = null
+}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index a0d9fb8..17b0a06 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -165,13 +165,18 @@
       new List<DartType>.filled(typeParameters.length, dummyDartType);
   for (int i = 0; i < typeParameters.length; i++) {
     DartType? bound = typeParameters[i].bound;
+    bool isContravariant = typeParameters[i].variance == Variance.contravariant;
     if (bound == null) {
-      bound = const DynamicType();
+      bound = isNonNullableByDefault && isContravariant
+          ? const NeverType.nonNullable()
+          : const DynamicType();
     } else if (bound is InterfaceType && bound.classNode == objectClass) {
       DartType defaultType = typeParameters[i].defaultType!;
       if (!(defaultType is InterfaceType &&
           defaultType.classNode == objectClass)) {
-        bound = const DynamicType();
+        bound = isNonNullableByDefault && isContravariant
+            ? const NeverType.nonNullable()
+            : const DynamicType();
       }
     }
     bounds[i] = bound;
@@ -193,8 +198,10 @@
     Substitution substitution =
         Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
     for (int typeParameterIndex in component) {
-      bounds[typeParameterIndex] =
-          substitution.substituteType(bounds[typeParameterIndex]);
+      bounds[typeParameterIndex] = substitution.substituteType(
+          bounds[typeParameterIndex],
+          contravariant: typeParameters[typeParameterIndex].variance ==
+              Variance.contravariant);
     }
   }
 
@@ -206,7 +213,8 @@
     Substitution substitution =
         Substitution.fromUpperAndLowerBounds(upperBounds, lowerBounds);
     for (int j = 0; j < typeParameters.length; j++) {
-      bounds[j] = substitution.substituteType(bounds[j]);
+      bounds[j] = substitution.substituteType(bounds[j],
+          contravariant: typeParameters[j].variance == Variance.contravariant);
     }
   }