[cfe] Separate out IntersectionType from TypeParameterType
TEST=Covered by existing tests
Change-Id: Ie7b99b1c109edff5198cfbf5d22e1cfb1dc130d2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/253665
Reviewed-by: Johnni Winther <johnniwinther@google.com>
Reviewed-by: Mayank Patke <fishythefish@google.com>
Reviewed-by: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Nicholas Shahan <nshahan@google.com>
Commit-Queue: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
index 5b091df..b51fc45 100644
--- a/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
+++ b/pkg/_fe_analyzer_shared/test/flow_analysis/type_promotion/data/type_parameter.dart
@@ -12,7 +12,7 @@
void promoteNullable(T? t) {
T? s;
if (t is int) {
- s = /*T & int*/ t;
+ s = /*cfe.T? & int*/ /*analyzer.T & int*/ t;
}
}
diff --git a/pkg/compiler/lib/src/ir/scope_visitor.dart b/pkg/compiler/lib/src/ir/scope_visitor.dart
index 113387f..8b57cf3 100644
--- a/pkg/compiler/lib/src/ir/scope_visitor.dart
+++ b/pkg/compiler/lib/src/ir/scope_visitor.dart
@@ -755,6 +755,12 @@
return const EvaluationComplexity.lazy();
}
+ @override
+ EvaluationComplexity visitIntersectionType(ir.IntersectionType node) {
+ _analyzeTypeVariable(node.left, _currentTypeUsage!);
+ return const EvaluationComplexity.lazy();
+ }
+
EvaluationComplexity visitInContext(ir.Node node, VariableUse use) {
VariableUse? oldCurrentTypeUsage = _currentTypeUsage;
_currentTypeUsage = use;
diff --git a/pkg/compiler/lib/src/ir/util.dart b/pkg/compiler/lib/src/ir/util.dart
index d96ad3d..b955b0c 100644
--- a/pkg/compiler/lib/src/ir/util.dart
+++ b/pkg/compiler/lib/src/ir/util.dart
@@ -195,6 +195,11 @@
}
@override
+ bool visitIntersectionType(ir.IntersectionType node) {
+ return true;
+ }
+
+ @override
bool visitFunctionType(ir.FunctionType node) {
if (visit(node.returnType)) return true;
if (visitList(node.positionalParameters)) return true;
diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart
index c752997..b84523f 100644
--- a/pkg/compiler/lib/src/ir/visitors.dart
+++ b/pkg/compiler/lib/src/ir/visitors.dart
@@ -113,6 +113,11 @@
}
@override
+ DartType visitIntersectionType(ir.IntersectionType node) {
+ return node.left.accept(this);
+ }
+
+ @override
DartType visitFunctionType(ir.FunctionType node) {
int index = 0;
List<FunctionTypeVariable>? typeVariables;
diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart
index a2e2a26..1659004 100644
--- a/pkg/compiler/lib/src/serialization/helpers.dart
+++ b/pkg/compiler/lib/src/serialization/helpers.dart
@@ -142,14 +142,31 @@
_sink.writeEnum(DartTypeNodeKind.functionTypeVariable);
_sink.writeInt(index);
_sink.writeEnum(node.declaredNullability);
- _sink._writeDartTypeNode(node.promotedBound, functionTypeVariables,
- allowNull: true);
+ _sink._writeDartTypeNode(null, functionTypeVariables, allowNull: true);
} else {
_sink.writeEnum(DartTypeNodeKind.typeParameterType);
_sink.writeTypeParameterNode(node.parameter);
_sink.writeEnum(node.declaredNullability);
- _sink._writeDartTypeNode(node.promotedBound, functionTypeVariables,
- allowNull: true);
+ _sink._writeDartTypeNode(null, functionTypeVariables, allowNull: true);
+ }
+ }
+
+ @override
+ void visitIntersectionType(
+ ir.IntersectionType node, List<ir.TypeParameter> functionTypeVariables) {
+ int index = functionTypeVariables.indexOf(node.left.parameter);
+ if (index != -1) {
+ _sink.writeEnum(DartTypeNodeKind.functionTypeVariable);
+ _sink.writeInt(index);
+ _sink.writeEnum(node.declaredNullability);
+ _sink._writeDartTypeNode(node.right, functionTypeVariables,
+ allowNull: false);
+ } else {
+ _sink.writeEnum(DartTypeNodeKind.typeParameterType);
+ _sink.writeTypeParameterNode(node.left.parameter);
+ _sink.writeEnum(node.declaredNullability);
+ _sink._writeDartTypeNode(node.right, functionTypeVariables,
+ allowNull: false);
}
}
diff --git a/pkg/compiler/lib/src/serialization/source.dart b/pkg/compiler/lib/src/serialization/source.dart
index b3cc2c9..1bdab33 100644
--- a/pkg/compiler/lib/src/serialization/source.dart
+++ b/pkg/compiler/lib/src/serialization/source.dart
@@ -826,16 +826,26 @@
ir.Nullability typeParameterTypeNullability =
readEnum(ir.Nullability.values);
ir.DartType? promotedBound = _readDartTypeNode(functionTypeVariables);
- return ir.TypeParameterType(
- typeParameter, typeParameterTypeNullability, promotedBound);
+ ir.TypeParameterType typeParameterType =
+ ir.TypeParameterType(typeParameter, typeParameterTypeNullability);
+ if (promotedBound == null) {
+ return typeParameterType;
+ } else {
+ return ir.IntersectionType(typeParameterType, promotedBound);
+ }
case DartTypeNodeKind.functionTypeVariable:
int index = readInt();
assert(0 <= index && index < functionTypeVariables.length);
ir.Nullability typeParameterTypeNullability =
readEnum(ir.Nullability.values);
ir.DartType? promotedBound = _readDartTypeNode(functionTypeVariables);
- return ir.TypeParameterType(functionTypeVariables[index],
- typeParameterTypeNullability, promotedBound);
+ ir.TypeParameterType typeParameterType = ir.TypeParameterType(
+ functionTypeVariables[index], typeParameterTypeNullability);
+ if (promotedBound == null) {
+ return typeParameterType;
+ } else {
+ return ir.IntersectionType(typeParameterType, promotedBound);
+ }
case DartTypeNodeKind.functionType:
begin(functionTypeNodeTag);
int typeParameterCount = readInt();
diff --git a/pkg/compiler/test/helpers/ir_types.dart b/pkg/compiler/test/helpers/ir_types.dart
index b9745e5..e1ff1f7 100644
--- a/pkg/compiler/test/helpers/ir_types.dart
+++ b/pkg/compiler/test/helpers/ir_types.dart
@@ -48,6 +48,11 @@
}
@override
+ void visitIntersectionType(ir.IntersectionType node, StringBuffer sb) {
+ sb.write(node.left.parameter.name);
+ }
+
+ @override
void visitFunctionType(ir.FunctionType node, StringBuffer sb) {
writeType(node.returnType, sb);
sb.write(' Function');
diff --git a/pkg/dev_compiler/lib/src/kernel/compiler.dart b/pkg/dev_compiler/lib/src/kernel/compiler.dart
index 110dc18..22ce35e 100644
--- a/pkg/dev_compiler/lib/src/kernel/compiler.dart
+++ b/pkg/dev_compiler/lib/src/kernel/compiler.dart
@@ -3223,6 +3223,10 @@
js_ast.Expression visitTypeParameterType(TypeParameterType type) =>
_emitTypeParameterType(type);
+ @override
+ js_ast.Expression visitIntersectionType(IntersectionType type) =>
+ _emitTypeParameterType(type.left);
+
js_ast.Expression _emitTypeParameterType(TypeParameterType type,
{bool emitNullability = true}) {
var typeParam = _emitTypeParameter(type.parameter);
diff --git a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
index c2759d1..132bda6 100644
--- a/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/invalid_type.dart
@@ -110,10 +110,12 @@
// node.parameter.bound is not checked because such a bound doesn't
// automatically means that the potential errors related to the occurrences
// of the type-parameter type itself are reported.
- if (node.promotedBound != null &&
- node.promotedBound!.accept1(this, visitedTypedefs)) {
- return true;
- }
return false;
}
+
+ @override
+ bool visitIntersectionType(
+ IntersectionType node, Set<TypedefType> visitedTypedefs) {
+ return node.right.accept1(this, visitedTypedefs);
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
index 13f1592..25d9701 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_algorithms.dart
@@ -1149,6 +1149,15 @@
bool visitTypeParameterType(TypeParameterType node) => true;
@override
+ bool visitIntersectionType(IntersectionType node) {
+ // The left-hand side of an [IntersectionType] is always a
+ // [TypeParameterType].
+ // ignore: unnecessary_type_check
+ assert(node.left is TypeParameterType);
+ return true;
+ }
+
+ @override
bool visitTypedefType(TypedefType node) {
return anyTypeVariables(node.typeArguments);
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
index d21a6c7..d248946 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_builder_computer.dart
@@ -178,6 +178,11 @@
}
@override
+ TypeBuilder visitIntersectionType(IntersectionType node) {
+ throw "Not implemented";
+ }
+
+ @override
TypeBuilder visitTypedefType(TypedefType node) {
throw "Not implemented";
}
diff --git a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
index ec26f2a..5537820 100644
--- a/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/type_labeler.dart
@@ -175,6 +175,11 @@
}
@override
+ void visitIntersectionType(IntersectionType node) {
+ return node.left.accept(this);
+ }
+
+ @override
void visitFunctionType(FunctionType node) {
node.returnType.accept(this);
result.add(" Function");
diff --git a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
index 25e39b9..d9de536 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/inference_visitor_base.dart
@@ -3615,6 +3615,8 @@
DartType? resolveOneStep(DartType type) {
if (type is TypeParameterType) {
return type.bound;
+ } else if (type is IntersectionType) {
+ return type.right;
} else {
return null;
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
index 48a0929..9e0f44b 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_demotion.dart
@@ -46,9 +46,10 @@
}
@override
- bool visitTypeParameterType(TypeParameterType node) {
- return node.promotedBound != null;
- }
+ bool visitTypeParameterType(TypeParameterType node) => false;
+
+ @override
+ bool visitIntersectionType(IntersectionType node) => true;
}
/// Returns [type] in which all promoted type variables have been replace with
@@ -125,10 +126,16 @@
@override
DartType? visitTypeParameterType(TypeParameterType node, int variance) {
Nullability? newNullability = visitNullability(node);
- if (demoteTypeVariables && node.promotedBound != null) {
- return new TypeParameterType(
- node.parameter, newNullability ?? node.declaredNullability);
- }
return createTypeParameterType(node, newNullability);
}
+
+ @override
+ DartType? visitIntersectionType(IntersectionType node, int variance) {
+ Nullability? newNullability = visitNullability(node);
+ if (demoteTypeVariables) {
+ return new TypeParameterType(
+ node.left.parameter, newNullability ?? node.left.nullability);
+ }
+ return createTypeParameterType(node.left, newNullability);
+ }
}
diff --git a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
index a817c94..93b0299 100644
--- a/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
+++ b/pkg/front_end/lib/src/fasta/type_inference/type_inference_engine.dart
@@ -26,7 +26,7 @@
/// Visitor to check whether a given type mentions any of a class's type
/// parameters in a non-covariant fashion.
-class IncludesTypeParametersNonCovariantly extends DartTypeVisitor<bool> {
+class IncludesTypeParametersNonCovariantly implements DartTypeVisitor<bool> {
int _variance;
final List<TypeParameter> _typeParametersToSearchFor;
@@ -36,7 +36,28 @@
: _variance = initialVariance;
@override
- bool defaultDartType(DartType node) => false;
+ bool defaultDartType(DartType node) {
+ throw new UnsupportedError(
+ "IncludesTypeParametersNonCovariantly.defaultDartType");
+ }
+
+ @override
+ bool visitDynamicType(DynamicType node) => false;
+
+ @override
+ bool visitExtensionType(ExtensionType node) => false;
+
+ @override
+ bool visitNeverType(NeverType node) => false;
+
+ @override
+ bool visitInvalidType(InvalidType node) => false;
+
+ @override
+ bool visitNullType(NullType node) => false;
+
+ @override
+ bool visitVoidType(VoidType node) => false;
@override
bool visitFunctionType(FunctionType node) {
@@ -84,6 +105,11 @@
return !Variance.greaterThanOrEqual(_variance, node.parameter.variance) &&
_typeParametersToSearchFor.contains(node.parameter);
}
+
+ @override
+ bool visitIntersectionType(IntersectionType node) {
+ return node.left.accept(this);
+ }
}
/// Keeps track of the global state for the type inference that occurs outside
@@ -321,7 +347,9 @@
}
@override
- bool isTypeParameterType(DartType type) => type is TypeParameterType;
+ bool isTypeParameterType(DartType type) {
+ return type is TypeParameterType || type is IntersectionType;
+ }
@override
DartType tryPromoteToType(DartType to, DartType from) {
@@ -329,9 +357,13 @@
return to;
}
if (from is TypeParameterType) {
- if (isSubtypeOf(to, from.promotedBound ?? from.bound)) {
- return new TypeParameterType.intersection(
- from.parameter, from.nullability, to);
+ if (isSubtypeOf(to, from.bound)) {
+ return new IntersectionType(from, to);
+ }
+ }
+ if (from is IntersectionType) {
+ if (isSubtypeOf(to, from.right)) {
+ return new IntersectionType(from.left, to);
}
}
return from;
diff --git a/pkg/front_end/lib/src/testing/id_testing_utils.dart b/pkg/front_end/lib/src/testing/id_testing_utils.dart
index a764f12..7d5ddbf 100644
--- a/pkg/front_end/lib/src/testing/id_testing_utils.dart
+++ b/pkg/front_end/lib/src/testing/id_testing_utils.dart
@@ -641,10 +641,13 @@
void visitTypeParameterType(TypeParameterType node) {
sb.write(node.parameter.name);
sb.write(nullabilityToText(node.nullability, typeRepresentation));
- if (node.promotedBound != null) {
- sb.write(' & ');
- visit(node.promotedBound!);
- }
+ }
+
+ @override
+ void visitIntersectionType(IntersectionType node) {
+ visit(node.left);
+ sb.write(' & ');
+ visit(node.right);
}
@override
diff --git a/pkg/front_end/test/static_types/data/promoted_access.dart b/pkg/front_end/test/static_types/data/promoted_access.dart
index 82085cb..d3ea4ff 100644
--- a/pkg/front_end/test/static_types/data/promoted_access.dart
+++ b/pkg/front_end/test/static_types/data/promoted_access.dart
@@ -11,11 +11,11 @@
method(T o) {
if (/*cfe.T*/ /*cfe:nnbd.T%*/ o is Class) {
/*cfe.T & Class<dynamic>*/
- /*cfe:nnbd.T! & Class<dynamic>!*/
+ /*cfe:nnbd.T% & Class<dynamic>!*/
o. /*invoke: dynamic*/ method(/*Null*/ null);
- /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T! & Class<dynamic>!|dynamic*/ o
+ /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T% & Class<dynamic>!|dynamic*/ o
?. /*invoke: dynamic*/ method(/*Null*/ null);
- /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T! & Class<dynamic>!|dynamic*/ o
+ /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T% & Class<dynamic>!|dynamic*/ o
?. /*dynamic*/ property;
}
}
@@ -24,11 +24,11 @@
method<T>(T o) {
if (/*cfe.T*/ /*cfe:nnbd.T%*/ o is Class) {
/*cfe.T & Class<dynamic>*/
- /*cfe:nnbd.T! & Class<dynamic>!*/
+ /*cfe:nnbd.T% & Class<dynamic>!*/
o. /*invoke: dynamic*/ method(/*Null*/ null);
- /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T! & Class<dynamic>!|dynamic*/ o
+ /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T% & Class<dynamic>!|dynamic*/ o
?. /*invoke: dynamic*/ method(/*Null*/ null);
- /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T! & Class<dynamic>!|dynamic*/ o
+ /*cfe.T & Class<dynamic>|dynamic*/ /*cfe:nnbd.T% & Class<dynamic>!|dynamic*/ o
?. /*dynamic*/ property;
}
}
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
index 9723009..5717e61 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.expect
@@ -33,7 +33,7 @@
if(t is{ForNonNullableByDefault} self::B) {
self::Foo::T% bar = t{self::Foo::T% & self::B /* '%' & '!' = '!' */};
if(t{self::Foo::T% & self::B /* '%' & '!' = '!' */} is{ForNonNullableByDefault} self::C) {
- self::Foo::T baz = t{self::Foo::T & self::C /* '!' & '!' = '!' */};
+ self::Foo::T% baz = t{self::Foo::T% & self::C /* '%' & '!' = '!' */};
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
index 9723009..5717e61 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.strong.transformed.expect
@@ -33,7 +33,7 @@
if(t is{ForNonNullableByDefault} self::B) {
self::Foo::T% bar = t{self::Foo::T% & self::B /* '%' & '!' = '!' */};
if(t{self::Foo::T% & self::B /* '%' & '!' = '!' */} is{ForNonNullableByDefault} self::C) {
- self::Foo::T baz = t{self::Foo::T & self::C /* '!' & '!' = '!' */};
+ self::Foo::T% baz = t{self::Foo::T% & self::C /* '%' & '!' = '!' */};
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.expect
index 9723009..5717e61 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.expect
@@ -33,7 +33,7 @@
if(t is{ForNonNullableByDefault} self::B) {
self::Foo::T% bar = t{self::Foo::T% & self::B /* '%' & '!' = '!' */};
if(t{self::Foo::T% & self::B /* '%' & '!' = '!' */} is{ForNonNullableByDefault} self::C) {
- self::Foo::T baz = t{self::Foo::T & self::C /* '!' & '!' = '!' */};
+ self::Foo::T% baz = t{self::Foo::T% & self::C /* '%' & '!' = '!' */};
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.modular.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.modular.expect
index 9723009..5717e61 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.modular.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.modular.expect
@@ -33,7 +33,7 @@
if(t is{ForNonNullableByDefault} self::B) {
self::Foo::T% bar = t{self::Foo::T% & self::B /* '%' & '!' = '!' */};
if(t{self::Foo::T% & self::B /* '%' & '!' = '!' */} is{ForNonNullableByDefault} self::C) {
- self::Foo::T baz = t{self::Foo::T & self::C /* '!' & '!' = '!' */};
+ self::Foo::T% baz = t{self::Foo::T% & self::C /* '%' & '!' = '!' */};
}
}
}
diff --git a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.transformed.expect b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.transformed.expect
index 9723009..5717e61 100644
--- a/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.transformed.expect
+++ b/pkg/front_end/testcases/nnbd/intersection_types.dart.weak.transformed.expect
@@ -33,7 +33,7 @@
if(t is{ForNonNullableByDefault} self::B) {
self::Foo::T% bar = t{self::Foo::T% & self::B /* '%' & '!' = '!' */};
if(t{self::Foo::T% & self::B /* '%' & '!' = '!' */} is{ForNonNullableByDefault} self::C) {
- self::Foo::T baz = t{self::Foo::T & self::C /* '!' & '!' = '!' */};
+ self::Foo::T% baz = t{self::Foo::T% & self::C /* '%' & '!' = '!' */};
}
}
}
diff --git a/pkg/front_end/tool/_fasta/bench_maker.dart b/pkg/front_end/tool/_fasta/bench_maker.dart
index 58c45c97..4cc1ed5 100644
--- a/pkg/front_end/tool/_fasta/bench_maker.dart
+++ b/pkg/front_end/tool/_fasta/bench_maker.dart
@@ -334,10 +334,13 @@
String name = computeName(node.parameter);
usedTypeParameters.add(node.parameter);
sb.write(name);
- if (node.promotedBound != null) {
- sb.write(" & ");
- node.promotedBound!.accept1(this, sb);
- }
+ }
+
+ @override
+ void visitIntersectionType(IntersectionType node, StringBuffer sb) {
+ node.left.accept1(this, sb);
+ sb.write(" & ");
+ node.right.accept1(this, sb);
}
@override
diff --git a/pkg/kernel/binary.md b/pkg/kernel/binary.md
index db46616..4149740 100644
--- a/pkg/kernel/binary.md
+++ b/pkg/kernel/binary.md
@@ -147,7 +147,7 @@
type ComponentFile {
UInt32 magic = 0x90ABCDEF;
- UInt32 formatVersion = 83;
+ UInt32 formatVersion = 84;
Byte[10] shortSdkHash;
List<String> problemsAsJson; // Described in problems.md.
Library[] libraries;
@@ -1529,7 +1529,12 @@
// the class type parameters in a constructor refer to those declared on the
// class.
UInt index;
- Option<DartType> bound;
+}
+
+type IntersectionType extends DartType {
+ Byte tag = 99;
+ TypeParameterType left;
+ DartType right;
}
type TypedefType {
diff --git a/pkg/kernel/lib/ast.dart b/pkg/kernel/lib/ast.dart
index 74fe943..8e40415 100644
--- a/pkg/kernel/lib/ast.dart
+++ b/pkg/kernel/lib/ast.dart
@@ -12078,6 +12078,335 @@
}
}
+class IntersectionType extends DartType {
+ final TypeParameterType left;
+ final DartType right;
+
+ IntersectionType(this.left, this.right) {
+ // TODO(cstefantsova): Also assert that [rhs] is a subtype of [lhs.bound].
+
+ Nullability leftNullability = left.nullability;
+ Nullability rightNullability = right.nullability;
+ assert(
+ (leftNullability == Nullability.nonNullable &&
+ rightNullability == Nullability.nonNullable) ||
+ (leftNullability == Nullability.nonNullable &&
+ rightNullability == Nullability.undetermined) ||
+ (leftNullability == Nullability.legacy &&
+ rightNullability == Nullability.legacy) ||
+ (leftNullability == Nullability.undetermined &&
+ rightNullability == Nullability.nonNullable) ||
+ (leftNullability == Nullability.undetermined &&
+ rightNullability == Nullability.nullable) ||
+ (leftNullability == Nullability.undetermined &&
+ rightNullability == Nullability.undetermined)
+ // These are observed in real situations:
+ ||
+ // pkg/front_end/test/id_tests/type_promotion_test
+ // replicated in nnbd_mixed/type_parameter_nullability
+ (leftNullability == Nullability.nullable &&
+ rightNullability == Nullability.nonNullable) ||
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/incremental_hello_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/tool/fasta_perf_test
+ // nnbd/issue42089
+ // replicated in nnbd_mixed/type_parameter_nullability
+ (leftNullability == Nullability.nullable &&
+ rightNullability == Nullability.nullable) ||
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/test/dill_round_trip_test
+ // pkg/front_end/test/compile_dart2js_with_no_sdk_test
+ // pkg/front_end/test/fasta/types/large_app_benchmark_test
+ // pkg/front_end/test/incremental_dart2js_test
+ // pkg/front_end/test/read_dill_from_binary_md_test
+ // pkg/front_end/test/static_types/static_type_test
+ // pkg/front_end/test/split_dill_test
+ // pkg/front_end/tool/incremental_perf_test
+ // pkg/vm/test/kernel_front_end_test
+ // general/promoted_null_aware_access
+ // inference/constructors_infer_from_arguments_factory
+ // inference/infer_types_on_loop_indices_for_each_loop
+ // inference/infer_types_on_loop_indices_for_each_loop_async
+ // replicated in nnbd_mixed/type_parameter_nullability
+ (leftNullability == Nullability.legacy &&
+ rightNullability == Nullability.nonNullable) ||
+ // pkg/front_end/test/fasta/incremental_hello_test
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/tool/fasta_perf_test
+ // replicated in nnbd_mixed/type_parameter_nullability
+ (leftNullability == Nullability.nullable &&
+ rightNullability == Nullability.undetermined) ||
+ // These are only observed in tests and might be artifacts of the
+ // tests rather than real situations:
+ //
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ (leftNullability == Nullability.legacy &&
+ rightNullability == Nullability.nullable) ||
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ (leftNullability == Nullability.nonNullable &&
+ rightNullability == Nullability.nullable) ||
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ (leftNullability == Nullability.undetermined &&
+ rightNullability == Nullability.legacy) ||
+ // pkg/kernel/test/clone_test
+ // The legacy nullability is due to RHS being InvalidType.
+ (leftNullability == Nullability.nonNullable &&
+ rightNullability == Nullability.legacy),
+ "Unexpected nullabilities for ${left} & ${right}: "
+ "leftNullability = ${leftNullability}, "
+ "rightNullability = ${rightNullability}.");
+ }
+
+ @override
+ R accept<R>(DartTypeVisitor<R> v) => v.visitIntersectionType(this);
+
+ @override
+ R accept1<R, A>(DartTypeVisitor1<R, A> v, A arg) =>
+ v.visitIntersectionType(this, arg);
+
+ @override
+ void visitChildren(Visitor v) {
+ left.accept(v);
+ right.accept(v);
+ }
+
+ @override
+ bool operator ==(Object other) => equals(other, null);
+
+ @override
+ bool equals(Object other, Assumptions? assumptions) {
+ if (identical(this, other)) {
+ return true;
+ } else if (other is IntersectionType) {
+ return left.equals(other.left, assumptions) &&
+ right.equals(other.right, assumptions);
+ } else {
+ return false;
+ }
+ }
+
+ @override
+ int get hashCode {
+ int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
+ int hash = nullabilityHash;
+ hash = 0x3fffffff & (hash * 31 + (hash ^ left.hashCode));
+ hash = 0x3fffffff & (hash * 31 + (hash ^ right.hashCode));
+ return hash;
+ }
+
+ /// Computes the nullability of [IntersectionType] from its parts.
+ ///
+ /// [nullability] is calculated from [left.nullability] and
+ /// [right.nullability].
+ ///
+ /// In the following program the nullability of `x` is
+ /// [Nullability.undetermined] because it's copied from that of `bar`. The
+ /// nullability of `y` is [Nullability.nonNullable] because its type is an
+ /// intersection type where the LHS is `T` and the RHS is the promoted type
+ /// `int`. The nullability of the type of `y` is computed from the
+ /// nullabilities of those two types.
+ ///
+ /// class A<T extends Object?> {
+ /// foo(T bar) {
+ /// var x = bar;
+ /// if (bar is int) {
+ /// var y = bar;
+ /// }
+ /// }
+ /// }
+ ///
+ /// The method combines the nullabilities of [left] and [right] to yield the
+ /// nullability of the intersection type.
+ @override
+ Nullability get nullability {
+ // Note that RHS is always a subtype of the bound of the type parameter.
+
+ // The code below implements the rule for the nullability of an
+ // intersection type as per the following table:
+ //
+ // | LHS \ RHS | ! | ? | * | % |
+ // |-----------|-----|-----|-----|-----|
+ // | ! | ! | + | N/A | ! |
+ // | ? | (!) | (?) | N/A | (%) |
+ // | * | (*) | + | * | N/A |
+ // | % | ! | % | + | % |
+ //
+ // In the table, LHS corresponds to [lhsNullability] in the code below; RHS
+ // corresponds to [rhsNullability]; !, ?, *, and % correspond to
+ // nonNullable, nullable, legacy, and undetermined values of the
+ // Nullability enum.
+
+ Nullability lhsNullability = left.nullability;
+ Nullability rhsNullability = right.nullability;
+ assert(
+ (lhsNullability == Nullability.nonNullable &&
+ rhsNullability == Nullability.nonNullable) ||
+ (lhsNullability == Nullability.nonNullable &&
+ rhsNullability == Nullability.undetermined) ||
+ (lhsNullability == Nullability.legacy &&
+ rhsNullability == Nullability.legacy) ||
+ (lhsNullability == Nullability.undetermined &&
+ rhsNullability == Nullability.nonNullable) ||
+ (lhsNullability == Nullability.undetermined &&
+ rhsNullability == Nullability.nullable) ||
+ (lhsNullability == Nullability.undetermined &&
+ rhsNullability == Nullability.undetermined)
+ // Apparently these happens as well:
+ ||
+ // pkg/front_end/test/id_tests/type_promotion_test
+ (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.nonNullable) ||
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/incremental_hello_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/tool/fasta_perf_test
+ // nnbd/issue42089
+ (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.nullable) ||
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/test/dill_round_trip_test
+ // pkg/front_end/test/compile_dart2js_with_no_sdk_test
+ // pkg/front_end/test/fasta/types/large_app_benchmark_test
+ // pkg/front_end/test/incremental_dart2js_test
+ // pkg/front_end/test/read_dill_from_binary_md_test
+ // pkg/front_end/test/static_types/static_type_test
+ // pkg/front_end/test/split_dill_test
+ // pkg/front_end/tool/incremental_perf_test
+ // pkg/vm/test/kernel_front_end_test
+ // general/promoted_null_aware_access
+ // inference/constructors_infer_from_arguments_factory
+ // inference/infer_types_on_loop_indices_for_each_loop
+ // inference/infer_types_on_loop_indices_for_each_loop_async
+ (lhsNullability == Nullability.legacy &&
+ rhsNullability == Nullability.nonNullable) ||
+ // pkg/front_end/test/fasta/incremental_hello_test
+ // pkg/front_end/test/explicit_creation_test
+ // pkg/front_end/tool/fasta_perf_test
+ // pkg/front_end/test/fasta/incremental_hello_test
+ (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.undetermined) ||
+
+ // This is created but never observed.
+ // (lhsNullability == Nullability.legacy &&
+ // rhsNullability == Nullability.nullable) ||
+
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ (lhsNullability == Nullability.undetermined &&
+ rhsNullability == Nullability.legacy) ||
+ // pkg/front_end/test/fasta/types/kernel_type_parser_test
+ // pkg/front_end/test/fasta/types/fasta_types_test
+ (lhsNullability == Nullability.nonNullable &&
+ rhsNullability == Nullability.nullable),
+ "Unexpected nullabilities for: LHS nullability = $lhsNullability, "
+ "RHS nullability = ${rhsNullability}.");
+
+ // Whenever there's N/A in the table, it means that the corresponding
+ // combination of the LHS and RHS nullability is not possible when
+ // compiling from Dart source files, so we can define it to be whatever is
+ // faster and more convenient to implement. The verifier should check that
+ // the cases marked as N/A never occur in the output of the CFE.
+ //
+ // The code below uses the following extension of the table function:
+ //
+ // | LHS \ RHS | ! | ? | * | % |
+ // |-----------|-----|-----|-----|-----|
+ // | ! | ! | ! | ! | ! |
+ // | ? | (!) | (?) | * | (%) |
+ // | * | (*) | * | * | % |
+ // | % | ! | % | % | % |
+
+ if (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.nonNullable) {
+ return Nullability.nonNullable;
+ }
+
+ if (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.nullable) {
+ return Nullability.nullable;
+ }
+
+ if (lhsNullability == Nullability.legacy &&
+ rhsNullability == Nullability.nonNullable) {
+ return Nullability.legacy;
+ }
+
+ if (lhsNullability == Nullability.nullable &&
+ rhsNullability == Nullability.undetermined) {
+ return Nullability.undetermined;
+ }
+
+ // Intersection with a non-nullable type always yields a non-nullable type,
+ // as it's the most restrictive kind of types.
+ if (lhsNullability == Nullability.nonNullable ||
+ rhsNullability == Nullability.nonNullable) {
+ return Nullability.nonNullable;
+ }
+
+ // If the nullability of LHS is 'undetermined', the nullability of the
+ // intersection is also 'undetermined' if RHS is 'undetermined' or
+ // nullable.
+ //
+ // Consider the following example:
+ //
+ // class A<X extends Object?, Y extends X> {
+ // foo(X x) {
+ // if (x is Y) {
+ // x = null; // Compile-time error. Consider X = Y = int.
+ // Object a = x; // Compile-time error. Consider X = Y = int?.
+ // }
+ // if (x is int?) {
+ // x = null; // Compile-time error. Consider X = int.
+ // Object b = x; // Compile-time error. Consider X = int?.
+ // }
+ // }
+ // }
+ if (lhsNullability == Nullability.undetermined ||
+ rhsNullability == Nullability.undetermined) {
+ return Nullability.undetermined;
+ }
+
+ return Nullability.legacy;
+ }
+
+ @override
+ Nullability get declaredNullability => nullability;
+
+ @override
+ IntersectionType withDeclaredNullability(Nullability declaredNullability) {
+ if (left.declaredNullability == this.declaredNullability) {
+ return this;
+ }
+ TypeParameterType newLeft =
+ left.withDeclaredNullability(declaredNullability);
+ if (identical(newLeft, left)) {
+ return this;
+ }
+ return new IntersectionType(newLeft, right);
+ }
+
+ @override
+ String toString() {
+ return "IntersectionType(${toStringInternal()})";
+ }
+
+ @override
+ void toTextInternal(AstPrinter printer) {
+ printer.write('(');
+ printer.writeType(left);
+ printer.write(" & ");
+ printer.writeType(right);
+ printer.write(')');
+ printer.write(nullabilityToString(nullability));
+ }
+}
+
/// Reference to a type variable.
///
/// A type variable has an optional bound because type promotion can change the
@@ -12096,95 +12425,7 @@
TypeParameter parameter;
- /// An optional promoted bound on the type parameter.
- ///
- /// 'null' indicates that the type parameter's bound has not been promoted and
- /// is therefore the same as the bound of [parameter].
- DartType? promotedBound;
-
- TypeParameterType.internal(
- this.parameter, this.declaredNullability, DartType? promotedBound)
- : this.promotedBound = promotedBound {
- assert(
- promotedBound == null ||
- (declaredNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.nonNullable) ||
- (declaredNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.undetermined) ||
- (declaredNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.legacy) ||
- (declaredNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.nonNullable) ||
- (declaredNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.nullable) ||
- (declaredNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.undetermined)
- // These are observed in real situations:
- ||
- // pkg/front_end/test/id_tests/type_promotion_test
- // replicated in nnbd_mixed/type_parameter_nullability
- (declaredNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nonNullable) ||
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/incremental_hello_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/tool/fasta_perf_test
- // nnbd/issue42089
- // replicated in nnbd_mixed/type_parameter_nullability
- (declaredNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nullable) ||
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/test/dill_round_trip_test
- // pkg/front_end/test/compile_dart2js_with_no_sdk_test
- // pkg/front_end/test/fasta/types/large_app_benchmark_test
- // pkg/front_end/test/incremental_dart2js_test
- // pkg/front_end/test/read_dill_from_binary_md_test
- // pkg/front_end/test/static_types/static_type_test
- // pkg/front_end/test/split_dill_test
- // pkg/front_end/tool/incremental_perf_test
- // pkg/vm/test/kernel_front_end_test
- // general/promoted_null_aware_access
- // inference/constructors_infer_from_arguments_factory
- // inference/infer_types_on_loop_indices_for_each_loop
- // inference/infer_types_on_loop_indices_for_each_loop_async
- // replicated in nnbd_mixed/type_parameter_nullability
- (declaredNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.nonNullable) ||
- // pkg/front_end/test/fasta/incremental_hello_test
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/tool/fasta_perf_test
- // replicated in nnbd_mixed/type_parameter_nullability
- (declaredNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.undetermined) ||
- // These are only observed in tests and might be artifacts of the
- // tests rather than real situations:
- //
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- (declaredNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.nullable) ||
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- (declaredNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.nullable) ||
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- (declaredNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.legacy),
- "Unexpected nullabilities for $parameter & $promotedBound: "
- "declaredNullability = $declaredNullability, "
- "promoted bound nullability = ${promotedBound.nullability}.");
- }
-
- TypeParameterType(TypeParameter parameter, Nullability declaredNullability,
- [DartType? promotedBound])
- : this.internal(parameter, declaredNullability, promotedBound);
-
- /// Creates an intersection type between a type parameter and [promotedBound].
- TypeParameterType.intersection(TypeParameter parameter,
- Nullability declaredNullability, DartType promotedBound)
- : this.internal(parameter, declaredNullability, promotedBound);
+ TypeParameterType(this.parameter, this.declaredNullability);
/// Creates a type-parameter type to be used in alpha-renaming.
///
@@ -12218,9 +12459,7 @@
v.visitTypeParameterType(this, arg);
@override
- void visitChildren(Visitor v) {
- promotedBound?.accept(v);
- }
+ void visitChildren(Visitor v) {}
@override
bool operator ==(Object other) => equals(other, null);
@@ -12244,14 +12483,6 @@
return false;
}
}
- if (promotedBound != null) {
- if (other.promotedBound == null) return false;
- if (!promotedBound!.equals(other.promotedBound!, assumptions)) {
- return false;
- }
- } else if (other.promotedBound != null) {
- return false;
- }
return true;
} else {
return false;
@@ -12266,36 +12497,14 @@
int hash = parameter.isFunctionTypeTypeParameter ? 0 : parameter.hashCode;
int nullabilityHash = (0x33333333 >> nullability.index) ^ 0x33333333;
hash = 0x3fffffff & (hash * 31 + (hash ^ nullabilityHash));
- hash = 0x3fffffff & (hash * 31 + (hash ^ promotedBound.hashCode));
return hash;
}
- /// Returns the bound of the type parameter, accounting for promotions.
- DartType get bound => promotedBound ?? parameter.bound;
+ /// A quick access to the bound of the parameter.
+ DartType get bound => parameter.bound;
- /// Nullability of the type, calculated from its parts.
- ///
- /// [nullability] is calculated from [typeParameterTypeNullability] and the
- /// nullability of [promotedBound] if it's present.
- ///
- /// For example, in the following program [typeParameterTypeNullability] of
- /// both `x` and `y` is [Nullability.undetermined], because it's copied from
- /// that of `bar` and T has a nullable type as its bound. However, despite
- /// [nullability] of `x` is [Nullability.undetermined], [nullability] of `y`
- /// is [Nullability.nonNullable] because of its [promotedBound].
- ///
- /// class A<T extends Object?> {
- /// foo(T bar) {
- /// var x = bar;
- /// if (bar is int) {
- /// var y = bar;
- /// }
- /// }
- /// }
@override
- Nullability get nullability {
- return getNullability(declaredNullability, promotedBound);
- }
+ Nullability get nullability => declaredNullability;
/// Gets a new [TypeParameterType] with given [typeParameterTypeNullability].
///
@@ -12308,7 +12517,7 @@
if (declaredNullability == this.declaredNullability) {
return this;
}
- return new TypeParameterType(parameter, declaredNullability, promotedBound);
+ return new TypeParameterType(parameter, declaredNullability);
}
/// Gets the nullability of a type-parameter type based on the bound.
@@ -12337,9 +12546,6 @@
type = type.typeArgument;
}
if (type is TypeParameterType && type.parameter == typeParameter) {
- // Intersection types can't appear in the bound.
- assert(type.promotedBound == null);
-
nullabilityDependsOnItself = true;
}
}
@@ -12355,173 +12561,6 @@
: boundNullability;
}
- /// Gets nullability of [TypeParameterType] from arguments to its constructor.
- ///
- /// The method combines [typeParameterTypeNullability] and the nullability of
- /// [promotedBound] to yield the nullability of the intersection type. If the
- /// right-hand side of the intersection is absent (that is, if [promotedBound]
- /// is null), the nullability of the intersection type is simply
- /// [typeParameterTypeNullability].
- static Nullability getNullability(
- Nullability typeParameterTypeNullability, DartType? promotedBound) {
- // If promotedBound is null, getNullability simply returns the nullability
- // of the type parameter type.
- Nullability lhsNullability = typeParameterTypeNullability;
- if (promotedBound == null) {
- return lhsNullability;
- }
-
- // If promotedBound isn't null, getNullability returns the nullability of an
- // intersection of the left-hand side (referred to as LHS below) and the
- // right-hand side (referred to as RHS below). Note that RHS is always a
- // subtype of the bound of the type parameter.
-
- // The code below implements the rule for the nullability of an intersection
- // type as per the following table:
- //
- // | LHS \ RHS | ! | ? | * | % |
- // |-----------|-----|-----|-----|-----|
- // | ! | ! | + | N/A | ! |
- // | ? | (!) | (?) | N/A | (%) |
- // | * | (*) | + | * | N/A |
- // | % | ! | % | + | % |
- //
- // In the table, LHS corresponds to lhsNullability in the code below; RHS
- // corresponds to promotedBound.nullability; !, ?, *, and % correspond to
- // nonNullable, nullable, legacy, and undetermined values of the Nullability
- // enum.
-
- assert(
- (lhsNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.nonNullable) ||
- (lhsNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.undetermined) ||
- (lhsNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.legacy) ||
- (lhsNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.nonNullable) ||
- (lhsNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.nullable) ||
- (lhsNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.undetermined)
- // Apparently these happens as well:
- ||
- // pkg/front_end/test/id_tests/type_promotion_test
- (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nonNullable) ||
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/incremental_hello_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/tool/fasta_perf_test
- // nnbd/issue42089
- (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nullable) ||
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/test/dill_round_trip_test
- // pkg/front_end/test/compile_dart2js_with_no_sdk_test
- // pkg/front_end/test/fasta/types/large_app_benchmark_test
- // pkg/front_end/test/incremental_dart2js_test
- // pkg/front_end/test/read_dill_from_binary_md_test
- // pkg/front_end/test/static_types/static_type_test
- // pkg/front_end/test/split_dill_test
- // pkg/front_end/tool/incremental_perf_test
- // pkg/vm/test/kernel_front_end_test
- // general/promoted_null_aware_access
- // inference/constructors_infer_from_arguments_factory
- // inference/infer_types_on_loop_indices_for_each_loop
- // inference/infer_types_on_loop_indices_for_each_loop_async
- (lhsNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.nonNullable) ||
- // pkg/front_end/test/fasta/incremental_hello_test
- // pkg/front_end/test/explicit_creation_test
- // pkg/front_end/tool/fasta_perf_test
- // pkg/front_end/test/fasta/incremental_hello_test
- (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.undetermined) ||
-
- // This is created but never observed.
- // (lhsNullability == Nullability.legacy &&
- // promotedBound.nullability == Nullability.nullable) ||
-
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- (lhsNullability == Nullability.undetermined &&
- promotedBound.nullability == Nullability.legacy) ||
- // pkg/front_end/test/fasta/types/kernel_type_parser_test
- // pkg/front_end/test/fasta/types/fasta_types_test
- (lhsNullability == Nullability.nonNullable &&
- promotedBound.nullability == Nullability.nullable),
- "Unexpected nullabilities for: LHS nullability = $lhsNullability, "
- "RHS nullability = ${promotedBound.nullability}.");
-
- // Whenever there's N/A in the table, it means that the corresponding
- // combination of the LHS and RHS nullability is not possible when compiling
- // from Dart source files, so we can define it to be whatever is faster and
- // more convenient to implement. The verifier should check that the cases
- // marked as N/A never occur in the output of the CFE.
- //
- // The code below uses the following extension of the table function:
- //
- // | LHS \ RHS | ! | ? | * | % |
- // |-----------|-----|-----|-----|-----|
- // | ! | ! | ! | ! | ! |
- // | ? | (!) | (?) | * | (%) |
- // | * | (*) | * | * | % |
- // | % | ! | % | % | % |
-
- if (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nonNullable) {
- return Nullability.nonNullable;
- }
-
- if (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.nullable) {
- return Nullability.nullable;
- }
-
- if (lhsNullability == Nullability.legacy &&
- promotedBound.nullability == Nullability.nonNullable) {
- return Nullability.legacy;
- }
-
- if (lhsNullability == Nullability.nullable &&
- promotedBound.nullability == Nullability.undetermined) {
- return Nullability.undetermined;
- }
-
- // Intersection with a non-nullable type always yields a non-nullable type,
- // as it's the most restrictive kind of types.
- if (lhsNullability == Nullability.nonNullable ||
- promotedBound.nullability == Nullability.nonNullable) {
- return Nullability.nonNullable;
- }
-
- // If the nullability of LHS is 'undetermined', the nullability of the
- // intersection is also 'undetermined' if RHS is 'undetermined' or nullable.
- //
- // Consider the following example:
- //
- // class A<X extends Object?, Y extends X> {
- // foo(X x) {
- // if (x is Y) {
- // x = null; // Compile-time error. Consider X = Y = int.
- // Object a = x; // Compile-time error. Consider X = Y = int?.
- // }
- // if (x is int?) {
- // x = null; // Compile-time error. Consider X = int.
- // Object b = x; // Compile-time error. Consider X = int?.
- // }
- // }
- // }
- if (lhsNullability == Nullability.undetermined ||
- promotedBound.nullability == Nullability.undetermined) {
- return Nullability.undetermined;
- }
-
- return Nullability.legacy;
- }
-
@override
String toString() {
return "TypeParameterType(${toStringInternal()})";
@@ -12529,18 +12568,8 @@
@override
void toTextInternal(AstPrinter printer) {
- if (promotedBound != null) {
- printer.write('(');
- printer.writeTypeParameterName(parameter);
- printer.write(nullabilityToString(declaredNullability));
- printer.write(" & ");
- printer.writeType(promotedBound!);
- printer.write(')');
- printer.write(nullabilityToString(nullability));
- } else {
- printer.writeTypeParameterName(parameter);
- printer.write(nullabilityToString(declaredNullability));
- }
+ printer.writeTypeParameterName(parameter);
+ printer.write(nullabilityToString(declaredNullability));
}
}
diff --git a/pkg/kernel/lib/binary/ast_from_binary.dart b/pkg/kernel/lib/binary/ast_from_binary.dart
index f37d04d..5feffea 100644
--- a/pkg/kernel/lib/binary/ast_from_binary.dart
+++ b/pkg/kernel/lib/binary/ast_from_binary.dart
@@ -3053,6 +3053,8 @@
return _readSimpleFunctionType();
case Tag.TypeParameterType:
return _readTypeParameterType();
+ case Tag.IntersectionType:
+ return _readIntersectionType();
default:
throw fail('unexpected dart type tag: $tag');
}
@@ -3142,9 +3144,14 @@
DartType _readTypeParameterType() {
int declaredNullabilityIndex = readByte();
int index = readUInt30();
- DartType? bound = readDartTypeOption();
return new TypeParameterType(typeParameterStack[index],
- Nullability.values[declaredNullabilityIndex], bound);
+ Nullability.values[declaredNullabilityIndex]);
+ }
+
+ DartType _readIntersectionType() {
+ TypeParameterType left = readDartType() as TypeParameterType;
+ DartType right = readDartType();
+ return new IntersectionType(left, right);
}
List<TypeParameter> readAndPushTypeParameterList(
diff --git a/pkg/kernel/lib/binary/ast_to_binary.dart b/pkg/kernel/lib/binary/ast_to_binary.dart
index 6b7c969..8b33a8b 100644
--- a/pkg/kernel/lib/binary/ast_to_binary.dart
+++ b/pkg/kernel/lib/binary/ast_to_binary.dart
@@ -2501,7 +2501,13 @@
writeByte(Tag.TypeParameterType);
writeByte(node.declaredNullability.index);
writeUInt30(_typeParameterIndexer[node.parameter]);
- writeOptionalNode(node.promotedBound);
+ }
+
+ @override
+ void visitIntersectionType(IntersectionType node) {
+ writeByte(Tag.IntersectionType);
+ writeDartType(node.left);
+ writeDartType(node.right);
}
@override
diff --git a/pkg/kernel/lib/binary/tag.dart b/pkg/kernel/lib/binary/tag.dart
index 2e861b6..985273d 100644
--- a/pkg/kernel/lib/binary/tag.dart
+++ b/pkg/kernel/lib/binary/tag.dart
@@ -140,6 +140,7 @@
static const int SimpleInterfaceType = 96;
static const int SimpleFunctionType = 97;
static const int NeverType = 98;
+ static const int IntersectionType = 99;
static const int ConstantExpression = 106;
@@ -179,7 +180,7 @@
/// Internal version of kernel binary format.
/// Bump it when making incompatible changes in kernel binaries.
/// Keep in sync with runtime/vm/kernel_binary.h, pkg/kernel/binary.md.
- static const int BinaryFormatVersion = 83;
+ static const int BinaryFormatVersion = 84;
}
abstract class ConstantTag {
diff --git a/pkg/kernel/lib/core_types.dart b/pkg/kernel/lib/core_types.dart
index 1734950..ec38516 100644
--- a/pkg/kernel/lib/core_types.dart
+++ b/pkg/kernel/lib/core_types.dart
@@ -1142,15 +1142,12 @@
}
// BOTTOM(X&T) is true iff BOTTOM(T).
- if (type is TypeParameterType &&
- type.promotedBound != null &&
- type.isPotentiallyNonNullable) {
- return isBottom(type.promotedBound!);
+ if (type is IntersectionType && type.isPotentiallyNonNullable) {
+ return isBottom(type.right);
}
// BOTTOM(X extends T) is true iff BOTTOM(T).
if (type is TypeParameterType && type.isPotentiallyNonNullable) {
- assert(type.promotedBound == null);
return isBottom(type.parameter.bound);
}
diff --git a/pkg/kernel/lib/src/bounds_checks.dart b/pkg/kernel/lib/src/bounds_checks.dart
index 884fe9d..ccb9e59 100644
--- a/pkg/kernel/lib/src/bounds_checks.dart
+++ b/pkg/kernel/lib/src/bounds_checks.dart
@@ -467,7 +467,7 @@
}
for (int i = 0; i < arguments.length; ++i) {
DartType argument = arguments[i];
- if (argument is TypeParameterType && argument.promotedBound != null) {
+ if (argument is IntersectionType) {
// TODO(cstefantsova): Consider recognizing this case with a flag on the
// issue object.
result.add(new TypeArgumentIssue(i, argument, parameters[i], null));
@@ -642,6 +642,16 @@
}
}
+ @override
+ DartType? visitIntersectionType(IntersectionType node, int variance) {
+ // Types such as X & Never are bottom types.
+ if (isBottom(node) && flipBottom(variance)) {
+ return topType;
+ } else {
+ return null;
+ }
+ }
+
// TypedefTypes receive special treatment because the variance of their
// arguments' positions depend on the opt-in status of the library.
@override
@@ -715,6 +725,13 @@
}
@override
+ int visitIntersectionType(IntersectionType node,
+ Map<TypeParameter, Map<DartType, int>> computedVariances) {
+ if (node.left.parameter == typeParameter) return Variance.covariant;
+ return Variance.unrelated;
+ }
+
+ @override
int visitInterfaceType(InterfaceType node,
Map<TypeParameter, Map<DartType, int>> computedVariances) {
int result = Variance.unrelated;
diff --git a/pkg/kernel/lib/src/coverage.dart b/pkg/kernel/lib/src/coverage.dart
index 553e22f..6625a63 100644
--- a/pkg/kernel/lib/src/coverage.dart
+++ b/pkg/kernel/lib/src/coverage.dart
@@ -744,6 +744,12 @@
}
@override
+ void visitIntersectionType(IntersectionType node) {
+ visited.add(DartTypeKind.IntersectionType);
+ node.visitChildren(this);
+ }
+
+ @override
void visitTypeParameterType(TypeParameterType node) {
visited.add(DartTypeKind.TypeParameterType);
node.visitChildren(this);
@@ -1121,6 +1127,7 @@
FunctionType,
FutureOrType,
InterfaceType,
+ IntersectionType,
InvalidType,
NeverType,
NullType,
diff --git a/pkg/kernel/lib/src/dart_type_equivalence.dart b/pkg/kernel/lib/src/dart_type_equivalence.dart
index 18a2081..60dc0e1 100644
--- a/pkg/kernel/lib/src/dart_type_equivalence.dart
+++ b/pkg/kernel/lib/src/dart_type_equivalence.dart
@@ -194,11 +194,6 @@
@override
bool visitTypeParameterType(TypeParameterType node, DartType other) {
if (other is TypeParameterType) {
- bool nodeIsIntersection = node.promotedBound != null;
- bool otherIsIntersection = other.promotedBound != null;
- if (nodeIsIntersection != otherIsIntersection) {
- return false;
- }
if (!_checkAndRegisterNullabilities(
node.declaredNullability, other.declaredNullability)) {
return false;
@@ -206,9 +201,16 @@
if (!identical(_lookup(node.parameter), other.parameter)) {
return false;
}
- return nodeIsIntersection
- ? node.promotedBound!.accept1(this, other.promotedBound)
- : true;
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ bool visitIntersectionType(IntersectionType node, DartType other) {
+ if (other is IntersectionType) {
+ return node.left.accept1(this, other.left) &&
+ node.right.accept1(this, other.right);
}
return false;
}
diff --git a/pkg/kernel/lib/src/equivalence.dart b/pkg/kernel/lib/src/equivalence.dart
index 365311d..9ee89a7 100644
--- a/pkg/kernel/lib/src/equivalence.dart
+++ b/pkg/kernel/lib/src/equivalence.dart
@@ -666,6 +666,11 @@
}
@override
+ bool visitIntersectionType(IntersectionType node, Node other) {
+ return strategy.checkIntersectionType(this, node, other);
+ }
+
+ @override
bool visitTypeParameterType(TypeParameterType node, Node other) {
return strategy.checkTypeParameterType(this, node, other);
}
@@ -4245,6 +4250,23 @@
return result;
}
+ bool checkIntersectionType(
+ EquivalenceVisitor visitor, IntersectionType? node, Object? other) {
+ if (identical(node, other)) return true;
+ if (node is! IntersectionType) return false;
+ if (other is! IntersectionType) return false;
+ visitor.pushNodeState(node, other);
+ bool result = true;
+ if (!checkIntersectionType_left(visitor, node, other)) {
+ result = visitor.resultOnInequivalence;
+ }
+ if (!checkIntersectionType_right(visitor, node, other)) {
+ result = visitor.resultOnInequivalence;
+ }
+ visitor.popState();
+ return result;
+ }
+
bool checkTypeParameterType(
EquivalenceVisitor visitor, TypeParameterType? node, Object? other) {
if (identical(node, other)) return true;
@@ -4258,9 +4280,6 @@
if (!checkTypeParameterType_parameter(visitor, node, other)) {
result = visitor.resultOnInequivalence;
}
- if (!checkTypeParameterType_promotedBound(visitor, node, other)) {
- result = visitor.resultOnInequivalence;
- }
visitor.popState();
return result;
}
@@ -7351,6 +7370,16 @@
return visitor.checkNodes(node.onType, other.onType, 'onType');
}
+ bool checkIntersectionType_left(EquivalenceVisitor visitor,
+ IntersectionType node, IntersectionType other) {
+ return visitor.checkNodes(node.left, other.left, 'left');
+ }
+
+ bool checkIntersectionType_right(EquivalenceVisitor visitor,
+ IntersectionType node, IntersectionType other) {
+ return visitor.checkNodes(node.right, other.right, 'right');
+ }
+
bool checkTypeParameterType_declaredNullability(EquivalenceVisitor visitor,
TypeParameterType node, TypeParameterType other) {
return visitor.checkValues(node.declaredNullability,
@@ -7363,12 +7392,6 @@
node.parameter, other.parameter, 'parameter');
}
- bool checkTypeParameterType_promotedBound(EquivalenceVisitor visitor,
- TypeParameterType node, TypeParameterType other) {
- return visitor.checkNodes(
- node.promotedBound, other.promotedBound, 'promotedBound');
- }
-
bool checkNamedType_name(
EquivalenceVisitor visitor, NamedType node, NamedType other) {
return visitor.checkValues(node.name, other.name, 'name');
diff --git a/pkg/kernel/lib/src/future_value_type.dart b/pkg/kernel/lib/src/future_value_type.dart
index 773c8e7..b5c2e08 100644
--- a/pkg/kernel/lib/src/future_value_type.dart
+++ b/pkg/kernel/lib/src/future_value_type.dart
@@ -88,6 +88,12 @@
}
@override
+ DartType visitIntersectionType(DartType node, CoreTypes coreTypes) {
+ // Otherwise, for all S, futureValueType(S) = Object?.
+ return coreTypes.objectNullableRawType;
+ }
+
+ @override
DartType visitTypedefType(DartType node, CoreTypes coreTypes) {
// Otherwise, for all S, futureValueType(S) = Object?.
return coreTypes.objectNullableRawType;
diff --git a/pkg/kernel/lib/src/merge_visitor.dart b/pkg/kernel/lib/src/merge_visitor.dart
index 58e18fa..da2040d 100644
--- a/pkg/kernel/lib/src/merge_visitor.dart
+++ b/pkg/kernel/lib/src/merge_visitor.dart
@@ -281,11 +281,7 @@
if (nullability == null) {
return null;
}
- if (a.promotedBound != null && b.promotedBound != null) {
- return mergePromotedTypeParameterTypes(a, b, nullability);
- } else if (a.promotedBound == null && b.promotedBound == null) {
- return mergeTypeParameterTypes(a, b, nullability);
- }
+ return mergeTypeParameterTypes(a, b, nullability);
}
if (b is InvalidType) {
return b;
@@ -296,22 +292,30 @@
DartType mergeTypeParameterTypes(
TypeParameterType a, TypeParameterType b, Nullability nullability) {
assert(a.parameter == b.parameter);
- assert(a.promotedBound == null);
- assert(b.promotedBound == null);
return new TypeParameterType(a.parameter, nullability);
}
- DartType? mergePromotedTypeParameterTypes(
- TypeParameterType a, TypeParameterType b, Nullability nullability) {
- assert(a.parameter == b.parameter);
- assert(a.promotedBound != null);
- assert(b.promotedBound != null);
- DartType? newPromotedBound =
- a.promotedBound!.accept1(this, b.promotedBound);
- if (newPromotedBound == null) {
+ @override
+ DartType? visitIntersectionType(IntersectionType a, DartType b) {
+ if (b is IntersectionType) {
+ return mergeIntersectionTypes(a, b);
+ }
+ if (b is InvalidType) {
+ return b;
+ }
+ return null;
+ }
+
+ DartType? mergeIntersectionTypes(IntersectionType a, IntersectionType b) {
+ DartType? newLeft = a.left.accept1(this, b.left);
+ if (newLeft == null) {
return null;
}
- return new TypeParameterType(a.parameter, nullability, newPromotedBound);
+ DartType? newRight = a.right.accept1(this, b.right);
+ if (newRight == null) {
+ return null;
+ }
+ return new IntersectionType(newLeft as TypeParameterType, newRight);
}
@override
diff --git a/pkg/kernel/lib/src/node_creator.dart b/pkg/kernel/lib/src/node_creator.dart
index 51fc5d4..eb1d1cf 100644
--- a/pkg/kernel/lib/src/node_creator.dart
+++ b/pkg/kernel/lib/src/node_creator.dart
@@ -1134,8 +1134,12 @@
return _createOneOf(_pendingDartTypes, kind, index, [
() =>
TypeParameterType(_needTypeParameter(), Nullability.nonNullable),
- () => TypeParameterType(
- _needTypeParameter(), Nullability.nonNullable, _createDartType()),
+ ]);
+ case DartTypeKind.IntersectionType:
+ return _createOneOf(_pendingDartTypes, kind, index, [
+ () => IntersectionType(
+ TypeParameterType(_needTypeParameter(), Nullability.nonNullable),
+ _createDartType()),
]);
case DartTypeKind.TypedefType:
return _createOneOf(_pendingDartTypes, kind, index, [
diff --git a/pkg/kernel/lib/src/non_null.dart b/pkg/kernel/lib/src/non_null.dart
index b0e7cd2..bcdd0b9 100644
--- a/pkg/kernel/lib/src/non_null.dart
+++ b/pkg/kernel/lib/src/non_null.dart
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE.md file.
import '../ast.dart';
+import '../type_algebra.dart';
/// Returns the type defined as `NonNull(type)` in the nnbd specification.
DartType computeNonNull(DartType type) {
@@ -134,65 +135,70 @@
DartType? visitTypeParameterType(TypeParameterType node) {
// NonNull(X) = X & NonNull(B), where B is the bound of X.
//
- // NonNull(X & T) = X & NonNull(T)
- //
// NonNull(T?) = NonNull(T)
//
// NonNull(T*) = NonNull(T)
if (node.nullability == Nullability.nonNullable) {
return null;
}
- if (node.promotedBound != null) {
- // NonNull(X & T) = X & NonNull(T)
-
- if (node.promotedBound!.nullability == Nullability.nonNullable) {
- // The promoted bound is already non-nullable so we set the declared
- // nullability to non-nullable.
- return node.withDeclaredNullability(Nullability.nonNullable);
+ // NonNull(X) = X & NonNull(B), where B is the bound of X.
+ if (node.bound.nullability == Nullability.nonNullable) {
+ // The bound is already non-nullable so we set the declared nullability
+ // to non-nullable.
+ return node.withDeclaredNullability(Nullability.nonNullable);
+ }
+ DartType? bound = node.bound.accept(this);
+ if (bound == null) {
+ // The bound could not be made non-nullable so we set the declared
+ // nullability to undetermined.
+ if (node.declaredNullability == Nullability.undetermined) {
+ return null;
}
- DartType? promotedBound = node.promotedBound!.accept(this);
- if (promotedBound == null) {
- // The promoted bound could not be made non-nullable so we set the
- // declared nullability to undetermined.
- if (node.declaredNullability == Nullability.undetermined) {
- return null;
- }
- return new TypeParameterType.intersection(
- node.parameter, Nullability.undetermined, node.promotedBound!);
- } else if (promotedBound.nullability == Nullability.nonNullable) {
- // The bound could be made non-nullable so we use it as the promoted
- // bound.
- return new TypeParameterType.intersection(
- node.parameter, Nullability.nonNullable, promotedBound);
- } else {
- // The bound could not be made non-nullable so we use it as the promoted
- // bound with undetermined nullability.
- return new TypeParameterType.intersection(
- node.parameter, Nullability.undetermined, promotedBound);
- }
+ return node.withDeclaredNullability(Nullability.undetermined);
} else {
- // NonNull(X) = X & NonNull(B), where B is the bound of X.
- if (node.bound.nullability == Nullability.nonNullable) {
- // The bound is already non-nullable so we set the declared nullability
- // to non-nullable.
- return node.withDeclaredNullability(Nullability.nonNullable);
+ // The nullability is fully determined by the bound so we pass the
+ // default nullability for the declared nullability.
+ return new IntersectionType(
+ new TypeParameterType(node.parameter,
+ TypeParameterType.computeNullabilityFromBound(node.parameter)),
+ bound);
+ }
+ }
+
+ @override
+ DartType? visitIntersectionType(IntersectionType node) {
+ // NonNull(X & T) = X & NonNull(T)
+ if (node.nullability == Nullability.nonNullable) {
+ return null;
+ }
+
+ if (node.right.nullability == Nullability.nonNullable) {
+ // The RHS is already non-nullable so nothing should be changed.
+ return node.withDeclaredNullability(Nullability.nonNullable);
+ }
+ DartType? right = node.right.accept(this);
+ if (right == null) {
+ // The RHS could not be made non-nullable so we set the
+ // declared nullability to undetermined.
+ if (node.left.declaredNullability == Nullability.undetermined) {
+ return null;
}
- DartType? bound = node.bound.accept(this);
- if (bound == null) {
- // The bound could not be made non-nullable so we set the declared
- // nullability to undetermined.
- if (node.declaredNullability == Nullability.undetermined) {
- return null;
- }
- return node.withDeclaredNullability(Nullability.undetermined);
- } else {
- // The nullability is fully determined by the bound so we pass the
- // default nullability for the declared nullability.
- return new TypeParameterType.intersection(
- node.parameter,
- TypeParameterType.computeNullabilityFromBound(node.parameter),
- bound);
- }
+ return new IntersectionType(
+ new TypeParameterType(node.left.parameter, Nullability.undetermined),
+ node.right);
+ } else if (right.nullability == Nullability.nonNullable) {
+ // The bound could be made non-nullable so we use it as the promoted
+ // bound.
+ return new IntersectionType(
+ computeTypeWithoutNullabilityMarker(node.left,
+ isNonNullableByDefault: true) as TypeParameterType,
+ right);
+ } else {
+ // The bound could not be made non-nullable so we use it as the promoted
+ // bound with undetermined nullability.
+ return new IntersectionType(
+ new TypeParameterType(node.left.parameter, Nullability.undetermined),
+ right);
}
}
diff --git a/pkg/kernel/lib/src/norm.dart b/pkg/kernel/lib/src/norm.dart
index 0cc5d54..e961f27 100644
--- a/pkg/kernel/lib/src/norm.dart
+++ b/pkg/kernel/lib/src/norm.dart
@@ -92,44 +92,43 @@
@override
DartType? visitTypeParameterType(TypeParameterType node, int variance) {
- if (node.promotedBound == null) {
- DartType bound = node.parameter.bound;
- if (normalizesToNever(bound)) {
- DartType result = NeverType.fromNullability(node.nullability);
- return result.accept1(this, variance) ?? result;
- }
- assert(!coreTypes.isBottom(bound));
- // If the bound isn't Never, the type is already normalized.
- return null;
- } else {
- DartType bound = node.promotedBound!;
- bound = bound.accept1(this, variance) ?? bound;
- if (bound is NeverType && bound.nullability == Nullability.nonNullable) {
- return bound;
- } else if (coreTypes.isTop(bound)) {
- assert(!coreTypes.isBottom(bound));
- assert(bound.nullability == Nullability.nullable);
- return new TypeParameterType(node.parameter, node.declaredNullability);
- } else if (bound is TypeParameterType &&
- bound.parameter == node.parameter &&
- bound.declaredNullability == node.declaredNullability &&
- bound.promotedBound == null) {
- assert(!coreTypes.isBottom(bound));
- assert(!coreTypes.isTop(bound));
- return new TypeParameterType(node.parameter, node.declaredNullability);
- } else if (bound == coreTypes.objectNonNullableRawType &&
- norm(coreTypes, node.parameter.bound) ==
- coreTypes.objectNonNullableRawType) {
- return new TypeParameterType(node.parameter, node.declaredNullability);
- } else if (identical(bound, node.promotedBound)) {
- // If [bound] is identical to [node.promotedBound], then the NORM
- // algorithms didn't change the promoted bound, so the [node] is
- // unchanged as well, and we return null to indicate that.
- return null;
- }
- return new TypeParameterType(
- node.parameter, node.declaredNullability, bound);
+ DartType bound = node.parameter.bound;
+ if (normalizesToNever(bound)) {
+ DartType result = NeverType.fromNullability(node.nullability);
+ return result.accept1(this, variance) ?? result;
}
+ assert(!coreTypes.isBottom(bound));
+ // If the bound isn't Never, the type is already normalized.
+ return null;
+ }
+
+ @override
+ DartType? visitIntersectionType(IntersectionType node, int variance) {
+ DartType right = node.right;
+ right = right.accept1(this, variance) ?? right;
+ if (right is NeverType && right.nullability == Nullability.nonNullable) {
+ return right;
+ } else if (coreTypes.isTop(right)) {
+ assert(!coreTypes.isBottom(right));
+ assert(right.nullability == Nullability.nullable);
+ return node.left;
+ } else if (right is TypeParameterType &&
+ right.parameter == node.left.parameter &&
+ right.declaredNullability == node.left.declaredNullability) {
+ assert(!coreTypes.isBottom(right));
+ assert(!coreTypes.isTop(right));
+ return node.left;
+ } else if (right == coreTypes.objectNonNullableRawType &&
+ norm(coreTypes, node.left.parameter.bound) ==
+ coreTypes.objectNonNullableRawType) {
+ return node.left;
+ } else if (identical(right, node.right)) {
+ // If [bound] is identical to [node.right], then the NORM
+ // algorithms didn't change the promoted bound, so the [node] is
+ // unchanged as well, and we return null to indicate that.
+ return null;
+ }
+ return new IntersectionType(node.left, right);
}
@override
@@ -142,11 +141,9 @@
if (type is NeverType && type.nullability == Nullability.nonNullable) {
return true;
} else if (type is TypeParameterType) {
- if (type.promotedBound == null) {
- return normalizesToNever(type.parameter.bound);
- } else {
- return normalizesToNever(type.promotedBound!);
- }
+ return normalizesToNever(type.parameter.bound);
+ } else if (type is IntersectionType) {
+ return normalizesToNever(type.right);
}
return false;
}
diff --git a/pkg/kernel/lib/src/replacement_visitor.dart b/pkg/kernel/lib/src/replacement_visitor.dart
index 5a60355..3fea941 100644
--- a/pkg/kernel/lib/src/replacement_visitor.dart
+++ b/pkg/kernel/lib/src/replacement_visitor.dart
@@ -213,14 +213,17 @@
@override
DartType? visitTypeParameterType(TypeParameterType node, int variance) {
Nullability? newNullability = visitNullability(node);
- if (node.promotedBound != null) {
- DartType? newPromotedBound = node.promotedBound!.accept1(this, variance);
- return createPromotedTypeParameterType(
- node, newNullability, newPromotedBound);
- }
return createTypeParameterType(node, newNullability);
}
+ @override
+ DartType? visitIntersectionType(IntersectionType node, int variance) {
+ DartType? newLeft = node.left.accept1(this, variance);
+ DartType? newRight = node.right.accept1(this, variance);
+ return createIntersectionType(
+ node, newLeft as TypeParameterType?, newRight);
+ }
+
DartType? createTypeParameterType(
TypeParameterType node, Nullability? newNullability) {
if (newNullability == null) {
@@ -231,16 +234,12 @@
}
}
- DartType? createPromotedTypeParameterType(TypeParameterType node,
- Nullability? newNullability, DartType? newPromotedBound) {
- if (newNullability == null && newPromotedBound == null) {
- // No nullability or bound needed to be substituted.
+ DartType? createIntersectionType(
+ IntersectionType node, TypeParameterType? left, DartType? right) {
+ if (left == null && right == null) {
return null;
} else {
- return new TypeParameterType(
- node.parameter,
- newNullability ?? node.declaredNullability,
- newPromotedBound ?? node.promotedBound);
+ return new IntersectionType(left ?? node.left, right ?? node.right);
}
}
diff --git a/pkg/kernel/lib/src/standard_bounds.dart b/pkg/kernel/lib/src/standard_bounds.dart
index 4263359..9e3b8a7 100644
--- a/pkg/kernel/lib/src/standard_bounds.dart
+++ b/pkg/kernel/lib/src/standard_bounds.dart
@@ -211,27 +211,22 @@
}
// MOREBOTTOM(X&S, Y&T) = MOREBOTTOM(S, T).
- if (s is TypeParameterType &&
- s.promotedBound != null &&
- t is TypeParameterType &&
- t.promotedBound != null) {
- return morebottom(s.promotedBound!, t.promotedBound!);
+ if (s is IntersectionType && t is IntersectionType) {
+ return morebottom(s.right, t.right);
}
// MOREBOTTOM(X&S, T) = true.
- if (s is TypeParameterType && s.promotedBound != null) {
+ if (s is IntersectionType) {
return true;
}
// MOREBOTTOM(S, X&T) = false.
- if (t is TypeParameterType && t.promotedBound != null) {
+ if (t is IntersectionType) {
return false;
}
// MOREBOTTOM(X extends S, Y extends T) = MOREBOTTOM(S, T).
if (s is TypeParameterType && t is TypeParameterType) {
- assert(s.promotedBound == null);
- assert(t.promotedBound == null);
return morebottom(s.parameter.bound, t.parameter.bound);
}
@@ -741,11 +736,21 @@
type1, type2, clientLibrary);
}
+ if (type1 is IntersectionType) {
+ return _getNullabilityAwareIntersectionStandardUpperBound(
+ type1, type2, clientLibrary);
+ }
+
if (type2 is TypeParameterType) {
return _getNullabilityAwareTypeParameterStandardUpperBound(
type2, type1, clientLibrary);
}
+ if (type2 is IntersectionType) {
+ return _getNullabilityAwareIntersectionStandardUpperBound(
+ type2, type1, clientLibrary);
+ }
+
if (type1 is FunctionType) {
if (type2 is FunctionType) {
return _getNullabilityAwareFunctionStandardUpperBound(
@@ -1216,67 +1221,65 @@
DartType _getNullabilityAwareTypeParameterStandardUpperBound(
TypeParameterType type1, DartType type2, Library clientLibrary) {
- if (type1.promotedBound == null) {
- // UP(X1 extends B1, T2) =
- // T2 if X1 <: T2
- // otherwise X1 if T2 <: X1
- // 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.nullability));
- }
- if (isSubtypeOf(type2, type1, SubtypeCheckMode.withNullabilities)) {
- return type1.withDeclaredNullability(
- uniteNullabilities(type1.declaredNullability, type2.nullability));
- }
- NullabilityAwareTypeVariableEliminator eliminator =
- new NullabilityAwareTypeVariableEliminator(
- eliminationTargets: <TypeParameter>{type1.parameter},
- bottomType: const NeverType.nonNullable(),
- topType: coreTypes.objectNullableRawType,
- topFunctionType: coreTypes.functionNonNullableRawType,
- unhandledTypeHandler: (type, recursor) => false);
- return _getNullabilityAwareStandardUpperBound(
- eliminator.eliminateToGreatest(type1.parameter.bound),
- type2,
- clientLibrary)
- .withDeclaredNullability(uniteNullabilities(
- type1.declaredNullability,
- uniteNullabilities(type1.parameter.bound.declaredNullability,
- type2.nullability)));
- } else {
- // UP(X1 & B1, T2) =
- // T2 if X1 <: T2
- // otherwise X1 if T2 <: X1
- // 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)) {
- return type2.withDeclaredNullability(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
- }
- if (isSubtypeOf(type2, demoted, SubtypeCheckMode.withNullabilities)) {
- return demoted.withDeclaredNullability(uniteNullabilities(
- type1.declaredNullability, type2.declaredNullability));
- }
- NullabilityAwareTypeVariableEliminator eliminator =
- new NullabilityAwareTypeVariableEliminator(
- eliminationTargets: <TypeParameter>{type1.parameter},
- bottomType: const NeverType.nonNullable(),
- topType: coreTypes.objectNullableRawType,
- topFunctionType: coreTypes.functionNonNullableRawType,
- unhandledTypeHandler: (type, recursor) => false);
- return _getNullabilityAwareStandardUpperBound(
- eliminator.eliminateToGreatest(type1.promotedBound!),
- type2,
- clientLibrary)
- .withDeclaredNullability(uniteNullabilities(
- type1.promotedBound!.declaredNullability, type2.nullability));
+ // UP(X1 extends B1, T2) =
+ // T2 if X1 <: T2
+ // otherwise X1 if T2 <: X1
+ // 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.nullability));
}
+ if (isSubtypeOf(type2, type1, SubtypeCheckMode.withNullabilities)) {
+ return type1.withDeclaredNullability(
+ uniteNullabilities(type1.declaredNullability, type2.nullability));
+ }
+ NullabilityAwareTypeVariableEliminator eliminator =
+ new NullabilityAwareTypeVariableEliminator(
+ eliminationTargets: <TypeParameter>{type1.parameter},
+ bottomType: const NeverType.nonNullable(),
+ topType: coreTypes.objectNullableRawType,
+ topFunctionType: coreTypes.functionNonNullableRawType,
+ unhandledTypeHandler: (type, recursor) => false);
+ return _getNullabilityAwareStandardUpperBound(
+ eliminator.eliminateToGreatest(type1.parameter.bound),
+ type2,
+ clientLibrary)
+ .withDeclaredNullability(uniteNullabilities(
+ type1.declaredNullability,
+ uniteNullabilities(
+ type1.parameter.bound.declaredNullability, type2.nullability)));
+ }
+
+ DartType _getNullabilityAwareIntersectionStandardUpperBound(
+ IntersectionType type1, DartType type2, Library clientLibrary) {
+ // UP(X1 & B1, T2) =
+ // T2 if X1 <: T2
+ // otherwise X1 if T2 <: X1
+ // otherwise UP(B1a, T2)
+ // where B1a is the greatest closure of B1 with respect to X1,
+ // as defined in [inference.md].
+ DartType demoted = type1.left;
+ if (isSubtypeOf(demoted, type2, SubtypeCheckMode.withNullabilities)) {
+ return type2.withDeclaredNullability(uniteNullabilities(
+ type1.declaredNullability, type2.declaredNullability));
+ }
+ if (isSubtypeOf(type2, demoted, SubtypeCheckMode.withNullabilities)) {
+ return demoted.withDeclaredNullability(uniteNullabilities(
+ type1.declaredNullability, type2.declaredNullability));
+ }
+ NullabilityAwareTypeVariableEliminator eliminator =
+ new NullabilityAwareTypeVariableEliminator(
+ eliminationTargets: <TypeParameter>{type1.left.parameter},
+ bottomType: const NeverType.nonNullable(),
+ topType: coreTypes.objectNullableRawType,
+ topFunctionType: coreTypes.functionNonNullableRawType,
+ unhandledTypeHandler: (type, recursor) => false);
+ return _getNullabilityAwareStandardUpperBound(
+ eliminator.eliminateToGreatest(type1.right), type2, clientLibrary)
+ .withDeclaredNullability(uniteNullabilities(
+ type1.right.declaredNullability, type2.nullability));
}
DartType _getNullabilityObliviousStandardUpperBound(
diff --git a/pkg/kernel/lib/src/types.dart b/pkg/kernel/lib/src/types.dart
index 4cfbb33..ba77a54 100644
--- a/pkg/kernel/lib/src/types.dart
+++ b/pkg/kernel/lib/src/types.dart
@@ -106,9 +106,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -127,9 +127,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -138,50 +138,47 @@
return relation.isExtensionRelated(s, t, this);
}
} else if (t is TypeParameterType) {
- if (t.promotedBound == null) {
- const IsTypeParameterSubtypeOf relation =
- const IsTypeParameterSubtypeOf();
- if (s is DynamicType) {
- return relation.isDynamicRelated(s, t, this);
- } else if (s is VoidType) {
- return relation.isVoidRelated(s, t, this);
- } else if (s is InterfaceType) {
- return relation.isInterfaceRelated(s, t, this);
- } else if (s is FunctionType) {
- return relation.isFunctionRelated(s, t, this);
- } else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
- } else if (s is TypedefType) {
- return relation.isTypedefRelated(s, t, this);
- } else if (s is FutureOrType) {
- return relation.isFutureOrRelated(s, t, this);
- } else if (s is ExtensionType) {
- return relation.isExtensionRelated(s, t, this);
- }
- } else {
- const IsIntersectionSubtypeOf relation =
- const IsIntersectionSubtypeOf();
- if (s is DynamicType) {
- return relation.isDynamicRelated(s, t, this);
- } else if (s is VoidType) {
- return relation.isVoidRelated(s, t, this);
- } else if (s is InterfaceType) {
- return relation.isInterfaceRelated(s, t, this);
- } else if (s is FunctionType) {
- return relation.isFunctionRelated(s, t, this);
- } else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
- } else if (s is TypedefType) {
- return relation.isTypedefRelated(s, t, this);
- } else if (s is FutureOrType) {
- return relation.isFutureOrRelated(s, t, this);
- } else if (s is ExtensionType) {
- return relation.isExtensionRelated(s, t, this);
- }
+ const IsTypeParameterSubtypeOf relation =
+ const IsTypeParameterSubtypeOf();
+ if (s is DynamicType) {
+ return relation.isDynamicRelated(s, t, this);
+ } else if (s is VoidType) {
+ return relation.isVoidRelated(s, t, this);
+ } else if (s is InterfaceType) {
+ return relation.isInterfaceRelated(s, t, this);
+ } else if (s is FunctionType) {
+ return relation.isFunctionRelated(s, t, this);
+ } else if (s is TypeParameterType) {
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
+ } else if (s is TypedefType) {
+ return relation.isTypedefRelated(s, t, this);
+ } else if (s is FutureOrType) {
+ return relation.isFutureOrRelated(s, t, this);
+ } else if (s is ExtensionType) {
+ return relation.isExtensionRelated(s, t, this);
+ }
+ } else if (t is IntersectionType) {
+ const IsIntersectionSubtypeOf relation = const IsIntersectionSubtypeOf();
+ if (s is DynamicType) {
+ return relation.isDynamicRelated(s, t, this);
+ } else if (s is VoidType) {
+ return relation.isVoidRelated(s, t, this);
+ } else if (s is InterfaceType) {
+ return relation.isInterfaceRelated(s, t, this);
+ } else if (s is FunctionType) {
+ return relation.isFunctionRelated(s, t, this);
+ } else if (s is TypeParameterType) {
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
+ } else if (s is TypedefType) {
+ return relation.isTypedefRelated(s, t, this);
+ } else if (s is FutureOrType) {
+ return relation.isFutureOrRelated(s, t, this);
+ } else if (s is ExtensionType) {
+ return relation.isExtensionRelated(s, t, this);
}
} else if (t is TypedefType) {
const IsTypedefSubtypeOf relation = const IsTypedefSubtypeOf();
@@ -194,9 +191,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -215,9 +212,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -236,9 +233,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -257,9 +254,9 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -279,9 +276,10 @@
} else if (s is FunctionType) {
return relation.isFunctionRelated(s, t, this);
} else if (s is TypeParameterType) {
- return s.promotedBound == null
- ? relation.isTypeParameterRelated(s, t, this)
- : relation.isIntersectionRelated(s, t, this);
+ return relation.isTypeParameterRelated(s, t, this);
+ } else if (s is IntersectionType) {
+ return relation.isIntersectionRelated(s, t, this);
+ } else if (s is IntersectionType) {
} else if (s is TypedefType) {
return relation.isTypedefRelated(s, t, this);
} else if (s is FutureOrType) {
@@ -362,7 +360,7 @@
IsSubtypeOf isInterfaceRelated(InterfaceType s, T t, Types types);
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, T t, Types types);
+ IntersectionType intersection, T t, Types types);
IsSubtypeOf isFunctionRelated(FunctionType s, T t, Types types);
@@ -414,9 +412,9 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, InterfaceType t, Types types) {
+ IntersectionType intersection, InterfaceType t, Types types) {
return types.performNullabilityAwareSubtypeCheck(
- intersection.promotedBound!, t); // Rule 12.
+ intersection.right, t); // Rule 12.
}
@override
@@ -599,10 +597,9 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, FunctionType t, Types types) {
+ IntersectionType intersection, FunctionType t, Types types) {
// Rule 12.
- return types.performNullabilityAwareSubtypeCheck(
- intersection.promotedBound!, t);
+ return types.performNullabilityAwareSubtypeCheck(intersection.right, t);
}
@override
@@ -652,14 +649,14 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, TypeParameterType t, Types types) {
+ IntersectionType intersection, TypeParameterType t, Types types) {
// Nullable types aren't promoted to intersection types.
// TODO(cstefantsova): Uncomment the following when the inference is
// updated.
//assert(intersection.typeParameterTypeNullability != Nullability.nullable);
// Rule 8.
- if (intersection.parameter == t.parameter) {
+ if (intersection.left.parameter == t.parameter) {
if (intersection.nullability == Nullability.undetermined &&
t.nullability == Nullability.undetermined) {
// The two nullabilities are undetermined, but are connected via
@@ -671,8 +668,7 @@
// Rule 12.
return types.performNullabilityAwareSubtypeCheck(
- intersection.promotedBound!
- .withDeclaredNullability(intersection.nullability),
+ intersection.right.withDeclaredNullability(intersection.nullability),
t);
}
@@ -743,7 +739,7 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, TypedefType t, Types types) {
+ IntersectionType intersection, TypedefType t, Types types) {
return types.performNullabilityAwareSubtypeCheck(intersection, t.unalias);
}
@@ -885,9 +881,9 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, FutureOrType t, Types types) {
- return isTypeParameterRelated(intersection, t, types) // Rule 8.
- .orSubtypeCheckFor(intersection.promotedBound!, t, types); // Rule 12.
+ IntersectionType intersection, FutureOrType t, Types types) {
+ return isTypeParameterRelated(intersection.left, t, types) // Rule 8.
+ .orSubtypeCheckFor(intersection.right, t, types); // Rule 12.
}
@override
@@ -903,67 +899,67 @@
}
}
-class IsIntersectionSubtypeOf extends TypeRelation<TypeParameterType> {
+class IsIntersectionSubtypeOf extends TypeRelation<IntersectionType> {
const IsIntersectionSubtypeOf();
@override
- IsSubtypeOf isIntersectionRelated(TypeParameterType sIntersection,
- TypeParameterType tIntersection, Types types) {
+ IsSubtypeOf isIntersectionRelated(IntersectionType sIntersection,
+ IntersectionType tIntersection, Types types) {
// Rule 9.
return const IsTypeParameterSubtypeOf()
- .isIntersectionRelated(sIntersection, tIntersection, types)
- .andSubtypeCheckFor(sIntersection, tIntersection.promotedBound!, types);
+ .isIntersectionRelated(sIntersection, tIntersection.left, types)
+ .andSubtypeCheckFor(sIntersection, tIntersection.right, types);
}
@override
IsSubtypeOf isTypeParameterRelated(
- TypeParameterType s, TypeParameterType intersection, Types types) {
+ TypeParameterType s, IntersectionType intersection, Types types) {
// Rule 9.
return const IsTypeParameterSubtypeOf()
- .isTypeParameterRelated(s, intersection, types)
- .andSubtypeCheckFor(s, intersection.promotedBound!, types);
+ .isTypeParameterRelated(s, intersection.left, types)
+ .andSubtypeCheckFor(s, intersection.right, types);
}
@override
IsSubtypeOf isInterfaceRelated(
- InterfaceType s, TypeParameterType intersection, Types types) {
+ InterfaceType s, IntersectionType intersection, Types types) {
return const IsSubtypeOf.never();
}
@override
IsSubtypeOf isDynamicRelated(
- DynamicType s, TypeParameterType intersection, Types types) {
+ DynamicType s, IntersectionType intersection, Types types) {
return const IsSubtypeOf.never();
}
@override
IsSubtypeOf isFunctionRelated(
- FunctionType s, TypeParameterType intersection, Types types) {
+ FunctionType s, IntersectionType intersection, Types types) {
return const IsSubtypeOf.never();
}
@override
IsSubtypeOf isFutureOrRelated(
- FutureOrType s, TypeParameterType intersection, Types types) {
+ FutureOrType s, IntersectionType intersection, Types types) {
return const IsSubtypeOf.never();
}
@override
IsSubtypeOf isTypedefRelated(
- TypedefType s, TypeParameterType intersection, Types types) {
+ TypedefType s, IntersectionType intersection, Types types) {
// Rule 5.
return types.performNullabilityAwareSubtypeCheck(s.unalias, intersection);
}
@override
IsSubtypeOf isVoidRelated(
- VoidType s, TypeParameterType intersection, Types types) {
+ VoidType s, IntersectionType intersection, Types types) {
return const IsSubtypeOf.never();
}
@override
IsSubtypeOf isExtensionRelated(
- ExtensionType s, TypeParameterType t, Types types) {
+ ExtensionType s, IntersectionType t, Types types) {
return const IsSubtypeOf.never();
}
}
@@ -988,9 +984,9 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, NullType t, Types types) {
+ IntersectionType intersection, NullType t, Types types) {
return types.performNullabilityAwareMutualSubtypesCheck(
- intersection.promotedBound!, t);
+ intersection.right, t);
}
@override
@@ -1043,9 +1039,8 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, NeverType t, Types types) {
- return types.performNullabilityAwareSubtypeCheck(
- intersection.promotedBound!, t);
+ IntersectionType intersection, NeverType t, Types types) {
+ return types.performNullabilityAwareSubtypeCheck(intersection.right, t);
}
@override
@@ -1098,7 +1093,7 @@
@override
IsSubtypeOf isIntersectionRelated(
- TypeParameterType intersection, ExtensionType t, Types types) {
+ IntersectionType intersection, ExtensionType t, Types types) {
return types.performNullabilityAwareSubtypeCheck(intersection, t.onType);
}
diff --git a/pkg/kernel/lib/testing/type_parser_environment.dart b/pkg/kernel/lib/testing/type_parser_environment.dart
index c550c02..9e33bfe 100644
--- a/pkg/kernel/lib/testing/type_parser_environment.dart
+++ b/pkg/kernel/lib/testing/type_parser_environment.dart
@@ -464,13 +464,12 @@
}
@override
- TypeParameterType visitIntersectionType(
+ IntersectionType visitIntersectionType(
ParsedIntersectionType node, TypeParserEnvironment environment) {
TypeParameterType type =
_parseType(node.a, environment) as TypeParameterType;
DartType bound = _parseType(node.b, environment);
- return new TypeParameterType.intersection(
- type.parameter, type.nullability, bound);
+ return new IntersectionType(type, bound);
}
Supertype toSupertype(InterfaceType type) {
diff --git a/pkg/kernel/lib/text/ast_to_text.dart b/pkg/kernel/lib/text/ast_to_text.dart
index 9b97a47..0e523dd 100644
--- a/pkg/kernel/lib/text/ast_to_text.dart
+++ b/pkg/kernel/lib/text/ast_to_text.dart
@@ -2661,19 +2661,21 @@
void visitTypeParameterType(TypeParameterType node) {
writeTypeParameterReference(node.parameter);
writeNullability(node.declaredNullability);
- DartType? promotedBound = node.promotedBound;
- if (promotedBound != null) {
- writeSpaced('&');
- writeType(promotedBound);
+ }
- writeWord("/* '");
- writeNullability(node.declaredNullability, inComment: true);
- writeWord("' & '");
- writeDartTypeNullability(promotedBound, inComment: true);
- writeWord("' = '");
- writeNullability(node.nullability, inComment: true);
- writeWord("' */");
- }
+ @override
+ void visitIntersectionType(IntersectionType node) {
+ writeType(node.left);
+ writeSpaced('&');
+ writeType(node.right);
+ writeWord("/* '");
+
+ writeDartTypeNullability(node.left, inComment: true);
+ writeWord("' & '");
+ writeDartTypeNullability(node.right, inComment: true);
+ writeWord("' = '");
+ writeNullability(node.nullability, inComment: true);
+ writeWord("' */");
}
@override
diff --git a/pkg/kernel/lib/type_algebra.dart b/pkg/kernel/lib/type_algebra.dart
index aa91ae6..35f89770 100644
--- a/pkg/kernel/lib/type_algebra.dart
+++ b/pkg/kernel/lib/type_algebra.dart
@@ -375,6 +375,12 @@
freeTypeVariables.add(node.parameter);
}
}
+
+ @override
+ void visitIntersectionType(IntersectionType node) {
+ node.left.accept(this);
+ node.right.accept(this);
+ }
}
class _NullSubstitution extends Substitution {
@@ -806,6 +812,11 @@
}
return node;
}
+
+ @override
+ DartType visitIntersectionType(IntersectionType node) {
+ return node.left.accept(this);
+ }
}
class _DeepTypeSubstitutor extends _InnerTypeSubstitutor {
@@ -916,6 +927,11 @@
return variables.contains(node.parameter);
}
+ @override
+ bool visitIntersectionType(IntersectionType node) {
+ return visit(node.left) || visit(node.right);
+ }
+
bool handleTypeParameter(TypeParameter node) {
assert(!variables.contains(node));
if (node.bound.accept(this)) return true;
@@ -988,6 +1004,11 @@
return node.parameter.parent == null && !variables.contains(node.parameter);
}
+ @override
+ bool visitIntersectionType(IntersectionType node) {
+ return visit(node.left) || visit(node.right);
+ }
+
bool handleTypeParameter(TypeParameter node) {
assert(variables.contains(node));
if (node.bound.accept(this)) return true;
@@ -1061,6 +1082,11 @@
return !boundVariables.contains(node.parameter);
}
+ @override
+ bool visitIntersectionType(IntersectionType node) {
+ return visit(node.left) && visit(node.right);
+ }
+
bool handleTypeParameter(TypeParameter node) {
assert(boundVariables.contains(node));
if (node.bound.accept(this)) return true;
@@ -1156,9 +1182,10 @@
bool visitNullType(NullType node) => true;
@override
- bool visitTypeParameterType(TypeParameterType node) {
- return node.promotedBound == null;
- }
+ bool visitTypeParameterType(TypeParameterType node) => true;
+
+ @override
+ bool visitIntersectionType(IntersectionType node) => false;
@override
bool visitTypedefType(TypedefType node) {
@@ -1230,13 +1257,14 @@
@override
DartType visitTypeParameterType(TypeParameterType node, CoreTypes coreTypes) {
- if (node.promotedBound != null) {
- // Intersection types don't have their own nullabilities.
- return node;
- } else {
- return node.withDeclaredNullability(
- TypeParameterType.computeNullabilityFromBound(node.parameter));
- }
+ return node.withDeclaredNullability(
+ TypeParameterType.computeNullabilityFromBound(node.parameter));
+ }
+
+ @override
+ DartType visitIntersectionType(IntersectionType node, CoreTypes coreTypes) {
+ // Intersection types don't have their own nullabilities.
+ return node;
}
@override
@@ -1441,18 +1469,16 @@
assert(isNonNullableByDefault != null);
if (type is TypeParameterType) {
- if (type.promotedBound == null) {
- // The default nullability for library is used when there are no
- // nullability markers on the type.
- return new TypeParameterType(
- type.parameter,
- _defaultNullabilityForTypeParameterType(type.parameter,
- isNonNullableByDefault: isNonNullableByDefault));
- } else {
- // Intersection types can't be arguments to the nullable and the legacy
- // type constructors, so nothing can be peeled off.
- return type;
- }
+ // The default nullability for library is used when there are no
+ // nullability markers on the type.
+ return new TypeParameterType(
+ type.parameter,
+ _defaultNullabilityForTypeParameterType(type.parameter,
+ isNonNullableByDefault: isNonNullableByDefault));
+ } else if (type is IntersectionType) {
+ // Intersection types can't be arguments to the nullable and the legacy
+ // type constructors, so nothing can be peeled off.
+ return type;
} else if (type is NullType) {
return type;
} else {
@@ -1475,10 +1501,9 @@
// The default nullability for library is used when there are no nullability
// markers on the type.
- return type.promotedBound == null &&
- type.declaredNullability ==
- _defaultNullabilityForTypeParameterType(type.parameter,
- isNonNullableByDefault: isNonNullableByDefault);
+ return type.declaredNullability ==
+ _defaultNullabilityForTypeParameterType(type.parameter,
+ isNonNullableByDefault: isNonNullableByDefault);
}
bool isTypeWithoutNullabilityMarker(DartType type,
@@ -1552,6 +1577,9 @@
}
@override
+ bool visitIntersectionType(IntersectionType node) => false;
+
+ @override
bool visitTypedefType(TypedefType node) {
assert(node.declaredNullability != Nullability.undetermined);
return node.declaredNullability == Nullability.nullable ||
@@ -1570,7 +1598,7 @@
/// and Null are nullable, but aren't considered applications of the nullable
/// type constructor.
bool isNullableTypeConstructorApplication(DartType type) {
- if (type is TypeParameterType && type.promotedBound != null) {
+ if (type is IntersectionType) {
// Promoted types are never considered applications of ?.
return false;
}
diff --git a/pkg/kernel/lib/type_checker.dart b/pkg/kernel/lib/type_checker.dart
index 6f2a341..6116e0e 100644
--- a/pkg/kernel/lib/type_checker.dart
+++ b/pkg/kernel/lib/type_checker.dart
@@ -259,8 +259,16 @@
if (superclass.supertype == null) {
return Substitution.empty; // Members on Object are always accessible.
}
- while (type is TypeParameterType) {
- type = type.bound;
+ // TODO(cstefantsova): Implement the procedure for resolving type parameter
+ // types and intersection types.
+ while (true) {
+ if (type is TypeParameterType) {
+ type = type.bound;
+ } else if (type is IntersectionType) {
+ type = type.right;
+ } else {
+ break;
+ }
}
if (type is NeverType || type is NullType || type is InvalidType) {
// The bottom type is a subtype of all types, so it should be allowed.
diff --git a/pkg/kernel/lib/type_environment.dart b/pkg/kernel/lib/type_environment.dart
index a67f7ea..aa06199 100644
--- a/pkg/kernel/lib/type_environment.dart
+++ b/pkg/kernel/lib/type_environment.dart
@@ -115,9 +115,14 @@
/// Returns the non-type parameter type bound of [type].
DartType _resolveTypeParameterType(DartType type) {
- while (type is TypeParameterType) {
- TypeParameterType typeParameterType = type;
- type = typeParameterType.bound;
+ while (true) {
+ if (type is TypeParameterType) {
+ type = type.bound;
+ } else if (type is IntersectionType) {
+ type = type.right;
+ } else {
+ break;
+ }
}
return type;
}
diff --git a/pkg/kernel/lib/visitor.dart b/pkg/kernel/lib/visitor.dart
index 64f3acc..5ab39a6 100644
--- a/pkg/kernel/lib/visitor.dart
+++ b/pkg/kernel/lib/visitor.dart
@@ -748,6 +748,7 @@
R visitNeverType(NeverType node) => defaultDartType(node);
R visitNullType(NullType node) => defaultDartType(node);
R visitExtensionType(ExtensionType node) => defaultDartType(node);
+ R visitIntersectionType(IntersectionType node) => defaultDartType(node);
}
abstract class DartTypeVisitor1<R, T> {
@@ -767,6 +768,8 @@
R visitNeverType(NeverType node, T arg) => defaultDartType(node, arg);
R visitNullType(NullType node, T arg) => defaultDartType(node, arg);
R visitExtensionType(ExtensionType node, T arg) => defaultDartType(node, arg);
+ R visitIntersectionType(IntersectionType node, T arg) =>
+ defaultDartType(node, arg);
}
/// Visitor for [Constant] nodes.
@@ -1143,6 +1146,8 @@
R visitNullType(NullType node) => defaultDartType(node);
@override
R visitExtensionType(ExtensionType node) => defaultDartType(node);
+ @override
+ R visitIntersectionType(IntersectionType node) => defaultDartType(node);
// Constants
@override
diff --git a/pkg/kernel/test/non_null_test.dart b/pkg/kernel/test/non_null_test.dart
index 7ec2800..67d2b6f 100644
--- a/pkg/kernel/test/non_null_test.dart
+++ b/pkg/kernel/test/non_null_test.dart
@@ -66,7 +66,7 @@
'X & Object': 'X & Object',
'X? & Object?': 'X & Object',
'X? & dynamic': 'X & dynamic',
- 'X? & Object': 'X & Object',
+ 'X? & Object': 'X? & Object',
'Y': 'Y & X & Object',
'Y?': 'Y & X & Object',
'Y_extends_dynamic': 'Y_extends_dynamic',
diff --git a/pkg/kernel/test/type_parser.dart b/pkg/kernel/test/type_parser.dart
index 52401b9..a9a998d 100644
--- a/pkg/kernel/test/type_parser.dart
+++ b/pkg/kernel/test/type_parser.dart
@@ -184,11 +184,13 @@
default:
break;
}
- return new TypeParameterType(
+ TypeParameterType typeParameterType = new TypeParameterType(
target,
nullability ??
- TypeParameterType.computeNullabilityFromBound(target),
- promotedBound);
+ TypeParameterType.computeNullabilityFromBound(target));
+ return promotedBound == null
+ ? typeParameterType
+ : new IntersectionType(typeParameterType, promotedBound);
}
return fail("Unexpected lookup result for $name: $target");
diff --git a/pkg/vm/lib/transformations/type_flow/types.dart b/pkg/vm/lib/transformations/type_flow/types.dart
index 6db75a7..ecffc6b 100644
--- a/pkg/vm/lib/transformations/type_flow/types.dart
+++ b/pkg/vm/lib/transformations/type_flow/types.dart
@@ -99,6 +99,13 @@
} else {
result = fromStaticType(bound, canBeNull);
}
+ } else if (type is IntersectionType) {
+ final bound = type.right;
+ if (bound is TypeParameterType) {
+ result = const AnyType();
+ } else {
+ result = fromStaticType(bound, canBeNull);
+ }
} else {
throw 'Unexpected type ${type.runtimeType} $type';
}
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/regress_47878.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/regress_47878.dart.expect
index d52c496..e967752 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/regress_47878.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/regress_47878.dart.expect
@@ -14,7 +14,7 @@
self::DataStream::T? lastValue = block {
#C1!;
} =>throw "Attempt to execute code removed by Dart AOT compiler (TFA)";
- if(!(throw "Attempt to execute code removed by Dart AOT compiler (TFA)") && false && !([@vm.inferred-type.metadata=dart.core::bool (skip check) (receiver not int)] lastValue{self::DataStream::T & self::Disposable /* '!' & '!' = '!' */} =={core::Object::==}{(core::Object) → core::bool} #C1)) {
+ if(!(throw "Attempt to execute code removed by Dart AOT compiler (TFA)") && false && !([@vm.inferred-type.metadata=dart.core::bool (skip check) (receiver not int)] lastValue{self::DataStream::T% & self::Disposable /* '%' & '!' = '!' */} =={core::Object::==}{(core::Object) → core::bool} #C1)) {
}
}
}
diff --git a/runtime/vm/compiler/frontend/kernel_fingerprints.cc b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
index 6be0574..3896a91 100644
--- a/runtime/vm/compiler/frontend/kernel_fingerprints.cc
+++ b/runtime/vm/compiler/frontend/kernel_fingerprints.cc
@@ -251,9 +251,12 @@
Nullability nullability = ReadNullability();
BuildHash(static_cast<uint32_t>(nullability));
ReadUInt(); // read index for parameter.
- CalculateOptionalDartTypeFingerprint(); // read bound bound.
break;
}
+ case kIntersectionType:
+ CalculateDartTypeFingerprint(); // read left;
+ CalculateDartTypeFingerprint(); // read right;
+ break;
default:
ReportUnexpectedTag("type", tag);
UNREACHABLE();
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.cc b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
index b84479f..ced4d94 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.cc
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.cc
@@ -2221,7 +2221,10 @@
case kTypeParameterType:
ReadNullability(); // read nullability.
ReadUInt(); // read index for parameter.
- SkipOptionalDartType(); // read bound bound.
+ return;
+ case kIntersectionType:
+ SkipDartType(); // read left.
+ SkipDartType(); // read right.
return;
default:
ReportUnexpectedTag("type", tag);
@@ -3152,6 +3155,9 @@
refers_to_derived_type_param_ = true;
}
break;
+ case kIntersectionType:
+ BuildIntersectionType();
+ break;
default:
helper_->ReportUnexpectedTag("type", tag);
UNREACHABLE();
@@ -3300,7 +3306,6 @@
}
intptr_t parameter_index = helper_->ReadUInt(); // read parameter index.
- helper_->SkipOptionalDartType(); // read bound.
// If the type is from a constant, the parameter index isn't offset by the
// enclosing context.
@@ -3398,6 +3403,11 @@
active_class_->ToCString());
}
+void TypeTranslator::BuildIntersectionType() {
+ BuildTypeInternal(); // read left.
+ helper_->SkipDartType(); // read right.
+}
+
const TypeArguments& TypeTranslator::BuildTypeArguments(intptr_t length) {
bool only_dynamic = true;
intptr_t offset = helper_->ReaderOffset();
diff --git a/runtime/vm/compiler/frontend/kernel_translation_helper.h b/runtime/vm/compiler/frontend/kernel_translation_helper.h
index 314cab9..badf719 100644
--- a/runtime/vm/compiler/frontend/kernel_translation_helper.h
+++ b/runtime/vm/compiler/frontend/kernel_translation_helper.h
@@ -1540,6 +1540,7 @@
void BuildInterfaceType(bool simple);
void BuildFunctionType(bool simple);
void BuildTypeParameterType();
+ void BuildIntersectionType();
class TypeParameterScope {
public:
diff --git a/runtime/vm/compiler/frontend/scope_builder.cc b/runtime/vm/compiler/frontend/scope_builder.cc
index b6e849e..037d9ae 100644
--- a/runtime/vm/compiler/frontend/scope_builder.cc
+++ b/runtime/vm/compiler/frontend/scope_builder.cc
@@ -1358,6 +1358,9 @@
case kTypeParameterType:
VisitTypeParameterType();
return;
+ case kIntersectionType:
+ VisitIntersectionType();
+ return;
default:
ReportUnexpectedTag("type", tag);
UNREACHABLE();
@@ -1447,8 +1450,11 @@
}
}
}
+}
- helper_.SkipOptionalDartType(); // read bound bound.
+void ScopeBuilder::VisitIntersectionType() {
+ VisitDartType(); // read left.
+ helper_.SkipDartType(); // read right.
}
void ScopeBuilder::HandleLocalFunction(intptr_t parent_kernel_offset) {
diff --git a/runtime/vm/compiler/frontend/scope_builder.h b/runtime/vm/compiler/frontend/scope_builder.h
index ef1a985..619a686 100644
--- a/runtime/vm/compiler/frontend/scope_builder.h
+++ b/runtime/vm/compiler/frontend/scope_builder.h
@@ -47,6 +47,7 @@
void VisitInterfaceType(bool simple);
void VisitFunctionType(bool simple);
void VisitTypeParameterType();
+ void VisitIntersectionType();
void HandleLocalFunction(intptr_t parent_kernel_offset);
AbstractType& BuildAndVisitVariableType();
diff --git a/runtime/vm/compiler/recognized_methods_list.h b/runtime/vm/compiler/recognized_methods_list.h
index 19ed9a6..6f83801 100644
--- a/runtime/vm/compiler/recognized_methods_list.h
+++ b/runtime/vm/compiler/recognized_methods_list.h
@@ -15,11 +15,11 @@
V(::, identical, ObjectIdentical, 0x04168315) \
V(ClassID, getID, ClassIDgetID, 0xdc8b888a) \
V(Object, Object., ObjectConstructor, 0xab6d6cfa) \
- V(List, ., ListFactory, 0xbc820cf9) \
- V(_List, ., ObjectArrayAllocate, 0xd693eee6) \
- V(_List, []=, ObjectArraySetIndexed, 0xd7b48abc) \
- V(_GrowableList, ._withData, GrowableArrayAllocateWithData, 0xa32d060b) \
- V(_GrowableList, []=, GrowableArraySetIndexed, 0xd7b48abc) \
+ V(List, ., ListFactory, 0x1892cc51) \
+ V(_List, ., ObjectArrayAllocate, 0x4c9d39e2) \
+ V(_List, []=, ObjectArraySetIndexed, 0x050cd2ba) \
+ V(_GrowableList, ._withData, GrowableArrayAllocateWithData, 0x1947d8a1) \
+ V(_GrowableList, []=, GrowableArraySetIndexed, 0x050cd2ba) \
V(_TypedList, _getInt8, ByteArrayBaseGetInt8, 0x1623dc34) \
V(_TypedList, _getUint8, ByteArrayBaseGetUint8, 0x177ffe2a) \
V(_TypedList, _getInt16, ByteArrayBaseGetInt16, 0x2e40964f) \
@@ -144,8 +144,8 @@
V(_Double, roundToDouble, DoubleRoundToDouble, 0x5649ca00) \
V(_Double, toInt, DoubleToInteger, 0x676f20a9) \
V(_Double, truncateToDouble, DoubleTruncateToDouble, 0x62d48659) \
- V(::, min, MathMin, 0xc2021a5b) \
- V(::, max, MathMax, 0xe45b2596) \
+ V(::, min, MathMin, 0xd0ef27f3) \
+ V(::, max, MathMax, 0xbbfa2f8c) \
V(::, _doublePow, MathDoublePow, 0x989f3334) \
V(::, _intPow, MathIntPow, 0xb9afc09a) \
V(::, _sin, MathSin, 0x17daca03) \
@@ -169,8 +169,8 @@
0x70f53b2b) \
V(FinalizerBase, set:_isolateFinalizers, FinalizerBase_setIsolateFinalizers, \
0xb3e66928) \
- V(_FinalizerImpl, get:_callback, Finalizer_getCallback, 0x6f3d56bc) \
- V(_FinalizerImpl, set:_callback, Finalizer_setCallback, 0xc6aa96f9) \
+ V(_FinalizerImpl, get:_callback, Finalizer_getCallback, 0x185ebcf8) \
+ V(_FinalizerImpl, set:_callback, Finalizer_setCallback, 0xad0b5e35) \
V(_NativeFinalizer, get:_callback, NativeFinalizer_getCallback, 0x5cb374f5) \
V(_NativeFinalizer, set:_callback, NativeFinalizer_setCallback, 0xb12268f2) \
V(FinalizerEntry, allocate, FinalizerEntry_allocate, 0xe0bad878) \
@@ -259,11 +259,11 @@
V(_WeakProperty, set:key, WeakProperty_setKey, 0x963a095f) \
V(_WeakProperty, get:value, WeakProperty_getValue, 0xd2f28aae) \
V(_WeakProperty, set:value, WeakProperty_setValue, 0x8b2bafab) \
- V(_WeakReferenceImpl, get:target, WeakReference_getTarget, 0x632d6ca8) \
- V(_WeakReferenceImpl, set:_target, WeakReference_setTarget, 0x6edc7518) \
+ V(_WeakReferenceImpl, get:target, WeakReference_getTarget, 0xc990118a) \
+ V(_WeakReferenceImpl, set:_target, WeakReference_setTarget, 0xc729697a) \
V(::, _classRangeCheck, ClassRangeCheck, 0x09f5fc7a) \
V(::, _abi, FfiAbi, 0x7c4ab3b4) \
- V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x92ae104f) \
+ V(::, _asFunctionInternal, FfiAsFunctionInternal, 0x631b1071) \
V(::, _nativeCallbackFunction, FfiNativeCallbackFunction, 0x3ff5ae9c) \
V(::, _nativeEffect, NativeEffect, 0x537dce91) \
V(::, _loadAbiSpecificInt, FfiLoadAbiSpecificInt, 0x7807e872) \
@@ -280,7 +280,7 @@
V(::, _loadFloatUnaligned, FfiLoadFloatUnaligned, 0xc8c8dfff) \
V(::, _loadDouble, FfiLoadDouble, 0xf70cc619) \
V(::, _loadDoubleUnaligned, FfiLoadDoubleUnaligned, 0xc99ebd39) \
- V(::, _loadPointer, FfiLoadPointer, 0x4e79d0fc) \
+ V(::, _loadPointer, FfiLoadPointer, 0x9a0810c4) \
V(::, _storeAbiSpecificInt, FfiStoreAbiSpecificInt, 0xc70954c0) \
V(::, _storeAbiSpecificIntAtIndex, FfiStoreAbiSpecificIntAtIndex, 0xc64efe4b)\
V(::, _storeInt8, FfiStoreInt8, 0xdf50b2cd) \
@@ -295,8 +295,8 @@
V(::, _storeFloatUnaligned, FfiStoreFloatUnaligned, 0x600a9203) \
V(::, _storeDouble, FfiStoreDouble, 0x42998c64) \
V(::, _storeDoubleUnaligned, FfiStoreDoubleUnaligned, 0x3dced75b) \
- V(::, _storePointer, FfiStorePointer, 0xea6b7751) \
- V(::, _fromAddress, FfiFromAddress, 0xfd8cb1cc) \
+ V(::, _storePointer, FfiStorePointer, 0x8b68e519) \
+ V(::, _fromAddress, FfiFromAddress, 0x811e2220) \
V(Pointer, get:address, FfiGetAddress, 0x7cde87be) \
V(::, _asExternalTypedDataInt8, FfiAsExternalTypedDataInt8, 0x768a0698) \
V(::, _asExternalTypedDataInt16, FfiAsExternalTypedDataInt16, 0xd09cf9c6) \
@@ -311,10 +311,10 @@
V(::, _getNativeField, GetNativeField, 0xa0139b85) \
V(::, reachabilityFence, ReachabilityFence, 0x730f2b7f) \
V(_Utf8Decoder, _scan, Utf8DecoderScan, 0xf296c901) \
- V(_Future, timeout, FutureTimeout, 0xa7cb3294) \
- V(Future, wait, FutureWait, 0xb0b596bd) \
- V(_RootZone, runUnary, RootZoneRunUnary, 0xb607f8bf) \
- V(_FutureListener, handleValue, FutureListenerHandleValue, 0x438115a8) \
+ V(_Future, timeout, FutureTimeout, 0xbc736ef8) \
+ V(Future, wait, FutureWait, 0x764434e5) \
+ V(_RootZone, runUnary, RootZoneRunUnary, 0x7168b20b) \
+ V(_FutureListener, handleValue, FutureListenerHandleValue, 0x25b39832) \
V(::, has63BitSmis, Has63BitSmis, 0xf61b56f1) \
V(::, get:extensionStreamHasListener, ExtensionStreamHasListener, 0xfab46343)\
@@ -430,14 +430,14 @@
#define GRAPH_CORE_INTRINSICS_LIST(V) \
V(_Array, get:length, ObjectArrayLength, 0x5850f06b) \
- V(_Array, [], ObjectArrayGetIndexed, 0x57b029cf) \
- V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0x02f293ae) \
+ V(_Array, [], ObjectArrayGetIndexed, 0x78f4f491) \
+ V(_List, _setIndexed, ObjectArraySetIndexedUnchecked, 0xe62fb5f0) \
V(_GrowableList, get:length, GrowableArrayLength, 0x5850f06b) \
V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x7d9f9bf2) \
V(_GrowableList, _setData, GrowableArraySetData, 0xbdda401b) \
V(_GrowableList, _setLength, GrowableArraySetLength, 0xcc1bf9b6) \
- V(_GrowableList, [], GrowableArrayGetIndexed, 0x57b029cf) \
- V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0xfb40ee4f) \
+ V(_GrowableList, [], GrowableArrayGetIndexed, 0x78f4f491) \
+ V(_GrowableList, _setIndexed, GrowableArraySetIndexedUnchecked, 0x514b032f) \
V(_StringBase, get:length, StringBaseLength, 0x5850f06b) \
V(_OneByteString, codeUnitAt, OneByteStringCodeUnitAt, 0x17f90910) \
V(_TwoByteString, codeUnitAt, TwoByteStringCodeUnitAt, 0x17f90910) \
@@ -522,17 +522,17 @@
// (factory-name-symbol, class-name-string, constructor-name-string,
// result-cid, fingerprint).
#define RECOGNIZED_LIST_FACTORY_LIST(V) \
- V(_ListFactory, _List, ., kArrayCid, 0xd693eee6) \
- V(_ListFilledFactory, _List, .filled, kArrayCid, 0x7ffc3415) \
- V(_ListGenerateFactory, _List, .generate, kArrayCid, 0xc85f10b8) \
+ V(_ListFactory, _List, ., kArrayCid, 0x4c9d39e2) \
+ V(_ListFilledFactory, _List, .filled, kArrayCid, 0xe23ae9b1) \
+ V(_ListGenerateFactory, _List, .generate, kArrayCid, 0xa7c3f2ee) \
V(_GrowableListFactory, _GrowableList, ., kGrowableObjectArrayCid, \
- 0x3bff5c79) \
+ 0xf210216d) \
V(_GrowableListFilledFactory, _GrowableList, .filled, \
- kGrowableObjectArrayCid, 0x38a40a6d) \
+ kGrowableObjectArrayCid, 0x3aa70b31) \
V(_GrowableListGenerateFactory, _GrowableList, .generate, \
- kGrowableObjectArrayCid, 0x85567510) \
+ kGrowableObjectArrayCid, 0xe123f46e) \
V(_GrowableListWithData, _GrowableList, ._withData, kGrowableObjectArrayCid, \
- 0xa32d060b) \
+ 0x1947d8a1) \
V(_Int8ArrayFactory, Int8List, ., kTypedDataInt8ArrayCid, 0x660dd888) \
V(_Uint8ArrayFactory, Uint8List, ., kTypedDataUint8ArrayCid, 0xede3f64f) \
V(_Uint8ClampedArrayFactory, Uint8ClampedList, ., \
diff --git a/runtime/vm/kernel_binary.h b/runtime/vm/kernel_binary.h
index b0658b3..6465f9a2 100644
--- a/runtime/vm/kernel_binary.h
+++ b/runtime/vm/kernel_binary.h
@@ -20,8 +20,8 @@
static const uint32_t kMagicProgramFile = 0x90ABCDEFu;
// Both version numbers are inclusive.
-static const uint32_t kMinSupportedKernelFormatVersion = 83;
-static const uint32_t kMaxSupportedKernelFormatVersion = 83;
+static const uint32_t kMinSupportedKernelFormatVersion = 84;
+static const uint32_t kMaxSupportedKernelFormatVersion = 84;
// Keep in sync with package:kernel/lib/binary/tag.dart
#define KERNEL_TAG_LIST(V) \
@@ -122,6 +122,7 @@
V(AssertBlock, 81) \
V(TypedefType, 87) \
V(NeverType, 98) \
+ V(IntersectionType, 99) \
V(InvalidType, 90) \
V(DynamicType, 91) \
V(VoidType, 92) \