diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart index 7083e91c655..6ee4b901f40 100644 --- a/pkg/compiler/lib/src/deferred_load.dart +++ b/pkg/compiler/lib/src/deferred_load.dart @@ -1652,16 +1652,6 @@ class TypeDependencyVisitor implements DartTypeVisitor { types.forEach(visit); } - @override - void visitLegacyType(LegacyType type, Null argument) { - visit(type.baseType); - } - - @override - void visitNullableType(NullableType type, Null argument) { - visit(type.baseType); - } - @override void visitFutureOrType(FutureOrType type, Null argument) { _dependencies.addClass(_commonElements.futureClass); diff --git a/pkg/compiler/lib/src/elements/types.dart b/pkg/compiler/lib/src/elements/types.dart index 008cda1b6ce..b4bdca3beb7 100644 --- a/pkg/compiler/lib/src/elements/types.dart +++ b/pkg/compiler/lib/src/elements/types.dart @@ -22,14 +22,44 @@ import 'entities.dart'; /// implemented directly but other entity systems, for instance based directly /// on kernel ir without the need for [Element]. +enum Nullability { + none, + question, + star, +} + +extension NullabilityUtils on Nullability { + bool get isNone => this == Nullability.none; + bool get isQuestion => this == Nullability.question; + bool get isStar => this == Nullability.star; + bool get isPotentiallyNull => isQuestion || isStar; + bool get isPotentiallyNonNull => isNone || isStar; + + int compareTo(Nullability other) => index.compareTo(other.index); +} + abstract class DartType { - const DartType(); + final Nullability nullability; + + const DartType(this.nullability); + + /// Returns a new type formed by replacing the current [nullability] with the + /// specified one. + DartType _withNullability(Nullability nullability); + + DartType _withoutNullability() => _withNullability(Nullability.none); + DartType _withQuestion() => _withNullability(Nullability.question); /// Is `true` if this type is a top type. - bool _isTop(bool isLegacy) => false; + bool _isTop(bool useNullSafety) => false; - /// Is `true` if this type has no non-top type arguments. - bool _treatAsRaw(bool isLegacy) => true; + /// Is `true` if every type argument of this type is a top type. + // TODO(fishythefish): Should we instead check if each type argument is at its + // bound? + bool _treatAsRaw(bool useNullSafety) => true; + + /// Is `true` if this type is a top type but not a legacy top type. + bool _isStrongTop(bool useNullSafety) => _isTop(useNullSafety); /// Whether this type contains a type variable. bool get containsTypeVariables => false; @@ -96,6 +126,15 @@ class _Assumptions { _addAssumption(b, a); } + void assumePairs( + List as, List bs) { + int length = as.length; + assert(length == bs.length); + for (int i = 0; i < length; i++) { + assume(as[i], bs[i]); + } + } + void _removeAssumption(FunctionTypeVariable a, FunctionTypeVariable b) { Set set = _assumptionMap[a]; if (set != null) { @@ -112,6 +151,15 @@ class _Assumptions { _removeAssumption(b, a); } + void forgetPairs( + List as, List bs) { + int length = as.length; + assert(length == bs.length); + for (int i = 0; i < length; i++) { + forget(as[i], bs[i]); + } + } + /// Returns `true` if [a] and [b] are assumed to be equivalent. bool isAssumed(FunctionTypeVariable a, FunctionTypeVariable b) { return _assumptionMap[a]?.contains(b) ?? false; @@ -133,94 +181,25 @@ class _Assumptions { } } -class LegacyType extends DartType { - final DartType baseType; - - LegacyType(this.baseType); - - @override - bool get containsTypeVariables => baseType.containsTypeVariables; - - @override - void forEachTypeVariable(f(TypeVariableType variable)) { - baseType.forEachTypeVariable(f); - } - - @override - R accept(DartTypeVisitor visitor, A argument) => - visitor.visitLegacyType(this, argument); - - @override - int get hashCode => baseType.hashCode * 31; - - @override - bool operator ==(other) { - if (identical(this, other)) return true; - if (other is! LegacyType) return false; - return _equalsInternal(other, null); - } - - @override - bool _equals(DartType other, _Assumptions assumptions) { - if (identical(this, other)) return true; - if (other is! LegacyType) return false; - return _equalsInternal(other, assumptions); - } - - bool _equalsInternal(LegacyType other, _Assumptions assumptions) => - baseType._equals(other.baseType, assumptions); -} - -class NullableType extends DartType { - final DartType baseType; - - NullableType(this.baseType); - - @override - bool _isTop(bool isLegacy) => isLegacy ? false : baseType.isObject; - - @override - bool get containsTypeVariables => baseType.containsTypeVariables; - - @override - void forEachTypeVariable(f(TypeVariableType variable)) { - baseType.forEachTypeVariable(f); - } - - @override - R accept(DartTypeVisitor visitor, A argument) => - visitor.visitNullableType(this, argument); - - @override - int get hashCode => baseType.hashCode * 37; - - @override - bool operator ==(other) { - if (identical(this, other)) return true; - if (other is! NullableType) return false; - return _equalsInternal(other, null); - } - - @override - bool _equals(DartType other, _Assumptions assumptions) { - if (identical(this, other)) return true; - if (other is! NullableType) return false; - return _equalsInternal(other, assumptions); - } - - bool _equalsInternal(NullableType other, _Assumptions assumptions) => - baseType._equals(other.baseType, assumptions); -} - class InterfaceType extends DartType { final ClassEntity element; final List typeArguments; - InterfaceType(this.element, this.typeArguments) - : assert(typeArguments.every((e) => e != null)); + InterfaceType(this.element, this.typeArguments, Nullability nullability) + : assert(typeArguments.every((e) => e != null)), + super(nullability); @override - bool _isTop(bool isLegacy) => isLegacy ? isObject : false; + DartType _withNullability(Nullability nullability) => + InterfaceType(element, typeArguments, nullability); + + @override + bool _isTop(bool useNullSafety) => + isObject && (!useNullSafety || nullability.isPotentiallyNull); + + @override + bool _isStrongTop(bool useNullSafety) => + isObject && (!useNullSafety || nullability.isQuestion); @override bool get isObject => @@ -241,9 +220,9 @@ class InterfaceType extends DartType { } @override - bool _treatAsRaw(bool isLegacy) { + bool _treatAsRaw(bool useNullSafety) { for (DartType type in typeArguments) { - if (!type._isTop(isLegacy)) return false; + if (!type._isTop(useNullSafety)) return false; } return true; } @@ -259,6 +238,7 @@ class InterfaceType extends DartType { int argumentHash = argument != null ? argument.hashCode : 0; hash = 17 * hash + 3 * argumentHash; } + hash = 17 * hash + nullability.hashCode; return hash; } @@ -277,7 +257,8 @@ class InterfaceType extends DartType { } bool _equalsInternal(InterfaceType other, _Assumptions assumptions) { - return identical(element, other.element) && + return nullability == other.nullability && + identical(element, other.element) && _equalTypes(typeArguments, other.typeArguments, assumptions); } } @@ -285,7 +266,12 @@ class InterfaceType extends DartType { class TypeVariableType extends DartType { final TypeVariableEntity element; - TypeVariableType(this.element); + const TypeVariableType(this.element, Nullability nullability) + : super(nullability); + + @override + DartType _withNullability(Nullability nullability) => + TypeVariableType(element, nullability); @override bool get containsTypeVariables => true; @@ -300,21 +286,17 @@ class TypeVariableType extends DartType { visitor.visitTypeVariableType(this, argument); @override - int get hashCode => 17 * element.hashCode; + int get hashCode => 17 * element.hashCode + nullability.hashCode; @override - bool operator ==(other) { - if (other is! TypeVariableType) return false; - return identical(other.element, element); - } + bool operator ==(other) => + identical(this, other) || + other is TypeVariableType && + nullability == other.nullability && + identical(other.element, element); @override - bool _equals(DartType other, _Assumptions assumptions) { - if (other is TypeVariableType) { - return identical(other.element, element); - } - return false; - } + bool _equals(DartType other, _Assumptions assumptions) => this == other; } /// A type variable declared on a function type. @@ -334,7 +316,12 @@ class FunctionTypeVariable extends DartType { /// The bound of this function type variable. DartType _bound; - FunctionTypeVariable(this.index); + FunctionTypeVariable(this.index, Nullability nullability) + : super(nullability); + + @override + DartType _withNullability(Nullability nullability) => + FunctionTypeVariable(index, nullability)..bound = bound; DartType get bound { assert(_bound != null, "Bound has not been set."); @@ -346,20 +333,11 @@ class FunctionTypeVariable extends DartType { _bound = value; } - @override - int get hashCode => index.hashCode * 19; - - @override - bool operator ==(other) { - if (identical(this, other)) return true; - if (other is! FunctionTypeVariable) return false; - return false; - } - @override bool _equals(DartType other, _Assumptions assumptions) { if (identical(this, other)) return true; if (other is! FunctionTypeVariable) return false; + if (nullability != other.nullability) return false; if (assumptions != null) return assumptions.isAssumed(this, other); return false; } @@ -370,29 +348,37 @@ class FunctionTypeVariable extends DartType { } class NeverType extends DartType { - const NeverType._(); + const NeverType(Nullability nullability) : super(nullability); - factory NeverType() => const NeverType._(); + @override + DartType _withNullability(Nullability nullability) => NeverType(nullability); @override R accept(DartTypeVisitor visitor, A argument) => visitor.visitNeverType(this, argument); @override - int get hashCode => 41; + int get hashCode => nullability.hashCode; @override - bool _equals(DartType other, _Assumptions assumptions) => - identical(this, other); + bool operator ==(other) => + identical(this, other) || + other is NeverType && nullability == other.nullability; + + @override + bool _equals(DartType other, _Assumptions assumptions) => this == other; } class VoidType extends DartType { - const VoidType._(); + const VoidType._() : super(Nullability.none); factory VoidType() => const VoidType._(); @override - bool _isTop(bool isLegacy) => true; + DartType _withNullability(Nullability nullability) => this; + + @override + bool _isTop(bool useNullSafety) => true; @override R accept(DartTypeVisitor visitor, A argument) => @@ -402,18 +388,22 @@ class VoidType extends DartType { int get hashCode => 6007; @override - bool _equals(DartType other, _Assumptions assumptions) { - return identical(this, other); - } + bool operator ==(other) => identical(this, other) || other is VoidType; + + @override + bool _equals(DartType other, _Assumptions assumptions) => this == other; } class DynamicType extends DartType { - const DynamicType._(); + const DynamicType._() : super(Nullability.none); factory DynamicType() => const DynamicType._(); @override - bool _isTop(bool isLegacy) => true; + DartType _withNullability(Nullability nullability) => this; + + @override + bool _isTop(bool useNullSafety) => true; @override R accept(DartTypeVisitor visitor, A argument) => @@ -423,18 +413,22 @@ class DynamicType extends DartType { int get hashCode => 91; @override - bool _equals(DartType other, _Assumptions assumptions) { - return identical(this, other); - } + bool operator ==(other) => identical(this, other) || other is DynamicType; + + @override + bool _equals(DartType other, _Assumptions assumptions) => this == other; } class ErasedType extends DartType { - const ErasedType._(); + const ErasedType._() : super(Nullability.none); factory ErasedType() => const ErasedType._(); @override - bool _isTop(bool isLegacy) => true; + DartType _withNullability(Nullability nullability) => this; + + @override + bool _isTop(bool useNullSafety) => true; @override R accept(DartTypeVisitor visitor, A argument) => @@ -444,8 +438,10 @@ class ErasedType extends DartType { int get hashCode => 119; @override - bool _equals(DartType other, _Assumptions assumptions) => - identical(this, other); + bool operator ==(other) => identical(this, other) || other is ErasedType; + + @override + bool _equals(DartType other, _Assumptions assumptions) => this == other; } /// Represents a type which is simultaneously top and bottom. @@ -460,12 +456,15 @@ class ErasedType extends DartType { /// * Representing types appearing as generic method bounds which contain type /// variables. (See issue 33422.) class AnyType extends DartType { - const AnyType._(); + const AnyType._() : super(Nullability.none); factory AnyType() => const AnyType._(); @override - bool _isTop(bool isLegacy) => true; + DartType _withNullability(Nullability nullability) => this; + + @override + bool _isTop(bool useNullSafety) => true; @override R accept(DartTypeVisitor visitor, A argument) => @@ -475,8 +474,10 @@ class AnyType extends DartType { int get hashCode => 95; @override - bool _equals(DartType other, _Assumptions assumptions) => - identical(this, other); + bool operator ==(other) => identical(this, other) || other is AnyType; + + @override + bool _equals(DartType other, _Assumptions assumptions) => this == other; } class FunctionType extends DartType { @@ -499,7 +500,9 @@ class FunctionType extends DartType { this.optionalParameterTypes, this.namedParameters, this.namedParameterTypes, - this.typeVariables) { + this.typeVariables, + Nullability nullability) + : super(nullability) { assert(returnType != null, "Invalid return type in $this."); assert(!parameterTypes.contains(null), "Invalid parameter types in $this."); assert(!optionalParameterTypes.contains(null), @@ -511,10 +514,15 @@ class FunctionType extends DartType { assert(!typeVariables.contains(null), "Invalid type variables in $this."); } - bool get isGeneric => typeVariables.isNotEmpty; - - List get typeVariableBounds => - typeVariables.map((FunctionTypeVariable v) => v.bound).toList(); + @override + DartType _withNullability(Nullability nullability) => FunctionType( + returnType, + parameterTypes, + optionalParameterTypes, + namedParameters, + namedParameterTypes, + typeVariables, + nullability); @override bool get containsTypeVariables { @@ -557,6 +565,7 @@ class FunctionType extends DartType { for (DartType parameter in namedParameterTypes) { hash = 29 * hash + 13 * parameter.hashCode; } + hash = 31 * hash + nullability.hashCode; return hash; } @@ -575,12 +584,11 @@ class FunctionType extends DartType { } bool _equalsInternal(FunctionType other, _Assumptions assumptions) { + if (nullability != other.nullability) return false; if (typeVariables.length != other.typeVariables.length) return false; - if (typeVariables.isNotEmpty) { - assumptions ??= new _Assumptions(); - for (int index = 0; index < typeVariables.length; index++) { - assumptions.assume(typeVariables[index], other.typeVariables[index]); - } + assumptions ??= _Assumptions(); + assumptions.assumePairs(typeVariables, other.typeVariables); + try { for (int index = 0; index < typeVariables.length; index++) { if (!typeVariables[index] .bound @@ -588,30 +596,28 @@ class FunctionType extends DartType { return false; } } + return returnType._equals(other.returnType, assumptions) && + _equalTypes(parameterTypes, other.parameterTypes, assumptions) && + _equalTypes(optionalParameterTypes, other.optionalParameterTypes, + assumptions) && + equalElements(namedParameters, other.namedParameters) && + _equalTypes( + namedParameterTypes, other.namedParameterTypes, assumptions); + } finally { + assumptions.forgetPairs(typeVariables, other.typeVariables); } - bool result = returnType._equals(other.returnType, assumptions) && - _equalTypes(parameterTypes, other.parameterTypes, assumptions) && - _equalTypes(optionalParameterTypes, other.optionalParameterTypes, - assumptions) && - equalElements(namedParameters, other.namedParameters) && - _equalTypes( - namedParameterTypes, other.namedParameterTypes, assumptions); - if (typeVariables.isNotEmpty) { - for (int index = 0; index < typeVariables.length; index++) { - assumptions.forget(typeVariables[index], other.typeVariables[index]); - } - } - return result; } } class FutureOrType extends DartType { final DartType typeArgument; - FutureOrType(this.typeArgument); + const FutureOrType(this.typeArgument, Nullability nullability) + : super(nullability); @override - bool _isTop(bool isLegacy) => typeArgument._isTop(isLegacy); + DartType _withNullability(Nullability nullability) => + FutureOrType(typeArgument, nullability); @override bool get containsTypeVariables => typeArgument.containsTypeVariables; @@ -626,7 +632,7 @@ class FutureOrType extends DartType { visitor.visitFutureOrType(this, argument); @override - int get hashCode => typeArgument.hashCode * 13; + int get hashCode => typeArgument.hashCode * 13 + nullability.hashCode; @override bool operator ==(other) { @@ -643,7 +649,8 @@ class FutureOrType extends DartType { } bool _equalsInternal(FutureOrType other, _Assumptions assumptions) { - return typeArgument._equals(other.typeArgument, assumptions); + return nullability == other.nullability && + typeArgument._equals(other.typeArgument, assumptions); } } @@ -662,10 +669,6 @@ abstract class DartTypeVisitor { R visit(covariant DartType type, A argument) => type.accept(this, argument); - R visitLegacyType(covariant LegacyType type, A argument) => null; - - R visitNullableType(covariant NullableType type, A argument) => null; - R visitNeverType(covariant NeverType type, A argument) => null; R visitVoidType(covariant VoidType type, A argument) => null; @@ -694,14 +697,6 @@ abstract class BaseDartTypeVisitor extends DartTypeVisitor { R visitType(covariant DartType type, A argument); - @override - R visitLegacyType(covariant LegacyType type, A argument) => - visitType(type, argument); - - @override - R visitNullableType(covariant NullableType type, A argument) => - visitType(type, argument); - @override R visitNeverType(covariant NeverType type, A argument) => visitType(type, argument); @@ -772,32 +767,6 @@ abstract class DartTypeSubstitutionVisitor FunctionTypeVariable type, A argument, bool freshReference) => type; - @override - DartType visitLegacyType(covariant LegacyType type, A argument) { - DartType probe = _map[type]; - if (probe != null) return probe; - - DartType newBaseType = visit(type.baseType, argument); - // Create a new type only if necessary. - if (identical(type.baseType, newBaseType)) { - return _mapped(type, type); - } - return _mapped(type, LegacyType(newBaseType)); - } - - @override - DartType visitNullableType(covariant NullableType type, A argument) { - DartType probe = _map[type]; - if (probe != null) return probe; - - DartType newBaseType = visit(type.baseType, argument); - // Create a new type only if necessary. - if (identical(type.baseType, newBaseType)) { - return _mapped(type, type); - } - return _mapped(type, NullableType(newBaseType)); - } - @override DartType visitNeverType(covariant NeverType type, A argument) => type; @@ -852,7 +821,8 @@ abstract class DartTypeSubstitutionVisitor newOptionalParameterTypes, type.namedParameters, newNamedParameterTypes, - newTypeVariables)); + newTypeVariables, + type.nullability)); } List _handleFunctionTypeVariables( @@ -901,7 +871,7 @@ abstract class DartTypeSubstitutionVisitor undecided[i] = null; newVariables ??= variables.toList(); FunctionTypeVariable newVariable = - FunctionTypeVariable(variable.index); + FunctionTypeVariable(variable.index, variable.nullability); newVariables[i] = newVariable; _mapped(variable, newVariable); } @@ -935,7 +905,8 @@ abstract class DartTypeSubstitutionVisitor if (identical(typeArguments, newTypeArguments)) { return _mapped(type, type); } - return _mapped(type, InterfaceType(type.element, newTypeArguments)); + return _mapped( + type, InterfaceType(type.element, newTypeArguments, type.nullability)); } @override @@ -957,7 +928,7 @@ abstract class DartTypeSubstitutionVisitor if (identical(type.typeArgument, newTypeArgument)) { return _mapped(type, type); } - return _mapped(type, FutureOrType(newTypeArgument)); + return _mapped(type, FutureOrType(newTypeArgument, type.nullability)); } List _substTypes(List types, A argument) { @@ -1008,8 +979,6 @@ abstract class DartTypeStructuralPredicateVisitor bool run(DartType type) => visit(type, null); - bool handleLegacyType(LegacyType type) => false; - bool handleNullableType(NullableType type) => false; bool handleNeverType(NeverType type) => false; bool handleVoidType(VoidType type) => false; bool handleTypeVariableType(TypeVariableType type) => false; @@ -1022,15 +991,6 @@ abstract class DartTypeStructuralPredicateVisitor bool handleAnyType(AnyType type) => false; bool handleFutureOrType(FutureOrType type) => false; - @override - bool visitLegacyType(LegacyType type, List bindings) => - handleLegacyType(type) || visit(type.baseType, bindings); - - @override - bool visitNullableType( - NullableType type, List bindings) => - handleNullableType(type) || visit(type.baseType, bindings); - @override bool visitNeverType(NeverType type, List bindings) => false; @@ -1218,21 +1178,19 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { type.accept(this, null); } - @override - void visitLegacyType(covariant LegacyType type, _) { - _visit(type.baseType); - _token('*'); - } - - @override - void visitNullableType(covariant NullableType type, _) { - _visit(type.baseType); - _token('?'); + void _handleNullability(Nullability nullability) { + // We do not emit the '*' token for legacy types because this is a purely + // internal notion. The language specification does not define a '*' token + // in the type language, and no such token should be surfaced to users. + if (nullability.isQuestion) { + _token('?'); + } } @override void visitNeverType(covariant NeverType type, _) { _identifier('Never'); + _handleNullability(type.nullability); } @override @@ -1260,6 +1218,7 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { _identifier(type.element.typeDeclaration.name); _token('.'); _identifier(type.element.name); + _handleNullability(type.nullability); } _DeferredName _nameFor(FunctionTypeVariable type) { @@ -1277,6 +1236,7 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { if (_boundVariables == null || !_boundVariables.contains(type)) { _token('/*free*/'); } + _handleNullability(type.nullability); } @override @@ -1344,6 +1304,7 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { _token('}'); } _token(')'); + _handleNullability(type.nullability); // Exit function type variable scope. _boundVariables?.length -= type.typeVariables.length; } @@ -1352,6 +1313,7 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { void visitInterfaceType(covariant InterfaceType type, _) { _identifier(type.element.name); _optionalTypeArguments(type.typeArguments); + _handleNullability(type.nullability); } void _optionalTypeArguments(List types) { @@ -1372,6 +1334,7 @@ class _DartTypeToStringVisitor extends DartTypeVisitor { _token('<'); _visit(type.typeArgument); _token('>'); + _handleNullability(type.nullability); } } @@ -1380,15 +1343,22 @@ abstract class DartTypes { /// The types defined in 'dart:core'. CommonElements get commonElements; + bool get useNullSafety; bool get useLegacySubtyping; + // TODO(fishythefish): Clean up all uses of [defaultNullability]. + Nullability get defaultNullability => + useNullSafety ? Nullability.star : Nullability.none; + /// Returns `true` if every type argument of [t] is a top type. // TODO(fishythefish): Should we instead check if each type argument is at its // bound? - bool treatAsRawType(DartType t) => t._treatAsRaw(useLegacySubtyping); + bool treatAsRawType(DartType t) => t._treatAsRaw(useNullSafety); /// Returns `true` if [t] is a top type, that is, a supertype of every type. - bool isTopType(DartType t) => t._isTop(useLegacySubtyping); + bool isTopType(DartType t) => t._isTop(useNullSafety); + + bool _isStrongTopType(DartType t) => t._isStrongTop(useNullSafety); /// Returns `true` if [s] is a subtype of [t]. bool isSubtype(DartType s, DartType t) => _subtypeHelper(s, t); @@ -1413,27 +1383,32 @@ abstract class DartTypes { /// Based on /// https://github.com/dart-lang/language/blob/master/resources/type-system/subtyping.md. /// See also [_isSubtype] in `dart:_rti`. - bool _isSubtype(DartType s, Set sEnv, DartType t, - Set tEnv) { + bool _isSubtype(DartType s, DartType t, _Assumptions env) { // Reflexivity: if (s == t) return true; - if (s is FunctionTypeVariable && + if (env != null && + s is FunctionTypeVariable && t is FunctionTypeVariable && - sEnv.contains(s) && - tEnv.contains(t) && - s.index == t.index) return true; + s.nullability == t.nullability && + env.isAssumed(s, t)) return true; + + if (s is AnyType) return true; + if (allowPotentialSubtypes) { + if (t is TypeVariableType) return true; + if (s is TypeVariableType && s.nullability.isPotentiallyNonNull) + return true; + } + if (assumeInstantiations) { + if (t is FunctionTypeVariable) return true; + if (s is FunctionTypeVariable && s.nullability.isPotentiallyNonNull) + return true; + } // Right Top: if (isTopType(t)) return true; - if (s is AnyType) return true; - if (allowPotentialSubtypes && - (s is TypeVariableType || t is TypeVariableType)) return true; - if (assumeInstantiations && - (s is FunctionTypeVariable || t is FunctionTypeVariable)) return true; - // Left Top: - if (isTopType(s)) return false; + if (_isStrongTopType(s)) return false; // Left Bottom: if (useLegacySubtyping) { @@ -1443,58 +1418,60 @@ abstract class DartTypes { } // Left Type Variable Bound 1: - if (s is TypeVariableType) { - if (_isSubtype(getTypeVariableBound(s.element), sEnv, t, tEnv)) - return true; + if (s is TypeVariableType && s.nullability.isPotentiallyNonNull) { + if (_isSubtype(getTypeVariableBound(s.element), t, env)) return true; } - if (s is FunctionTypeVariable) { - if (_isSubtype(s._bound, sEnv, t, tEnv)) return true; + if (s is FunctionTypeVariable && s.nullability.isPotentiallyNonNull) { + if (_isSubtype(s._bound, t, env)) return true; } // Left Null: // Note: Interchanging the Left Null and Right Object rules allows us to // reduce casework. if (!useLegacySubtyping && s.isNull) { + if (t.nullability.isPotentiallyNull) return true; if (t is FutureOrType) { - return _isSubtype(s, sEnv, t.typeArgument, tEnv); + return _isSubtype(s, t.typeArgument, env); } - return t.isNull || t is NullableType || t is LegacyType; + return t.isNull; } // Right Object: - if (!useLegacySubtyping && t.isObject) { - if (s is FutureOrType) { - return _isSubtype(s.typeArgument, sEnv, t, tEnv); + if (!useLegacySubtyping && t.isObject && t.nullability.isNone) { + if (s is FutureOrType && s.nullability.isNone) { + return _isSubtype(s.typeArgument, t, env); } - if (s is LegacyType) { - return _isSubtype(s.baseType, sEnv, t, tEnv); + if (s.nullability.isStar) { + return _isSubtype(s._withoutNullability(), t, env); } - return s is! NullableType; + return !s.nullability.isQuestion; } // Left Legacy: - if (s is LegacyType) { - return _isSubtype(s.baseType, sEnv, t, tEnv); + if (s.nullability.isStar) { + return _isSubtype(s._withoutNullability(), t, env); } // Right Legacy: - if (t is LegacyType) { - return _isSubtype(s, sEnv, - useLegacySubtyping ? t.baseType : NullableType(t.baseType), tEnv); + if (t.nullability.isStar) { + return _isSubtype( + s, + useLegacySubtyping ? t._withoutNullability() : t._withQuestion(), + env); } // Left FutureOr: - if (s is FutureOrType) { + if (s is FutureOrType && s.nullability.isNone) { DartType typeArgument = s.typeArgument; - return _isSubtype(typeArgument, sEnv, t, tEnv) && - _isSubtype(commonElements.futureType(typeArgument), sEnv, t, tEnv); + return _isSubtype(typeArgument, t, env) && + _isSubtype(commonElements.futureType(typeArgument), t, env); } // Left Nullable: - if (s is NullableType) { + if (s.nullability.isQuestion) { return (useLegacySubtyping || - _isSubtype(commonElements.nullType, sEnv, t, tEnv)) && - _isSubtype(s.baseType, sEnv, t, tEnv); + _isSubtype(commonElements.nullType, t, env)) && + _isSubtype(s._withoutNullability(), t, env); } // Type Variable Reflexivity 1 is subsumed by Reflexivity and therefore @@ -1505,17 +1482,17 @@ abstract class DartTypes { // promoted type variables. // Right FutureOr: - if (t is FutureOrType) { + if (t is FutureOrType && t.nullability.isNone) { DartType typeArgument = t.typeArgument; - return _isSubtype(s, sEnv, typeArgument, tEnv) || - _isSubtype(s, sEnv, commonElements.futureType(typeArgument), tEnv); + return _isSubtype(s, typeArgument, env) || + _isSubtype(s, commonElements.futureType(typeArgument), env); } // Right Nullable: - if (t is NullableType) { + if (t.nullability.isQuestion) { return (!useLegacySubtyping && - _isSubtype(s, sEnv, commonElements.nullType, tEnv)) || - _isSubtype(s, sEnv, t.baseType, tEnv); + _isSubtype(s, commonElements.nullType, env)) || + _isSubtype(s, t._withoutNullability(), env); } // Left Promoted Variable does not apply because we do not represent @@ -1536,89 +1513,93 @@ abstract class DartTypes { if (t is FunctionType) { if (s == commonElements.jsJavaScriptFunctionType) return true; if (s is FunctionType) { - if (t.isGeneric) { - if (!s.isGeneric) return false; - List sBounds = s.typeVariableBounds; - List tBounds = t.typeVariableBounds; - int length = sBounds.length; - if (length != tBounds.length) { - return false; - } + List sTypeVariables = s.typeVariables; + List tTypeVariables = t.typeVariables; + int length = tTypeVariables.length; + if (length == sTypeVariables.length) { + env ??= _Assumptions(); + env.assumePairs(sTypeVariables, tTypeVariables); + } else if (!assumeInstantiations || length > 0) return false; + try { for (int i = 0; i < length; i++) { - if (!_isSubtype(sBounds[i], sEnv, tBounds[i], tEnv) || - !_isSubtype(tBounds[i], tEnv, sBounds[i], sEnv)) { + DartType sBound = sTypeVariables[i].bound; + DartType tBound = tTypeVariables[i].bound; + if (!_isSubtype(sBound, tBound, env) || + !_isSubtype(tBound, sBound, env)) { return false; } } - sEnv = sEnv.toSet()..addAll(s.typeVariables); - tEnv = tEnv.toSet()..addAll(t.typeVariables); - } - if (!_isSubtype(s.returnType, sEnv, t.returnType, tEnv)) return false; + if (!_isSubtype(s.returnType, t.returnType, env)) return false; - // TODO(fishythefish): Support required named parameters. + // TODO(fishythefish): Support required named parameters. - List sRequiredPositional = s.parameterTypes; - List tRequiredPositional = t.parameterTypes; - int sRequiredPositionalLength = sRequiredPositional.length; - int tRequiredPositionalLength = tRequiredPositional.length; - if (sRequiredPositionalLength > tRequiredPositionalLength) { - return false; - } - int requiredPositionalDelta = - tRequiredPositionalLength - sRequiredPositionalLength; - - List sOptionalPositional = s.optionalParameterTypes; - List tOptionalPositional = t.optionalParameterTypes; - int sOptionalPositionalLength = sOptionalPositional.length; - int tOptionalPositionalLength = tOptionalPositional.length; - if (sRequiredPositionalLength + sOptionalPositionalLength < - tRequiredPositionalLength + tOptionalPositionalLength) { - return false; - } - - for (int i = 0; i < sRequiredPositionalLength; i++) { - if (!_isSubtype( - tRequiredPositional[i], tEnv, sRequiredPositional[i], sEnv)) { + List sRequiredPositional = s.parameterTypes; + List tRequiredPositional = t.parameterTypes; + int sRequiredPositionalLength = sRequiredPositional.length; + int tRequiredPositionalLength = tRequiredPositional.length; + if (sRequiredPositionalLength > tRequiredPositionalLength) { return false; } - } + int requiredPositionalDelta = + tRequiredPositionalLength - sRequiredPositionalLength; - for (int i = 0; i < requiredPositionalDelta; i++) { - if (!_isSubtype(tRequiredPositional[sRequiredPositionalLength + i], - tEnv, sOptionalPositional[i], sEnv)) { + List sOptionalPositional = s.optionalParameterTypes; + List tOptionalPositional = t.optionalParameterTypes; + int sOptionalPositionalLength = sOptionalPositional.length; + int tOptionalPositionalLength = tOptionalPositional.length; + if (sRequiredPositionalLength + sOptionalPositionalLength < + tRequiredPositionalLength + tOptionalPositionalLength) { return false; } - } - for (int i = 0; i < tOptionalPositionalLength; i++) { - if (!_isSubtype(tOptionalPositional[i], tEnv, - sOptionalPositional[requiredPositionalDelta + i], sEnv)) { - return false; + for (int i = 0; i < sRequiredPositionalLength; i++) { + if (!_isSubtype( + tRequiredPositional[i], sRequiredPositional[i], env)) { + return false; + } } - } - List sOptionalNamed = s.namedParameters; - List tOptionalNamed = t.namedParameters; - List sOptionalNamedTypes = s.namedParameterTypes; - List tOptionalNamedTypes = t.namedParameterTypes; - int sOptionalNamedLength = sOptionalNamed.length; - int tOptionalNamedLength = tOptionalNamed.length; - for (int i = 0, j = 0; j < tOptionalNamedLength; j++) { - String sName; - String tName = tOptionalNamed[j]; - int comparison; - do { - if (i >= sOptionalNamedLength) return false; - sName = sOptionalNamed[i++]; - comparison = sName.compareTo(tName); - } while (comparison < 0); - if (comparison > 0) return false; - if (!_isSubtype( - tOptionalNamedTypes[j], tEnv, sOptionalNamedTypes[i - 1], sEnv)) - return false; + for (int i = 0; i < requiredPositionalDelta; i++) { + if (!_isSubtype( + tRequiredPositional[sRequiredPositionalLength + i], + sOptionalPositional[i], + env)) { + return false; + } + } + + for (int i = 0; i < tOptionalPositionalLength; i++) { + if (!_isSubtype(tOptionalPositional[i], + sOptionalPositional[requiredPositionalDelta + i], env)) { + return false; + } + } + + List sOptionalNamed = s.namedParameters; + List tOptionalNamed = t.namedParameters; + List sOptionalNamedTypes = s.namedParameterTypes; + List tOptionalNamedTypes = t.namedParameterTypes; + int sOptionalNamedLength = sOptionalNamed.length; + int tOptionalNamedLength = tOptionalNamed.length; + for (int i = 0, j = 0; j < tOptionalNamedLength; j++) { + String sName; + String tName = tOptionalNamed[j]; + int comparison; + do { + if (i >= sOptionalNamedLength) return false; + sName = sOptionalNamed[i++]; + comparison = sName.compareTo(tName); + } while (comparison < 0); + if (comparison > 0) return false; + if (!_isSubtype( + tOptionalNamedTypes[j], sOptionalNamedTypes[i - 1], env)) + return false; + } + return true; + } finally { + if (length > 0) env.forgetPairs(sTypeVariables, tTypeVariables); } - return true; } return false; } @@ -1638,14 +1619,14 @@ abstract class DartTypes { switch (variances[i]) { case Variance.legacyCovariant: case Variance.covariant: - if (!_isSubtype(sArgs[i], sEnv, tArgs[i], tEnv)) return false; + if (!_isSubtype(sArgs[i], tArgs[i], env)) return false; break; case Variance.contravariant: - if (!_isSubtype(tArgs[i], tEnv, sArgs[i], sEnv)) return false; + if (!_isSubtype(tArgs[i], sArgs[i], env)) return false; break; case Variance.invariant: - if (!_isSubtype(sArgs[i], sEnv, tArgs[i], tEnv) || - !_isSubtype(tArgs[i], tEnv, sArgs[i], sEnv)) return false; + if (!_isSubtype(sArgs[i], tArgs[i], env) || + !_isSubtype(tArgs[i], sArgs[i], env)) return false; break; default: throw StateError( @@ -1660,7 +1641,7 @@ abstract class DartTypes { return false; } - return _isSubtype(s, {}, t, {}); + return _isSubtype(s, t, null); } /// Returns [type] as an instance of [cls] or `null` if [type] is not a diff --git a/pkg/compiler/lib/src/ir/types.dart b/pkg/compiler/lib/src/ir/types.dart index f2b01cbb2a8..02a61c92d0f 100644 --- a/pkg/compiler/lib/src/ir/types.dart +++ b/pkg/compiler/lib/src/ir/types.dart @@ -5,6 +5,7 @@ import '../common_elements.dart'; import '../elements/entities.dart'; import '../elements/types.dart'; +import '../options.dart'; import '../ordered_typeset.dart'; import 'element_map.dart'; @@ -12,9 +13,13 @@ import 'element_map.dart'; class KernelDartTypes extends DartTypes { final IrToElementMap elementMap; @override + final bool useNullSafety; + @override final bool useLegacySubtyping; - KernelDartTypes(this.elementMap, this.useLegacySubtyping); + KernelDartTypes(this.elementMap, CompilerOptions options) + : useNullSafety = options.useNullSafety, + useLegacySubtyping = options.useLegacySubtyping; @override InterfaceType getThisType(ClassEntity cls) { diff --git a/pkg/compiler/lib/src/ir/visitors.dart b/pkg/compiler/lib/src/ir/visitors.dart index 9ab1eb43e8b..42ab535fb8f 100644 --- a/pkg/compiler/lib/src/ir/visitors.dart +++ b/pkg/compiler/lib/src/ir/visitors.dart @@ -50,6 +50,8 @@ class DartTypeConverter extends ir.DartTypeVisitor { DartTypeConverter(this.elementMap); + DartTypes get _dartTypes => elementMap.commonElements.dartTypes; + DartType convert(ir.DartType type) { topLevel = true; return type.accept(this); @@ -63,7 +65,8 @@ class DartTypeConverter extends ir.DartTypeVisitor { InterfaceType visitSupertype(ir.Supertype node) { ClassEntity cls = elementMap.getClass(node.classNode); - return new InterfaceType(cls, visitTypes(node.typeArguments)); + return new InterfaceType( + cls, visitTypes(node.typeArguments), _dartTypes.defaultNullability); } List visitTypes(List types) { @@ -83,7 +86,8 @@ class DartTypeConverter extends ir.DartTypeVisitor { // variables. return DynamicType(); } - return new TypeVariableType(elementMap.getTypeVariable(node.parameter)); + return new TypeVariableType(elementMap.getTypeVariable(node.parameter), + _dartTypes.defaultNullability); } @override @@ -91,7 +95,8 @@ class DartTypeConverter extends ir.DartTypeVisitor { int index = 0; List typeVariables; for (ir.TypeParameter typeParameter in node.typeParameters) { - FunctionTypeVariable typeVariable = new FunctionTypeVariable(index); + FunctionTypeVariable typeVariable = + new FunctionTypeVariable(index, _dartTypes.defaultNullability); currentFunctionTypeParameters[typeParameter] = typeVariable; typeVariables ??= []; typeVariables.add(typeVariable); @@ -114,7 +119,8 @@ class DartTypeConverter extends ir.DartTypeVisitor { .toList()), node.namedParameters.map((n) => n.name).toList(), node.namedParameters.map((n) => visitType(n.type)).toList(), - typeVariables ?? const []); + typeVariables ?? const [], + _dartTypes.defaultNullability); for (ir.TypeParameter typeParameter in node.typeParameters) { currentFunctionTypeParameters.remove(typeParameter); } @@ -126,9 +132,11 @@ class DartTypeConverter extends ir.DartTypeVisitor { ClassEntity cls = elementMap.getClass(node.classNode); if (cls.name == 'FutureOr' && cls.library == elementMap.commonElements.asyncLibrary) { - return new FutureOrType(visitTypes(node.typeArguments).single); + return new FutureOrType( + visitTypes(node.typeArguments).single, _dartTypes.defaultNullability); } - return new InterfaceType(cls, visitTypes(node.typeArguments)); + return new InterfaceType( + cls, visitTypes(node.typeArguments), _dartTypes.defaultNullability); } @override diff --git a/pkg/compiler/lib/src/js_backend/constant_emitter.dart b/pkg/compiler/lib/src/js_backend/constant_emitter.dart index 7833ded35e0..776e6985da7 100644 --- a/pkg/compiler/lib/src/js_backend/constant_emitter.dart +++ b/pkg/compiler/lib/src/js_backend/constant_emitter.dart @@ -447,8 +447,8 @@ class ConstantEmitter extends ModularConstantEmitter { _constantReferenceGenerator(constant.function) ]; if (_options.useNewRti) { - fields - .add(_reifiedTypeNewRti(InterfaceType(cls, constant.typeArguments))); + fields.add(_reifiedTypeNewRti(InterfaceType(cls, constant.typeArguments, + _commonElements.dartTypes.defaultNullability))); } else { fields.add(_reifiedTypeArguments(constant, constant.typeArguments)); } diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart index 435d29ec3f1..72b43793582 100644 --- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart +++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart @@ -40,7 +40,7 @@ jsAst.Statement buildJsInteropBootstrap( return new jsAst.Block(statements); } -FunctionType buildJsFunctionType() { +FunctionType buildJsFunctionType(DartTypes dartTypes) { // TODO(jacobr): consider using codegenWorldBuilder.isChecks to determine the // range of positional arguments that need to be supported by JavaScript // function types. @@ -50,5 +50,6 @@ FunctionType buildJsFunctionType() { new List.filled(16, DynamicType()), const [], const [], - const []); + const [], + dartTypes.defaultNullability); } diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart index f0f376a11c2..b45c907872b 100644 --- a/pkg/compiler/lib/src/js_backend/runtime_types.dart +++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart @@ -1004,17 +1004,6 @@ class TypeRepresentationGenerator return onVariable(type); } - @override - jsAst.Expression visitLegacyType(LegacyType type, ModularEmitter emitter) { - throw UnsupportedError('Legacy RTI does not support legacy types'); - } - - @override - jsAst.Expression visitNullableType( - NullableType type, ModularEmitter emitter) { - throw UnsupportedError('Legacy RTI does not support nullable types'); - } - @override jsAst.Expression visitNeverType(NeverType type, ModularEmitter emitter) { throw UnsupportedError('Legacy RTI does not support the Never type'); @@ -1248,16 +1237,6 @@ class ArgumentCollector extends DartTypeVisitor { /// InterfaceType. void collectAll(List types) => types.forEach(collect); - @override - void visitLegacyType(LegacyType type, _) { - collect(type.baseType); - } - - @override - void visitNullableType(NullableType type, _) { - collect(type.baseType); - } - @override void visitFutureOrType(FutureOrType type, _) { collect(type.typeArgument); @@ -1334,14 +1313,6 @@ class TypeVisitor extends DartTypeVisitor { } } - @override - void visitLegacyType(LegacyType type, TypeVisitorState state) => - visitType(type.baseType, state); - - @override - void visitNullableType(NullableType type, TypeVisitorState state) => - visitType(type.baseType, state); - @override void visitFutureOrType(FutureOrType type, TypeVisitorState state) => visitType(type.typeArgument, state); diff --git a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart index 2aa30b4486a..acd4992fd03 100644 --- a/pkg/compiler/lib/src/js_backend/runtime_types_new.dart +++ b/pkg/compiler/lib/src/js_backend/runtime_types_new.dart @@ -222,32 +222,35 @@ class _RecipeGenerator implements DartTypeVisitor { _emitCode(Recipe.extensionOp); } + void _emitNullability(Nullability nullability) { + switch (nullability) { + case Nullability.none: + return; + case Nullability.question: + _emitCode(Recipe.wrapQuestion); + return; + case Nullability.star: + _emitCode(Recipe.wrapStar); + return; + } + } + @override void visit(DartType type, _) => type.accept(this, _); - @override - void visitLegacyType(LegacyType type, _) { - visit(type.baseType, _); - _emitCode(Recipe.wrapStar); - } - - @override - void visitNullableType(NullableType type, _) { - visit(type.baseType, _); - _emitCode(Recipe.wrapQuestion); - } - @override void visitNeverType(NeverType type, _) { _emitExtensionOp(Recipe.pushNeverExtension); + _emitNullability(type.nullability); } @override void visitTypeVariableType(TypeVariableType type, _) { TypeEnvironmentStructure environment = _environment; if (environment is SingletonTypeEnvironmentStructure) { - if (type == environment.variable) { + if (type.element == environment.variable.element) { _emitInteger(0); + _emitNullability(type.nullability); return; } } @@ -257,11 +260,13 @@ class _RecipeGenerator implements DartTypeVisitor { metadata: metadata); if (index != null) { _emitInteger(index); + _emitNullability(type.nullability); return; } jsAst.Name name = _emitter.typeVariableAccessNewRti(type.element); _emitName(name); + _emitNullability(type.nullability); typeVariables.add(type); return; } @@ -277,6 +282,7 @@ class _RecipeGenerator implements DartTypeVisitor { // See [visitFunctionType] for explanation. _emitInteger(functionTypeVariables.length - position - 1); _emitCode(Recipe.genericFunctionTypeParameterIndex); + _emitNullability(type.nullability); } @override @@ -301,6 +307,7 @@ class _RecipeGenerator implements DartTypeVisitor { // Push the name, which is later converted by an implicit toType // operation. _emitName(name); + _emitNullability(type.nullability); } else { _emitName(name); _emitCode(Recipe.startTypeArguments); @@ -318,6 +325,7 @@ class _RecipeGenerator implements DartTypeVisitor { first = false; } _emitCode(Recipe.endTypeArguments); + _emitNullability(type.nullability); } } @@ -412,6 +420,8 @@ class _RecipeGenerator implements DartTypeVisitor { // Exit generic function scope. Remove the type variables pushed at entry. functionTypeVariables.length -= type.typeVariables.length; } + + _emitNullability(type.nullability); } @override @@ -423,6 +433,7 @@ class _RecipeGenerator implements DartTypeVisitor { void visitFutureOrType(FutureOrType type, _) { visit(type.typeArgument, _); _emitCode(Recipe.wrapFutureOr); + _emitNullability(type.nullability); } } diff --git a/pkg/compiler/lib/src/js_backend/type_reference.dart b/pkg/compiler/lib/src/js_backend/type_reference.dart index 9e99b0b5188..68887ad3930 100644 --- a/pkg/compiler/lib/src/js_backend/type_reference.dart +++ b/pkg/compiler/lib/src/js_backend/type_reference.dart @@ -615,24 +615,26 @@ class _RecipeToIdentifier extends DartTypeVisitor { return true; } + void _handleNullability(Nullability nullability) { + switch (nullability) { + case Nullability.none: + return; + case Nullability.star: + _add('legacy'); + return; + case Nullability.question: + _add('nullable'); + return; + } + } + void _visit(DartType type, DartType parent) { type.accept(this, parent); } - @override - void visitLegacyType(covariant LegacyType type, _) { - _add('legacy'); - _visit(type.baseType, type); - } - - @override - void visitNullableType(covariant NullableType type, _) { - _add('nullable'); - _visit(type.baseType, type); - } - @override void visitNeverType(covariant NeverType type, _) { + _handleNullability(type.nullability); _add('Never'); } @@ -646,6 +648,11 @@ class _RecipeToIdentifier extends DartTypeVisitor { _add('dynamic'); } + @override + void visitErasedType(covariant ErasedType type, _) { + _add('erased'); + } + @override void visitAnyType(covariant AnyType type, _) { _add('any'); @@ -653,6 +660,7 @@ class _RecipeToIdentifier extends DartTypeVisitor { @override void visitTypeVariableType(covariant TypeVariableType type, DartType parent) { + _handleNullability(type.nullability); if (parent != type.element.typeDeclaration) { _identifier(type.element.typeDeclaration.name); } @@ -661,6 +669,7 @@ class _RecipeToIdentifier extends DartTypeVisitor { @override void visitFunctionTypeVariable(covariant FunctionTypeVariable type, _) { + _handleNullability(type.nullability); int index = type.index; String name = index < 26 ? String.fromCharCode($A + index) : 'v\$${index}'; _add(name); @@ -671,6 +680,7 @@ class _RecipeToIdentifier extends DartTypeVisitor { if (_dagCheck(type)) return; _visit(type.returnType, type); + _handleNullability(type.nullability); _add('Function'); var typeVariables = type.typeVariables; if (typeVariables.isNotEmpty) { @@ -734,6 +744,7 @@ class _RecipeToIdentifier extends DartTypeVisitor { // types which 'print' as a single identifier. if (arguments.isNotEmpty && _dagCheck(type)) return; + _handleNullability(type.nullability); _identifier(type.element.name); if (arguments.isEmpty) return; @@ -782,6 +793,7 @@ class _RecipeToIdentifier extends DartTypeVisitor { @override void visitFutureOrType(covariant FutureOrType type, _) { + _handleNullability(type.nullability); _identifier('FutureOr'); _visit(type.typeArgument, type); } diff --git a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart index 4c5afba958d..5f6068d8fb4 100644 --- a/pkg/compiler/lib/src/js_emitter/constant_ordering.dart +++ b/pkg/compiler/lib/src/js_emitter/constant_ordering.dart @@ -218,11 +218,7 @@ class _DartTypeKindVisitor implements DartTypeVisitor { @override int visitErasedType(ErasedType type, _) => 8; @override - int visitLegacyType(LegacyType type, _) => 9; - @override - int visitNullableType(NullableType type, _) => 10; - @override - int visitFutureOrType(FutureOrType type, _) => 11; + int visitFutureOrType(FutureOrType type, _) => 9; } class _DartTypeOrdering extends DartTypeVisitor { @@ -243,19 +239,16 @@ class _DartTypeOrdering extends DartTypeVisitor { return r; } - @override - int visitLegacyType(covariant LegacyType type, covariant LegacyType other) => - compare(type.baseType, other.baseType); - - @override - int visitNullableType( - covariant NullableType type, covariant NullableType other) => - visit(type.baseType, other.baseType); + int _compareNullability(DartType a, DartType b) => + a.nullability.compareTo(b.nullability); @override int visitFutureOrType( - covariant FutureOrType type, covariant FutureOrType other) => - visit(type.typeArgument, other.typeArgument); + covariant FutureOrType type, covariant FutureOrType other) { + int r = _compareNullability(type, other); + if (r != 0) return r; + return visit(type.typeArgument, other.typeArgument); + } @override int visitNeverType(covariant NeverType type, covariant NeverType other) { @@ -277,11 +270,13 @@ class _DartTypeOrdering extends DartTypeVisitor { @override int visitFunctionTypeVariable(covariant FunctionTypeVariable type, covariant FunctionTypeVariable other) { + int r = _compareNullability(type, other); + if (r != 0) return r; int leftIndex = _leftFunctionTypeVariables.indexOf(type); int rightIndex = _rightFunctionTypeVariables.indexOf(other); assert(leftIndex != -1); assert(rightIndex != -1); - int r = leftIndex.compareTo(rightIndex); + r = leftIndex.compareTo(rightIndex); if (r != 0) return r; return compare(type.bound, other.bound); } @@ -289,37 +284,39 @@ class _DartTypeOrdering extends DartTypeVisitor { @override int visitFunctionType( covariant FunctionType type, covariant FunctionType other) { - int leftLength = _leftFunctionTypeVariables.length; - int rightLength = _rightFunctionTypeVariables.length; + int r = _compareNullability(type, other); + if (r != 0) return r; + int oldLeftLength = _leftFunctionTypeVariables.length; + int oldRightLength = _rightFunctionTypeVariables.length; _leftFunctionTypeVariables.addAll(type.typeVariables); _rightFunctionTypeVariables.addAll(other.typeVariables); - int r = _compareTypeArguments(type.parameterTypes, other.parameterTypes); - if (r == 0) { + try { + r = _compareTypeArguments(type.parameterTypes, other.parameterTypes); + if (r != 0) return r; r = _compareTypeArguments( type.optionalParameterTypes, other.optionalParameterTypes); - } - if (r == 0) { + if (r != 0) return r; r = _ConstantOrdering.compareLists((String a, String b) => a.compareTo(b), type.namedParameters, other.namedParameters); - } - if (r == 0) { + if (r != 0) return r; r = _compareTypeArguments( type.namedParameterTypes, other.namedParameterTypes); + if (r != 0) return r; + return compare(type.returnType, other.returnType); + } finally { + _leftFunctionTypeVariables.removeRange( + oldLeftLength, _leftFunctionTypeVariables.length); + _rightFunctionTypeVariables.removeRange( + oldRightLength, _rightFunctionTypeVariables.length); } - if (r == 0) { - r = compare(type.returnType, other.returnType); - } - _leftFunctionTypeVariables.removeRange( - leftLength, _leftFunctionTypeVariables.length); - _rightFunctionTypeVariables.removeRange( - rightLength, _rightFunctionTypeVariables.length); - return r; } @override int visitInterfaceType( covariant InterfaceType type, covariant InterfaceType other) { - int r = _constantOrdering.compareClasses(type.element, other.element); + int r = _compareNullability(type, other); + if (r != 0) return r; + r = _constantOrdering.compareClasses(type.element, other.element); if (r != 0) return r; return _compareTypeArguments(type.typeArguments, other.typeArguments); } diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart index 8ebbf99bed5..6075868e4dd 100644 --- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart +++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart @@ -196,7 +196,8 @@ class RuntimeTypeGenerator { classElement, generateFunctionTypeSignature, generateTypeCheck); if (classElement == _commonElements.jsJavaScriptFunctionClass) { - var type = jsInteropAnalysis.buildJsFunctionType(); + var type = + jsInteropAnalysis.buildJsFunctionType(_commonElements.dartTypes); if (type != null) { jsAst.Expression thisAccess = new jsAst.This(); jsAst.Expression encoding = _rtiEncoder.getSignatureEncoding( @@ -322,14 +323,6 @@ class _TypeContainedInOutputUnitVisitor return true; } - @override - bool visitLegacyType(LegacyType type, OutputUnit argument) => - visit(type.baseType, argument); - - @override - bool visitNullableType(NullableType type, OutputUnit argument) => - visit(type.baseType, argument); - @override bool visitNeverType(NeverType type, OutputUnit argument) => true; diff --git a/pkg/compiler/lib/src/js_model/element_map_impl.dart b/pkg/compiler/lib/src/js_model/element_map_impl.dart index 2ce9eadc9bb..3b47b4c4630 100644 --- a/pkg/compiler/lib/src/js_model/element_map_impl.dart +++ b/pkg/compiler/lib/src/js_model/element_map_impl.dart @@ -137,7 +137,7 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { : this.options = _elementMap.options { _elementEnvironment = new JsElementEnvironment(this); _typeConverter = new DartTypeConverter(this); - _types = new KernelDartTypes(this, options.useLegacySubtyping); + _types = new KernelDartTypes(this, options); _commonElements = new CommonElementsImpl( _types, _elementEnvironment, _elementMap.options); _constantValuefier = new ConstantValuefier(this); @@ -298,7 +298,7 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { this._environment, ir.Component component, DataSource source) { _elementEnvironment = new JsElementEnvironment(this); _typeConverter = new DartTypeConverter(this); - _types = new KernelDartTypes(this, options.useLegacySubtyping); + _types = new KernelDartTypes(this, options); _commonElements = new CommonElementsImpl(_types, _elementEnvironment, options); _constantValuefier = new ConstantValuefier(this); @@ -619,7 +619,8 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { @override InterfaceType createInterfaceType( ir.Class cls, List typeArguments) { - return new InterfaceType(getClass(cls), getDartTypes(typeArguments)); + return new InterfaceType( + getClass(cls), getDartTypes(typeArguments), types.defaultNullability); } @override @@ -641,20 +642,23 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { if (data is JClassDataImpl && data.thisType == null) { ir.Class node = data.cls; if (node.typeParameters.isEmpty) { - data.thisType = - data.rawType = new InterfaceType(cls, const []); + data.thisType = data.rawType = new InterfaceType( + cls, const [], types.defaultNullability); } else { data.thisType = new InterfaceType( cls, new List.generate(node.typeParameters.length, (int index) { return new TypeVariableType( - getTypeVariableInternal(node.typeParameters[index])); - })); + getTypeVariableInternal(node.typeParameters[index]), + types.defaultNullability); + }), + types.defaultNullability); data.rawType = new InterfaceType( cls, new List.filled( - node.typeParameters.length, DynamicType())); + node.typeParameters.length, DynamicType()), + types.defaultNullability); } } } @@ -668,7 +672,9 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { data.jsInteropType = data.thisType; } else { data.jsInteropType = InterfaceType( - cls, List.filled(node.typeParameters.length, AnyType())); + cls, + List.filled(node.typeParameters.length, AnyType()), + types.defaultNullability); } } } @@ -901,7 +907,8 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { } typeVariables = new List.generate( node.typeParameters.length, - (int index) => new FunctionTypeVariable(index)); + (int index) => + new FunctionTypeVariable(index, types.defaultNullability)); DartType subst(DartType type) { return type.subst(typeVariables, typeParameters); @@ -919,8 +926,14 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { typeVariables = const []; } - return new FunctionType(returnType, parameterTypes, optionalParameterTypes, - namedParameters, namedParameterTypes, typeVariables); + return new FunctionType( + returnType, + parameterTypes, + optionalParameterTypes, + namedParameters, + namedParameterTypes, + typeVariables, + types.defaultNullability); } @override @@ -1743,13 +1756,14 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { Map memberMap = {}; JRecord container = new JRecord(member.library, box.name); BoxLocal boxLocal = new BoxLocal(container); - InterfaceType thisType = new InterfaceType(container, const []); + InterfaceType thisType = new InterfaceType( + container, const [], types.defaultNullability); InterfaceType supertype = commonElements.objectType; JClassData containerData = new RecordClassData( new RecordContainerDefinition(getMemberDefinition(member).location), thisType, supertype, - getOrderedTypeSet(supertype.element).extendClass(_types, thisType)); + getOrderedTypeSet(supertype.element).extendClass(types, thisType)); classes.register(container, containerData, new RecordEnv(memberMap)); InterfaceType memberThisType = member.enclosingClass != null @@ -1806,12 +1820,13 @@ class JsKernelToElementMap implements JsToElementMap, IrToElementMap { JClass classEntity = new JClosureClass(enclosingLibrary, name); // Create a classData and set up the interfaces and subclass // relationships that _ensureSupertypes and _ensureThisAndRawType are doing - InterfaceType thisType = new InterfaceType(classEntity, const []); + InterfaceType thisType = new InterfaceType( + classEntity, const [], types.defaultNullability); ClosureClassData closureData = new ClosureClassData( new ClosureClassDefinition(location), thisType, supertype, - getOrderedTypeSet(supertype.element).extendClass(_types, thisType)); + getOrderedTypeSet(supertype.element).extendClass(types, thisType)); classes.register(classEntity, closureData, new ClosureClassEnv(memberMap)); Local closureEntity; @@ -2219,7 +2234,8 @@ class JsElementEnvironment extends ElementEnvironment @override InterfaceType createInterfaceType( ClassEntity cls, List typeArguments) { - return new InterfaceType(cls, typeArguments); + return new InterfaceType( + cls, typeArguments, elementMap.types.defaultNullability); } @override diff --git a/pkg/compiler/lib/src/js_model/js_world_builder.dart b/pkg/compiler/lib/src/js_model/js_world_builder.dart index 1ff938bc37f..f9b1672e6da 100644 --- a/pkg/compiler/lib/src/js_model/js_world_builder.dart +++ b/pkg/compiler/lib/src/js_model/js_world_builder.dart @@ -427,7 +427,8 @@ class JsClosedWorldBuilder { boxedVariables, info, localsMap, - new InterfaceType(superclass, const []), + new InterfaceType( + superclass, const [], _elementMap.types.defaultNullability), createSignatureMethod: createSignatureMethod); // Tell the hierarchy that this is the super class. then we can use @@ -756,17 +757,9 @@ class _TypeConverter implements DartTypeVisitor { return list; } - @override - DartType visitLegacyType(LegacyType type, _EntityConverter converter) => - LegacyType(visit(type.baseType, converter)); - - @override - DartType visitNullableType(NullableType type, _EntityConverter converter) => - NullableType(visit(type.baseType, converter)); - @override DartType visitNeverType(NeverType type, _EntityConverter converter) => - NeverType(); + NeverType(type.nullability); @override DartType visitDynamicType(DynamicType type, _EntityConverter converter) { @@ -782,14 +775,14 @@ class _TypeConverter implements DartTypeVisitor { @override DartType visitInterfaceType(InterfaceType type, _EntityConverter converter) { - return new InterfaceType( - converter(type.element), visitList(type.typeArguments, converter)); + return new InterfaceType(converter(type.element), + visitList(type.typeArguments, converter), type.nullability); } @override DartType visitTypeVariableType( TypeVariableType type, _EntityConverter converter) { - return new TypeVariableType(converter(type.element)); + return new TypeVariableType(converter(type.element), type.nullability); } @override @@ -797,7 +790,8 @@ class _TypeConverter implements DartTypeVisitor { List typeVariables = []; for (FunctionTypeVariable typeVariable in type.typeVariables) { typeVariables.add(_functionTypeVariables[typeVariable] = - new FunctionTypeVariable(typeVariable.index)); + new FunctionTypeVariable( + typeVariable.index, typeVariable.nullability)); } for (FunctionTypeVariable typeVariable in type.typeVariables) { _functionTypeVariables[typeVariable].bound = typeVariable.bound != null @@ -813,8 +807,14 @@ class _TypeConverter implements DartTypeVisitor { for (FunctionTypeVariable typeVariable in type.typeVariables) { _functionTypeVariables.remove(typeVariable); } - return new FunctionType(returnType, parameterTypes, optionalParameterTypes, - type.namedParameters, namedParameterTypes, typeVariables); + return new FunctionType( + returnType, + parameterTypes, + optionalParameterTypes, + type.namedParameters, + namedParameterTypes, + typeVariables, + type.nullability); } @override @@ -836,7 +836,8 @@ class _TypeConverter implements DartTypeVisitor { @override DartType visitFutureOrType(FutureOrType type, _EntityConverter converter) { - return new FutureOrType(visit(type.typeArgument, converter)); + return new FutureOrType( + visit(type.typeArgument, converter), type.nullability); } } diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart index cd66278cbc3..fdf289910a6 100644 --- a/pkg/compiler/lib/src/kernel/element_map_impl.dart +++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart @@ -117,7 +117,7 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { this.reporter, this._environment, this._frontendStrategy, this.options) { _elementEnvironment = new KernelElementEnvironment(this); _typeConverter = new DartTypeConverter(this); - _types = new KernelDartTypes(this, options.useLegacySubtyping); + _types = new KernelDartTypes(this, options); _commonElements = new CommonElementsImpl(_types, _elementEnvironment, options); _constantValuefier = new ConstantValuefier(this); @@ -240,7 +240,8 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { @override InterfaceType createInterfaceType( ir.Class cls, List typeArguments) { - return new InterfaceType(getClass(cls), getDartTypes(typeArguments)); + return new InterfaceType( + getClass(cls), getDartTypes(typeArguments), types.defaultNullability); } LibraryEntity getLibrary(ir.Library node) => getLibraryInternal(node); @@ -261,20 +262,23 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { if (data is KClassDataImpl && data.thisType == null) { ir.Class node = data.node; if (node.typeParameters.isEmpty) { - data.thisType = - data.rawType = new InterfaceType(cls, const []); + data.thisType = data.rawType = new InterfaceType( + cls, const [], types.defaultNullability); } else { data.thisType = new InterfaceType( cls, new List.generate(node.typeParameters.length, (int index) { return new TypeVariableType( - getTypeVariableInternal(node.typeParameters[index])); - })); + getTypeVariableInternal(node.typeParameters[index]), + types.defaultNullability); + }), + types.defaultNullability); data.rawType = new InterfaceType( cls, new List.filled( - node.typeParameters.length, DynamicType())); + node.typeParameters.length, DynamicType()), + types.defaultNullability); } } } @@ -288,7 +292,9 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { data.jsInteropType = data.thisType; } else { data.jsInteropType = InterfaceType( - cls, List.filled(node.typeParameters.length, AnyType())); + cls, + List.filled(node.typeParameters.length, AnyType()), + types.defaultNullability); } } } @@ -524,7 +530,8 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { } typeVariables = new List.generate( node.typeParameters.length, - (int index) => new FunctionTypeVariable(index)); + (int index) => + new FunctionTypeVariable(index, types.defaultNullability)); DartType subst(DartType type) { return type.subst(typeVariables, typeParameters); @@ -542,8 +549,14 @@ class KernelToElementMapImpl implements KernelToElementMap, IrToElementMap { typeVariables = const []; } - return new FunctionType(returnType, parameterTypes, optionalParameterTypes, - namedParameters, namedParameterTypes, typeVariables); + return new FunctionType( + returnType, + parameterTypes, + optionalParameterTypes, + namedParameters, + namedParameterTypes, + typeVariables, + types.defaultNullability); } @override @@ -1676,7 +1689,8 @@ class KernelElementEnvironment extends ElementEnvironment @override InterfaceType createInterfaceType( ClassEntity cls, List typeArguments) { - return new InterfaceType(cls, typeArguments); + return new InterfaceType( + cls, typeArguments, elementMap.types.defaultNullability); } @override diff --git a/pkg/compiler/lib/src/serialization/abstract_source.dart b/pkg/compiler/lib/src/serialization/abstract_source.dart index 5a455ed4f04..1ed94a352ad 100644 --- a/pkg/compiler/lib/src/serialization/abstract_source.dart +++ b/pkg/compiler/lib/src/serialization/abstract_source.dart @@ -182,16 +182,14 @@ abstract class AbstractDataSource extends DataSourceMixin switch (kind) { case DartTypeKind.none: return null; - case DartTypeKind.legacyType: - return LegacyType(_readDartType(functionTypeVariables)); - case DartTypeKind.nullableType: - return NullableType(_readDartType(functionTypeVariables)); case DartTypeKind.neverType: - return NeverType(); + Nullability nullability = readEnum(Nullability.values); + return NeverType(nullability); case DartTypeKind.voidType: return VoidType(); case DartTypeKind.typeVariable: - return new TypeVariableType(readTypeVariable()); + Nullability nullability = readEnum(Nullability.values); + return new TypeVariableType(readTypeVariable(), nullability); case DartTypeKind.functionTypeVariable: int index = readInt(); assert(0 <= index && index < functionTypeVariables.length); @@ -200,7 +198,10 @@ abstract class AbstractDataSource extends DataSourceMixin int typeVariableCount = readInt(); List typeVariables = new List.generate(typeVariableCount, - (int index) => new FunctionTypeVariable(index)); + (int index) { + Nullability nullability = readEnum(Nullability.values); + return new FunctionTypeVariable(index, nullability); + }); functionTypeVariables = new List.from(functionTypeVariables) ..addAll(typeVariables); @@ -218,18 +219,21 @@ abstract class AbstractDataSource extends DataSourceMixin for (int i = 0; i < namedParameters.length; i++) { namedParameters[i] = readString(); } + Nullability nullability = readEnum(Nullability.values); return new FunctionType( returnType, parameterTypes, optionalParameterTypes, namedParameters, namedParameterTypes, - typeVariables); + typeVariables, + nullability); case DartTypeKind.interfaceType: IndexedClass cls = readClass(); List typeArguments = _readDartTypes(functionTypeVariables); - return new InterfaceType(cls, typeArguments); + Nullability nullability = readEnum(Nullability.values); + return new InterfaceType(cls, typeArguments, nullability); case DartTypeKind.dynamicType: return DynamicType(); case DartTypeKind.erasedType: @@ -238,7 +242,8 @@ abstract class AbstractDataSource extends DataSourceMixin return AnyType(); case DartTypeKind.futureOr: DartType typeArgument = _readDartType(functionTypeVariables); - return new FutureOrType(typeArgument); + Nullability nullability = readEnum(Nullability.values); + return new FutureOrType(typeArgument, nullability); } throw new UnsupportedError("Unexpected DartTypeKind $kind"); } diff --git a/pkg/compiler/lib/src/serialization/helpers.dart b/pkg/compiler/lib/src/serialization/helpers.dart index 3e6d62122bb..851f878e979 100644 --- a/pkg/compiler/lib/src/serialization/helpers.dart +++ b/pkg/compiler/lib/src/serialization/helpers.dart @@ -89,8 +89,6 @@ class Tag { /// Enum used for identifying [DartType] subclasses in serialization. enum DartTypeKind { none, - legacyType, - nullableType, neverType, voidType, typeVariable, @@ -123,24 +121,11 @@ class DartTypeWriter } } - @override - void visitLegacyType(covariant LegacyType type, - List functionTypeVariables) { - _sink.writeEnum(DartTypeKind.legacyType); - _sink._writeDartType(type.baseType, functionTypeVariables); - } - - @override - void visitNullableType(covariant NullableType type, - List functionTypeVariables) { - _sink.writeEnum(DartTypeKind.nullableType); - _sink._writeDartType(type.baseType, functionTypeVariables); - } - @override void visitNeverType(covariant NeverType type, List functionTypeVariables) { _sink.writeEnum(DartTypeKind.neverType); + _sink.writeEnum(type.nullability); } @override @@ -154,6 +139,7 @@ class DartTypeWriter List functionTypeVariables) { _sink.writeEnum(DartTypeKind.typeVariable); IndexedTypeVariable typeVariable = type.element; + _sink.writeEnum(type.nullability); _sink.writeTypeVariable(typeVariable); } @@ -178,6 +164,9 @@ class DartTypeWriter new List.from(functionTypeVariables) ..addAll(type.typeVariables); _sink.writeInt(type.typeVariables.length); + for (FunctionTypeVariable variable in type.typeVariables) { + _sink.writeEnum(variable.nullability); + } for (FunctionTypeVariable variable in type.typeVariables) { _sink._writeDartType(variable.bound, functionTypeVariables); } @@ -188,6 +177,7 @@ class DartTypeWriter for (String namedParameter in type.namedParameters) { _sink.writeString(namedParameter); } + _sink.writeEnum(type.nullability); } @override @@ -196,6 +186,7 @@ class DartTypeWriter _sink.writeEnum(DartTypeKind.interfaceType); _sink.writeClass(type.element); visitTypes(type.typeArguments, functionTypeVariables); + _sink.writeEnum(type.nullability); } @override @@ -221,6 +212,7 @@ class DartTypeWriter List functionTypeVariables) { _sink.writeEnum(DartTypeKind.futureOr); _sink._writeDartType(type.typeArgument, functionTypeVariables); + _sink.writeEnum(type.nullability); } } diff --git a/pkg/compiler/lib/src/ssa/builder_kernel.dart b/pkg/compiler/lib/src/ssa/builder_kernel.dart index 162f2b121fd..636f1c4d094 100644 --- a/pkg/compiler/lib/src/ssa/builder_kernel.dart +++ b/pkg/compiler/lib/src/ssa/builder_kernel.dart @@ -387,6 +387,8 @@ class KernelSsaGraphBuilder extends ir.Visitor { return options.useNewRti; case 'VARIANCE': return options.enableVariance; + case 'NNBD': + return options.useNullSafety; case 'LEGACY': return options.useLegacySubtyping; default: @@ -2121,8 +2123,8 @@ class KernelSsaGraphBuilder extends ir.Visitor { List arguments = [pop()]; ClassEntity cls = _commonElements.streamIterator; DartType typeArg = _elementMap.getDartType(node.variable.type); - InterfaceType instanceType = - localsHandler.substInContext(new InterfaceType(cls, [typeArg])); + InterfaceType instanceType = localsHandler.substInContext(new InterfaceType( + cls, [typeArg], closedWorld.dartTypes.defaultNullability)); // TODO(johnniwinther): This should be the exact type. StaticType staticInstanceType = new StaticType(instanceType, ClassRelation.subtype); @@ -3108,8 +3110,8 @@ class KernelSsaGraphBuilder extends ir.Visitor { } if (options.useNewRti) { // [type] could be `List`, so ensure it is `JSArray`. - InterfaceType arrayType = - InterfaceType(_commonElements.jsArrayClass, type.typeArguments); + InterfaceType arrayType = InterfaceType(_commonElements.jsArrayClass, + type.typeArguments, closedWorld.dartTypes.defaultNullability); HInstruction rti = _typeBuilder.analyzeTypeArgumentNewRti(arrayType, sourceElement); @@ -4713,8 +4715,8 @@ class KernelSsaGraphBuilder extends ir.Visitor { } // TODO(sra): This should be JSArray, created via // _elementEnvironment.getJsInteropType(_elementEnvironment.jsArrayClass); - InterfaceType interopType = - InterfaceType(_commonElements.jsArrayClass, [DynamicType()]); + InterfaceType interopType = InterfaceType(_commonElements.jsArrayClass, + [DynamicType()], closedWorld.dartTypes.defaultNullability); SourceInformation sourceInformation = _sourceInformationBuilder.buildCall(invocation, invocation); HInstruction rti = diff --git a/pkg/compiler/pubspec.yaml b/pkg/compiler/pubspec.yaml index 2dbf1fba7cd..2bc338ef895 100644 --- a/pkg/compiler/pubspec.yaml +++ b/pkg/compiler/pubspec.yaml @@ -3,7 +3,7 @@ name: compiler publish_to: none environment: - sdk: '>=2.3.0 <3.0.0' + sdk: '>=2.6.0 <3.0.0' # NOTE: `pub get / pub upgrade` are generally not needed when working on this # package. The `.packages` file in the repository root will be used by default. diff --git a/sdk/lib/_internal/js_runtime/lib/rti.dart b/sdk/lib/_internal/js_runtime/lib/rti.dart index 30d4f454854..87e06b3dace 100644 --- a/sdk/lib/_internal/js_runtime/lib/rti.dart +++ b/sdk/lib/_internal/js_runtime/lib/rti.dart @@ -2372,7 +2372,7 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { if (sKind == Rti.kindAny) return true; // Left Top: - if (isTopType(s)) return false; + if (isStrongTopType(s)) return false; // Left Bottom: if (isLegacy) { @@ -2489,6 +2489,10 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { int sLength = _Utils.arrayLength(sBounds); int tLength = _Utils.arrayLength(tBounds); if (sLength != tLength) return false; + + sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv); + tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv); + for (int i = 0; i < sLength; i++) { var sBound = _Utils.arrayAt(sBounds, i); var tBound = _Utils.arrayAt(tBounds, i); @@ -2498,9 +2502,6 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { } } - sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv); - tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv); - return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv, Rti._getGenericFunctionBase(t), tEnv); } @@ -2685,21 +2686,23 @@ bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv) { return true; } -bool isTopType(Rti t) { - if (JS_GET_FLAG('LEGACY')) { - if (isObjectType(t)) return true; - } else { - if (isNullableObjectType(t)) return true; - } +bool isTopType(Rti t) => isStrongTopType(t) || isLegacyObjectType(t); + +bool isStrongTopType(Rti t) { int kind = Rti._getKind(t); return kind == Rti.kindDynamic || kind == Rti.kindVoid || kind == Rti.kindAny || kind == Rti.kindErased || - kind == Rti.kindFutureOr && isTopType(Rti._getFutureOrArgument(t)); + !JS_GET_FLAG('NNBD') && isObjectType(t) || + isNullableObjectType(t); } bool isObjectType(Rti t) => _Utils.isIdentical(t, TYPE_REF()); +// TODO(fishythefish): Use `LEGACY_TYPE_REF()`. +bool isLegacyObjectType(Rti t) => + Rti._getKind(t) == Rti.kindQuestion && + isObjectType(Rti._getStarArgument(t)); // TODO(fishythefish): Use `TYPE_REF()`. bool isNullableObjectType(Rti t) => Rti._getKind(t) == Rti.kindQuestion && diff --git a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart index ef15c153220..a096fb8624f 100644 --- a/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart +++ b/sdk_nnbd/lib/_internal/js_runtime/lib/rti.dart @@ -2372,7 +2372,7 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { if (sKind == Rti.kindAny) return true; // Left Top: - if (isTopType(s)) return false; + if (isStrongTopType(s)) return false; // Left Bottom: if (isLegacy) { @@ -2489,6 +2489,10 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { int sLength = _Utils.arrayLength(sBounds); int tLength = _Utils.arrayLength(tBounds); if (sLength != tLength) return false; + + sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv); + tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv); + for (int i = 0; i < sLength; i++) { var sBound = _Utils.arrayAt(sBounds, i); var tBound = _Utils.arrayAt(tBounds, i); @@ -2498,9 +2502,6 @@ bool _isSubtype(universe, Rti s, sEnv, Rti t, tEnv) { } } - sEnv = sEnv == null ? sBounds : _Utils.arrayConcat(sBounds, sEnv); - tEnv = tEnv == null ? tBounds : _Utils.arrayConcat(tBounds, tEnv); - return _isFunctionSubtype(universe, Rti._getGenericFunctionBase(s), sEnv, Rti._getGenericFunctionBase(t), tEnv); } @@ -2685,21 +2686,23 @@ bool _isInterfaceSubtype(universe, Rti s, sEnv, Rti t, tEnv) { return true; } -bool isTopType(Rti t) { - if (JS_GET_FLAG('LEGACY')) { - if (isObjectType(t)) return true; - } else { - if (isNullableObjectType(t)) return true; - } +bool isTopType(Rti t) => isStrongTopType(t) || isLegacyObjectType(t); + +bool isStrongTopType(Rti t) { int kind = Rti._getKind(t); return kind == Rti.kindDynamic || kind == Rti.kindVoid || kind == Rti.kindAny || kind == Rti.kindErased || - kind == Rti.kindFutureOr && isTopType(Rti._getFutureOrArgument(t)); + !JS_GET_FLAG('NNBD') && isObjectType(t) || + isNullableObjectType(t); } bool isObjectType(Rti t) => _Utils.isIdentical(t, TYPE_REF()); +// TODO(fishythefish): Use `LEGACY_TYPE_REF()`. +bool isLegacyObjectType(Rti t) => + Rti._getKind(t) == Rti.kindQuestion && + isObjectType(Rti._getStarArgument(t)); // TODO(fishythefish): Use `TYPE_REF()`. bool isNullableObjectType(Rti t) => Rti._getKind(t) == Rti.kindQuestion && diff --git a/tests/compiler/dart2js/equivalence/check_helpers.dart b/tests/compiler/dart2js/equivalence/check_helpers.dart index 37bd658dedc..5ff9899fe77 100644 --- a/tests/compiler/dart2js/equivalence/check_helpers.dart +++ b/tests/compiler/dart2js/equivalence/check_helpers.dart @@ -440,21 +440,28 @@ class DartTypePrinter implements DartTypeVisitor { return comma; } - @override - visitLegacyType(LegacyType type, _) { - visit(type.baseType); - sb.write('*'); - } - - @override - visitNullableType(NullableType type, _) { - visit(type.baseType); - sb.write('?'); + void _writeNullability(Nullability nullability, StringBuffer sb) { + switch (nullability) { + case Nullability.none: + return; + case Nullability.question: + sb.write('?'); + return; + case Nullability.star: + sb.write('*'); + return; + } } @override visitNeverType(NeverType type, _) { sb.write('Never'); + _writeNullability(type.nullability, sb); + } + + @override + visitVoidType(VoidType type, _) { + sb.write('void'); } @override @@ -480,6 +487,7 @@ class DartTypePrinter implements DartTypeVisitor { visitTypes(type.typeArguments); sb.write('>'); } + _writeNullability(type.nullability, sb); } @override @@ -512,21 +520,19 @@ class DartTypePrinter implements DartTypeVisitor { sb.write('}'); } sb.write(')'); + _writeNullability(type.nullability, sb); } @override visitFunctionTypeVariable(FunctionTypeVariable type, _) { sb.write(type); + _writeNullability(type.nullability, sb); } @override visitTypeVariableType(TypeVariableType type, _) { sb.write(type); - } - - @override - visitVoidType(VoidType type, _) { - sb.write('void'); + _writeNullability(type.nullability, sb); } @override @@ -534,6 +540,7 @@ class DartTypePrinter implements DartTypeVisitor { sb.write('FutureOr<'); visit(type.typeArgument); sb.write('>'); + _writeNullability(type.nullability, sb); } String getText() => sb.toString(); diff --git a/tests/compiler/dart2js/helpers/shared_helper.dart b/tests/compiler/dart2js/helpers/shared_helper.dart index 0a193230fab..77204a37203 100644 --- a/tests/compiler/dart2js/helpers/shared_helper.dart +++ b/tests/compiler/dart2js/helpers/shared_helper.dart @@ -23,21 +23,23 @@ class DartTypeToTextVisitor extends DartTypeVisitor { return comma; } - @override - void visitLegacyType(LegacyType type, StringBuffer sb) { - visit(type.baseType, sb); - sb.write('*'); - } - - @override - void visitNullableType(NullableType type, StringBuffer sb) { - visit(type.baseType, sb); - sb.write('?'); + void _writeNullability(Nullability nullability, StringBuffer sb) { + switch (nullability) { + case Nullability.none: + return; + case Nullability.question: + sb.write('?'); + return; + case Nullability.star: + sb.write('*'); + return; + } } @override void visitNeverType(NeverType type, StringBuffer sb) { sb.write('Never'); + _writeNullability(type.nullability, sb); } @override @@ -45,18 +47,36 @@ class DartTypeToTextVisitor extends DartTypeVisitor { sb.write('void'); } + @override + void visitDynamicType(DynamicType type, StringBuffer sb) { + sb.write('dynamic'); + } + + @override + void visitErasedType(ErasedType type, StringBuffer sb) { + sb.write('erased'); + } + + @override + void visitAnyType(AnyType type, StringBuffer sb) { + sb.write('any'); + } + @override void visitTypeVariableType(TypeVariableType type, StringBuffer sb) { sb.write(type.element.name); + _writeNullability(type.nullability, sb); } @override void visitFunctionTypeVariable(FunctionTypeVariable type, StringBuffer sb) { sb.write(type.index); + _writeNullability(type.nullability, sb); } @override void visitFunctionType(FunctionType type, StringBuffer sb) { + if (!type.nullability.isNone) sb.write('('); sb.write('('); String comma = visitList(type.parameterTypes, sb); if (type.optionalParameterTypes.isNotEmpty) { @@ -81,6 +101,8 @@ class DartTypeToTextVisitor extends DartTypeVisitor { } sb.write(')->'); visit(type.returnType, sb); + if (!type.nullability.isNone) sb.write(')'); + _writeNullability(type.nullability, sb); } @override @@ -91,11 +113,7 @@ class DartTypeToTextVisitor extends DartTypeVisitor { visitList(type.typeArguments, sb); sb.write('>'); } - } - - @override - void visitDynamicType(DynamicType type, StringBuffer sb) { - sb.write('dynamic'); + _writeNullability(type.nullability, sb); } @override @@ -103,6 +121,7 @@ class DartTypeToTextVisitor extends DartTypeVisitor { sb.write('FutureOr<'); visit(type.typeArgument, sb); sb.write('>'); + _writeNullability(type.nullability, sb); } } diff --git a/tests/compiler/dart2js/helpers/type_test_helper.dart b/tests/compiler/dart2js/helpers/type_test_helper.dart index 1d36a31fbc3..dfe0245dac6 100644 --- a/tests/compiler/dart2js/helpers/type_test_helper.dart +++ b/tests/compiler/dart2js/helpers/type_test_helper.dart @@ -18,7 +18,7 @@ import 'package:compiler/src/world.dart' show JClosedWorld, KClosedWorld; import 'memory_compiler.dart' as memory; DartType instantiate(ClassEntity element, List arguments) { - return new InterfaceType(element, arguments); + return new InterfaceType(element, arguments, Nullability.none); } class TypeEnvironment { diff --git a/tests/compiler/dart2js/model/type_substitution_test.dart b/tests/compiler/dart2js/model/type_substitution_test.dart index 85c578494a7..89f5489ca7a 100644 --- a/tests/compiler/dart2js/model/type_substitution_test.dart +++ b/tests/compiler/dart2js/model/type_substitution_test.dart @@ -201,18 +201,24 @@ testTypeSubstitution() async { env.elementEnvironment, arguments, parameters, - new FunctionType(intType, [StringType], [], [], [], []), - new FunctionType(intType, [StringType], [], [], [], [])); + new FunctionType( + intType, [StringType], [], [], [], [], env.types.defaultNullability), + new FunctionType( + intType, [StringType], [], [], [], [], env.types.defaultNullability)); testSubstitution( env.elementEnvironment, arguments, parameters, - new FunctionType(VoidType(), [T, S], [], [], [], []), - new FunctionType(VoidType(), [intType, StringType], [], [], [], [])); + new FunctionType( + VoidType(), [T, S], [], [], [], [], env.types.defaultNullability), + new FunctionType(VoidType(), [intType, StringType], [], [], [], [], + env.types.defaultNullability)); testSubstitution( env.elementEnvironment, arguments, parameters, - new FunctionType(VoidType(), [DynamicType()], [], [], [], []), - new FunctionType(VoidType(), [DynamicType()], [], [], [], [])); + new FunctionType(VoidType(), [DynamicType()], [], [], [], [], + env.types.defaultNullability), + new FunctionType(VoidType(), [DynamicType()], [], [], [], [], + env.types.defaultNullability)); } diff --git a/tests/compiler/dart2js/rti/data/generic_bounds.dart b/tests/compiler/dart2js/rti/data/generic_bounds.dart index c30e230144a..4bbc2de16ac 100644 --- a/tests/compiler/dart2js/rti/data/generic_bounds.dart +++ b/tests/compiler/dart2js/rti/data/generic_bounds.dart @@ -39,13 +39,13 @@ class Class4 {} method10() => null; main() { - /*strong.needsArgs,needsSignature,selectors=[Selector(call, call, arity=0, types=1)]*/ - /*omit.needsSignature*/method7() => null; + /*strong.needsArgs,selectors=[Selector(call, call, arity=0, types=1)]*/ + /*omit.*/method7() => null; - /*strong.needsArgs,needsSignature,selectors=[Selector(call, call, arity=0, types=1)]*/ - /*omit.needsSignature*/method8>() => null; + /*strong.needsArgs,selectors=[Selector(call, call, arity=0, types=1)]*/ + /*omit.*/method8>() => null; - /*needsSignature*/ + /**/ method9() => null; dynamic f1 = method1; diff --git a/tests/compiler/dart2js/rti/data/local_function_signature2.dart b/tests/compiler/dart2js/rti/data/local_function_signature2.dart index 8f45a2d08b8..dd0c8388b61 100644 --- a/tests/compiler/dart2js/rti/data/local_function_signature2.dart +++ b/tests/compiler/dart2js/rti/data/local_function_signature2.dart @@ -6,7 +6,7 @@ import 'package:expect/expect.dart'; class Class1 { method1() { - /*needsSignature*/ + /**/ num local(num n) => null; return local; } @@ -18,7 +18,7 @@ class Class1 { } method3() { - /*needsSignature*/ + /**/ int local(num n) => null; return local; } diff --git a/tests/compiler/dart2js/rti/data/method_signatures_generic.dart b/tests/compiler/dart2js/rti/data/method_signatures_generic.dart index 9f33a9f0251..e356581ad22 100644 --- a/tests/compiler/dart2js/rti/data/method_signatures_generic.dart +++ b/tests/compiler/dart2js/rti/data/method_signatures_generic.dart @@ -16,7 +16,7 @@ class Class1 { } class Class2 { - /*strong.member: Class2.method4:direct,explicit=[method4.T],needsArgs,needsInst=[,]*/ + /*strong.member: Class2.method4:direct,explicit=[method4.T],needsArgs,needsInst=[,,,]*/ /*omit.member: Class2.method4:*/ num method4(T n) => null; } @@ -27,19 +27,19 @@ class Class3 { } class Class4 { - /*strong.member: Class4.method6:direct,explicit=[method6.T],needsArgs,needsInst=[,]*/ + /*strong.member: Class4.method6:direct,explicit=[method6.T],needsArgs,needsInst=[,,,]*/ /*omit.member: Class4.method6:*/ num method6(num n, T t) => null; } -/*strong.member: method7:direct,explicit=[method7.T],needsArgs,needsInst=[,]*/ +/*strong.member: method7:direct,explicit=[method7.T],needsArgs,needsInst=[,,,]*/ /*omit.member: method7:*/ num method7(T n) => null; /*member: method8:*/ T method8(num n) => null; -/*strong.member: method9:direct,explicit=[method9.T],needsArgs,needsInst=[,]*/ +/*strong.member: method9:direct,explicit=[method9.T],needsArgs,needsInst=[,,,]*/ /*omit.member: method9:*/ num method9(num n, T t) => null; diff --git a/tests/compiler/dart2js/rti/rti_need_test_helper.dart b/tests/compiler/dart2js/rti/rti_need_test_helper.dart index 168a38307cb..d3ae7f46796 100644 --- a/tests/compiler/dart2js/rti/rti_need_test_helper.dart +++ b/tests/compiler/dart2js/rti/rti_need_test_helper.dart @@ -203,12 +203,6 @@ class FindTypeVisitor extends BaseDartTypeVisitor { @override bool visitType(DartType type, _) => false; - @override - bool visitLegacyType(LegacyType type, _) => visit(type.baseType, _); - - @override - bool visitNullableType(NullableType type, _) => visit(type.baseType, _); - @override bool visitInterfaceType(InterfaceType type, _) { if (type.element == entity) return true;