[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);
}
}