Version 2.11.0-159.0.dev
Merge commit 'd3114bac63b8ec22e8dfee4bb91b3f4c8c1fab59' into 'dev'
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
index 874d7be..2464c9a 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_constraint_gatherer.dart
@@ -8,8 +8,6 @@
import 'package:kernel/type_algebra.dart';
-import 'package:kernel/src/replacement_visitor.dart';
-
import 'package:kernel/type_environment.dart';
import 'type_schema.dart' show UnknownType;
@@ -877,12 +875,18 @@
List<_ProtoConstraint> constraints =
_protoConstraints.sublist(baseConstraintCount);
_protoConstraints.length = baseConstraintCount;
- _NullabilityAwareTypeVariableEliminator eliminator =
- new _NullabilityAwareTypeVariableEliminator(
- freshTypeParameters.freshTypeParameters.toSet(),
- const NeverType(Nullability.nonNullable),
- coreTypes.objectNullableRawType,
- coreTypes.functionNonNullableRawType);
+ NullabilityAwareTypeVariableEliminator eliminator =
+ new NullabilityAwareTypeVariableEliminator(
+ eliminationTargets:
+ freshTypeParameters.freshTypeParameters.toSet(),
+ bottomType: const NeverType(Nullability.nonNullable),
+ topType: coreTypes.objectNullableRawType,
+ topFunctionType: coreTypes.functionNonNullableRawType,
+ unhandledTypeHandler: (DartType type, ignored) =>
+ type is UnknownType
+ ? false
+ : throw new UnsupportedError(
+ "Unsupported type '${type.runtimeType}'."));
for (_ProtoConstraint constraint in constraints) {
if (constraint.isUpper) {
_constrainParameterUpper(constraint.parameter,
@@ -1177,85 +1181,3 @@
: "$bound <: ${parameter.name}";
}
}
-
-/// Eliminates specified free type parameters in a type.
-///
-/// The algorithm for elimination of type variables is described in
-/// https://github.com/dart-lang/language/pull/957
-class _NullabilityAwareTypeVariableEliminator extends ReplacementVisitor {
- final DartType bottomType;
- final DartType topType;
- final DartType topFunctionType;
- final Set<TypeParameter> eliminationTargets;
- bool isLeastClosure;
- bool isCovariant = true;
-
- _NullabilityAwareTypeVariableEliminator(this.eliminationTargets,
- this.bottomType, this.topType, this.topFunctionType);
-
- /// Returns a subtype of [type] for all values of [eliminationTargets].
- DartType eliminateToLeast(DartType type) {
- isCovariant = true;
- isLeastClosure = true;
- return type.accept(this) ?? type;
- }
-
- /// Returns a supertype of [type] for all values of [eliminationTargets].
- DartType eliminateToGreatest(DartType type) {
- isCovariant = true;
- isLeastClosure = false;
- return type.accept(this) ?? type;
- }
-
- DartType get typeParameterReplacement {
- return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
- ? bottomType
- : topType;
- }
-
- DartType get functionReplacement {
- return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
- ? bottomType
- : topFunctionType;
- }
-
- @override
- void changeVariance() {
- isCovariant = !isCovariant;
- }
-
- @override
- DartType visitFunctionType(FunctionType node) {
- // - if `S` is
- // `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
- // [Tn+1 xn+1, ..., Tm xm])`
- // or `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
- // {Tn+1 xn+1, ..., Tm xm})`
- // and `L` contains any free type variables from any of the `Bi`:
- // - The least closure of `S` with respect to `L` is `Never`
- // - The greatest closure of `S` with respect to `L` is `Function`
- if (node.typeParameters.isNotEmpty) {
- for (TypeParameter typeParameter in node.typeParameters) {
- if (containsTypeVariable(typeParameter.bound, eliminationTargets,
- unhandledTypeHandler: (DartType type, ignored) =>
- type is UnknownType
- ? false
- : throw new UnsupportedError(
- "Unsupported type '${type.runtimeType}'."))) {
- return functionReplacement;
- }
- }
- }
- return super.visitFunctionType(node);
- }
-
- @override
- DartType visitTypeParameterType(TypeParameterType node) {
- if (eliminationTargets.contains(node.parameter)) {
- return typeParameterReplacement.withDeclaredNullability(
- uniteNullabilities(
- typeParameterReplacement.nullability, node.nullability));
- }
- return super.visitTypeParameterType(node);
- }
-}
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 0d4d9c9..5217ca9 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
@@ -661,7 +661,7 @@
null,
inferredTypes,
testLib);
- expect(inferredTypes[0], coreTypes.numNonNullableRawType);
+ expect(inferredTypes[0], coreTypes.numLegacyRawType);
}
}
@@ -1066,13 +1066,13 @@
// TODO(dmitryas): Test for various nullabilities.
testUpper("T", "T", "T", typeParameters: "T extends Object");
- testUpper("T", "List<Never>", "List<Object>",
+ testUpper("T", "List<Never>", "List<Object?>",
typeParameters: "T extends List<T>");
- testUpper("List<Never>", "T", "List<Object>",
+ testUpper("List<Never>", "T", "List<Object?>",
typeParameters: "T extends List<T>");
- testUpper("T", "U", "List<Object>",
+ testUpper("T", "U", "List<Object?>",
typeParameters: "T extends List<T>, U extends List<Never>");
- testUpper("U", "T", "List<Object>",
+ testUpper("U", "T", "List<Object?>",
typeParameters: "T extends List<T>, U extends List<Never>");
}
diff --git a/pkg/front_end/test/spell_checking_list_code.txt b/pkg/front_end/test/spell_checking_list_code.txt
index 5985a19..fc4f4d0 100644
--- a/pkg/front_end/test/spell_checking_list_code.txt
+++ b/pkg/front_end/test/spell_checking_list_code.txt
@@ -73,6 +73,7 @@
b0i
b0m
b0n
+b1a
b1i
b1m
b1n
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart b/pkg/front_end/testcases/nnbd/issue43455.dart
new file mode 100644
index 0000000..8501673
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart
@@ -0,0 +1,46 @@
+// 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.
+
+assertRightSubtype(dynamic x) {
+ x as Set<Object?>;
+}
+
+assertLeftSubtype<X>(X x) {
+ new Set<Object?>() as X;
+}
+
+class C<X extends Object?, Y extends Object> {
+ test(X x, Y? y) {
+ var v = {x, 42}; // Checking UP(X, int).
+ var w = {42, x}; // Checking UP(int, X).
+ var p = {y, 42}; // Checking UP(Y?, int).
+ var q = {42, y}; // Checking UP(int, Y?).
+
+ // Check that variable types are both subtype and supertype of Set<Object?>.
+ assertRightSubtype(v);
+ assertLeftSubtype(v);
+ assertRightSubtype(w);
+ assertLeftSubtype(w);
+ assertRightSubtype(p);
+ assertLeftSubtype(p);
+ assertRightSubtype(q);
+ assertLeftSubtype(q);
+
+ // Check the same for intersection types.
+ if (x is Object?) {
+ var v = {x, 42}; // Checking UP(X & Object?, int).
+ var w = {42, x}; // Checking UP(int, X & Object?).
+
+ assertRightSubtype(v);
+ assertLeftSubtype(v);
+ assertRightSubtype(w);
+ assertLeftSubtype(w);
+ }
+ }
+}
+
+main() {
+ new C<int?, int>().test(42, null);
+ new C<int?, int>().test(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect
new file mode 100644
index 0000000..d9fa31c
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.outline.expect
@@ -0,0 +1,16 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+ ;
+ method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic
+ ;
+}
+static method assertRightSubtype(dynamic x) → dynamic
+ ;
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect
new file mode 100644
index 0000000..0acee2d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+ : super core::Object::•()
+ ;
+ method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t2 = #t1.{core::Set::add}(x) in let final dynamic #t3 = #t1.{core::Set::add}(42) in #t1;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t5 = #t4.{core::Set::add}(42) in let final dynamic #t6 = #t4.{core::Set::add}(x) in #t4;
+ core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t8 = #t7.{core::Set::add}(y) in let final dynamic #t9 = #t7.{core::Set::add}(42) in #t7;
+ core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t11 = #t10.{core::Set::add}(42) in let final dynamic #t12 = #t10.{core::Set::add}(y) in #t10;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ self::assertRightSubtype(p);
+ self::assertLeftSubtype<core::Set<core::Object?>>(p);
+ self::assertRightSubtype(q);
+ self::assertLeftSubtype<core::Set<core::Object?>>(q);
+ if(x is{ForNonNullableByDefault} core::Object?) {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final dynamic #t15 = #t13.{core::Set::add}(42) in #t13;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t17 = #t16.{core::Set::add}(42) in let final dynamic #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ }
+ }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+ x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+ col::LinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+ new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+ new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect
new file mode 100644
index 0000000..49327f3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.strong.transformed.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+ : super core::Object::•()
+ ;
+ method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t2 = #t1.{core::Set::add}(x) in let final core::bool #t3 = #t1.{core::Set::add}(42) in #t1;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t5 = #t4.{core::Set::add}(42) in let final core::bool #t6 = #t4.{core::Set::add}(x) in #t4;
+ core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t8 = #t7.{core::Set::add}(y) in let final core::bool #t9 = #t7.{core::Set::add}(42) in #t7;
+ core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t11 = #t10.{core::Set::add}(42) in let final core::bool #t12 = #t10.{core::Set::add}(y) in #t10;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ self::assertRightSubtype(p);
+ self::assertLeftSubtype<core::Set<core::Object?>>(p);
+ self::assertRightSubtype(q);
+ self::assertLeftSubtype<core::Set<core::Object?>>(q);
+ if(x is{ForNonNullableByDefault} core::Object?) {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final core::bool #t15 = #t13.{core::Set::add}(42) in #t13;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t17 = #t16.{core::Set::add}(42) in let final core::bool #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ }
+ }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+ x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+ new col::_CompactLinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+ new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+ new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect
new file mode 100644
index 0000000..4ec51c7
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+assertRightSubtype(dynamic x) {}
+assertLeftSubtype<X>(X x) {}
+
+class C<X extends Object?, Y extends Object> {
+ test(X x, Y? y) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..287d84a
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+assertLeftSubtype<X>(X x) {}
+assertRightSubtype(dynamic x) {}
+
+class C<X extends Object?, Y extends Object> {
+ test(X x, Y? y) {}
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect
new file mode 100644
index 0000000..0acee2d
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+ : super core::Object::•()
+ ;
+ method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t2 = #t1.{core::Set::add}(x) in let final dynamic #t3 = #t1.{core::Set::add}(42) in #t1;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t5 = #t4.{core::Set::add}(42) in let final dynamic #t6 = #t4.{core::Set::add}(x) in #t4;
+ core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t8 = #t7.{core::Set::add}(y) in let final dynamic #t9 = #t7.{core::Set::add}(42) in #t7;
+ core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t11 = #t10.{core::Set::add}(42) in let final dynamic #t12 = #t10.{core::Set::add}(y) in #t10;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ self::assertRightSubtype(p);
+ self::assertLeftSubtype<core::Set<core::Object?>>(p);
+ self::assertRightSubtype(q);
+ self::assertLeftSubtype<core::Set<core::Object?>>(q);
+ if(x is{ForNonNullableByDefault} core::Object?) {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final dynamic #t15 = #t13.{core::Set::add}(42) in #t13;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = col::LinkedHashSet::•<core::Object?>() in let final dynamic #t17 = #t16.{core::Set::add}(42) in let final dynamic #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ }
+ }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+ x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+ col::LinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+ new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+ new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect
new file mode 100644
index 0000000..49327f3
--- /dev/null
+++ b/pkg/front_end/testcases/nnbd/issue43455.dart.weak.transformed.expect
@@ -0,0 +1,42 @@
+library /*isNonNullableByDefault*/;
+import self as self;
+import "dart:core" as core;
+import "dart:collection" as col;
+
+class C<X extends core::Object? = core::Object?, Y extends core::Object = core::Object> extends core::Object {
+ synthetic constructor •() → self::C<self::C::X%, self::C::Y>
+ : super core::Object::•()
+ ;
+ method test(generic-covariant-impl self::C::X% x, generic-covariant-impl self::C::Y? y) → dynamic {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t1 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t2 = #t1.{core::Set::add}(x) in let final core::bool #t3 = #t1.{core::Set::add}(42) in #t1;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t4 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t5 = #t4.{core::Set::add}(42) in let final core::bool #t6 = #t4.{core::Set::add}(x) in #t4;
+ core::Set<core::Object?> p = let final core::Set<core::Object?> #t7 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t8 = #t7.{core::Set::add}(y) in let final core::bool #t9 = #t7.{core::Set::add}(42) in #t7;
+ core::Set<core::Object?> q = let final core::Set<core::Object?> #t10 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t11 = #t10.{core::Set::add}(42) in let final core::bool #t12 = #t10.{core::Set::add}(y) in #t10;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ self::assertRightSubtype(p);
+ self::assertLeftSubtype<core::Set<core::Object?>>(p);
+ self::assertRightSubtype(q);
+ self::assertLeftSubtype<core::Set<core::Object?>>(q);
+ if(x is{ForNonNullableByDefault} core::Object?) {
+ core::Set<core::Object?> v = let final core::Set<core::Object?> #t13 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t14 = #t13.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in let final core::bool #t15 = #t13.{core::Set::add}(42) in #t13;
+ core::Set<core::Object?> w = let final core::Set<core::Object?> #t16 = new col::_CompactLinkedHashSet::•<core::Object?>() in let final core::bool #t17 = #t16.{core::Set::add}(42) in let final core::bool #t18 = #t16.{core::Set::add}(x{self::C::X% & core::Object? /* '%' & '?' = '%' */}) in #t16;
+ self::assertRightSubtype(v);
+ self::assertLeftSubtype<core::Set<core::Object?>>(v);
+ self::assertRightSubtype(w);
+ self::assertLeftSubtype<core::Set<core::Object?>>(w);
+ }
+ }
+}
+static method assertRightSubtype(dynamic x) → dynamic {
+ x as{ForNonNullableByDefault} core::Set<core::Object?>;
+}
+static method assertLeftSubtype<X extends core::Object? = dynamic>(self::assertLeftSubtype::X% x) → dynamic {
+ new col::_CompactLinkedHashSet::•<core::Object?>() as{ForNonNullableByDefault} self::assertLeftSubtype::X%;
+}
+static method main() → dynamic {
+ new self::C::•<core::int?, core::int>().{self::C::test}(42, null);
+ new self::C::•<core::int?, core::int>().{self::C::test}(null, null);
+}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.expect
@@ -11,7 +11,7 @@
method qux() → dynamic {
final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
if(v is{ForNonNullableByDefault} core::num) {
- this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+ this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.strong.transformed.expect
@@ -11,7 +11,7 @@
method qux() → dynamic {
final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
if(v is{ForNonNullableByDefault} core::num) {
- this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+ this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.expect
@@ -11,7 +11,7 @@
method qux() → dynamic {
final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
if(v is{ForNonNullableByDefault} core::num) {
- this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+ this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
index 78aceb3..15fcd35 100644
--- a/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/upper_bound_on_promoted_type.dart.weak.transformed.expect
@@ -11,7 +11,7 @@
method qux() → dynamic {
final self::Foo::T? v = this.{self::Foo::bar} as{TypeError,ForDynamic,ForNonNullableByDefault} self::Foo::T?;
if(v is{ForNonNullableByDefault} core::num) {
- this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object?} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
+ this.{self::Foo::baz}.[]=("value", v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::isFinite} ?{core::Object} v{self::Foo::T? & core::num /* '?' & '!' = '!' */} : v{self::Foo::T? & core::num /* '?' & '!' = '!' */}.{core::num::toString}());
}
}
}
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index e57f264..51a5ab9 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -710,9 +710,9 @@
type1.declaredNullability, type2.declaredNullability));
}
- // UP(T Function<...>(...), T2) = Object
- return coreTypes.objectRawType(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
+ // UP(T Function<...>(...), T2) = UP(Object, T2)
+ return _getNullabilityAwareStandardUpperBound(
+ coreTypes.objectNonNullableRawType, type2, clientLibrary);
} else if (type2 is FunctionType) {
if (type1 is InterfaceType &&
type1.classNode == coreTypes.functionClass) {
@@ -721,9 +721,9 @@
type1.declaredNullability, type2.declaredNullability));
}
- // UP(T1, T Function<...>(...)) = Object
- return coreTypes.objectRawType(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
+ // UP(T1, T Function<...>(...)) = UP(T1, Object)
+ return _getNullabilityAwareStandardUpperBound(
+ type1, coreTypes.objectNonNullableRawType, clientLibrary);
}
if (type1 is FutureOrType || type2 is FutureOrType) {
@@ -1148,7 +1148,9 @@
// UP(X1 extends B1, T2) =
// T2 if X1 <: T2
// otherwise X1 if T2 <: X1
- // otherwise UP(B1[Object/X1], T2)
+ // otherwise UP(B1a, T2)
+ // where B1a is the greatest closure of B1 with respect to X1,
+ // as defined in [inference.md].
if (isSubtypeOf(type1, type2, SubtypeCheckMode.withNullabilities)) {
return type2.withDeclaredNullability(uniteNullabilities(
type1.declaredNullability, type2.declaredNullability));
@@ -1157,20 +1159,28 @@
return type1.withDeclaredNullability(uniteNullabilities(
type1.declaredNullability, type2.declaredNullability));
}
- Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{
- type1.parameter: coreTypes.objectNonNullableRawType
- };
+ NullabilityAwareTypeVariableEliminator eliminator =
+ new NullabilityAwareTypeVariableEliminator(
+ eliminationTargets: <TypeParameter>{type1.parameter},
+ bottomType: const NeverType(Nullability.nonNullable),
+ topType: coreTypes.objectNullableRawType,
+ topFunctionType: coreTypes.functionNonNullableRawType,
+ unhandledTypeHandler: (type, recursor) => false);
return _getNullabilityAwareStandardUpperBound(
- substitute(type1.parameter.bound, substitution),
+ eliminator.eliminateToGreatest(type1.parameter.bound),
type2,
clientLibrary)
.withDeclaredNullability(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
+ type1.declaredNullability,
+ uniteNullabilities(type1.parameter.bound.declaredNullability,
+ type2.declaredNullability)));
} else {
// UP(X1 & B1, T2) =
// T2 if X1 <: T2
// otherwise X1 if T2 <: X1
- // otherwise UP(B1[Object/X1], T2)
+ // otherwise UP(B1a, T2)
+ // where B1a is the greatest closure of B1 with respect to X1,
+ // as defined in [inference.md].
DartType demoted =
new TypeParameterType(type1.parameter, type1.declaredNullability);
if (isSubtypeOf(demoted, type2, SubtypeCheckMode.withNullabilities)) {
@@ -1181,15 +1191,20 @@
return demoted.withDeclaredNullability(uniteNullabilities(
type1.declaredNullability, type2.declaredNullability));
}
- Map<TypeParameter, DartType> substitution = <TypeParameter, DartType>{
- type1.parameter: coreTypes.objectNonNullableRawType
- };
+ NullabilityAwareTypeVariableEliminator eliminator =
+ new NullabilityAwareTypeVariableEliminator(
+ eliminationTargets: <TypeParameter>{type1.parameter},
+ bottomType: const NeverType(Nullability.nonNullable),
+ topType: coreTypes.objectNullableRawType,
+ topFunctionType: coreTypes.functionNonNullableRawType,
+ unhandledTypeHandler: (type, recursor) => false);
return _getNullabilityAwareStandardUpperBound(
- substitute(type1.promotedBound, substitution),
+ eliminator.eliminateToGreatest(type1.promotedBound),
type2,
clientLibrary)
.withDeclaredNullability(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
+ type1.promotedBound.declaredNullability,
+ type2.declaredNullability));
}
}
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index 4661aeb..632c18d 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -5,6 +5,7 @@
import 'ast.dart';
import 'core_types.dart';
+import 'src/replacement_visitor.dart';
/// Returns a type where all occurrences of the given type parameters have been
/// replaced with the corresponding types.
@@ -1096,3 +1097,91 @@
@override
DartType visitVoidType(VoidType node, CoreTypes coreTypes) => node;
}
+
+/// Eliminates specified free type parameters in a type.
+///
+/// The algorithm for elimination of type variables is described in
+/// https://github.com/dart-lang/language/pull/957
+class NullabilityAwareTypeVariableEliminator extends ReplacementVisitor {
+ final DartType bottomType;
+ final DartType topType;
+ final DartType topFunctionType;
+ final Set<TypeParameter> eliminationTargets;
+ bool isLeastClosure;
+ bool isCovariant = true;
+ bool Function(DartType type, bool Function(DartType type) recursor)
+ unhandledTypeHandler; // Can be null.
+
+ NullabilityAwareTypeVariableEliminator(
+ {this.eliminationTargets,
+ this.bottomType,
+ this.topType,
+ this.topFunctionType,
+ this.unhandledTypeHandler})
+ : assert(eliminationTargets != null),
+ assert(bottomType != null),
+ assert(topType != null),
+ assert(topFunctionType != null);
+
+ /// Returns a subtype of [type] for all values of [eliminationTargets].
+ DartType eliminateToLeast(DartType type) {
+ isCovariant = true;
+ isLeastClosure = true;
+ return type.accept(this) ?? type;
+ }
+
+ /// Returns a supertype of [type] for all values of [eliminationTargets].
+ DartType eliminateToGreatest(DartType type) {
+ isCovariant = true;
+ isLeastClosure = false;
+ return type.accept(this) ?? type;
+ }
+
+ DartType get typeParameterReplacement {
+ return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
+ ? bottomType
+ : topType;
+ }
+
+ DartType get functionReplacement {
+ return isLeastClosure && isCovariant || (!isLeastClosure && !isCovariant)
+ ? bottomType
+ : topFunctionType;
+ }
+
+ @override
+ void changeVariance() {
+ isCovariant = !isCovariant;
+ }
+
+ @override
+ DartType visitFunctionType(FunctionType node) {
+ // - if `S` is
+ // `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
+ // [Tn+1 xn+1, ..., Tm xm])`
+ // or `T Function<X0 extends B0, ...., Xk extends Bk>(T0 x0, ...., Tn xn,
+ // {Tn+1 xn+1, ..., Tm xm})`
+ // and `L` contains any free type variables from any of the `Bi`:
+ // - The least closure of `S` with respect to `L` is `Never`
+ // - The greatest closure of `S` with respect to `L` is `Function`
+ if (node.typeParameters.isNotEmpty) {
+ for (TypeParameter typeParameter in node.typeParameters) {
+ if (containsTypeVariable(typeParameter.bound, eliminationTargets,
+ unhandledTypeHandler: unhandledTypeHandler)) {
+ return functionReplacement;
+ }
+ }
+ }
+ return super.visitFunctionType(node);
+ }
+
+ @override
+ DartType visitTypeParameterType(TypeParameterType node) {
+ if (eliminationTargets.contains(node.parameter)) {
+ return typeParameterReplacement.withDeclaredNullability(
+ uniteNullabilities(
+ typeParameterReplacement.nullability, node.nullability));
+ }
+ return super.visitTypeParameterType(node);
+ }
+}
diff --git a/tools/VERSION b/tools/VERSION
index cd329e1..452c461 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 11
PATCH 0
-PRERELEASE 158
+PRERELEASE 159
PRERELEASE_PATCH 0
\ No newline at end of file