Version 2.10.0-120.0.dev
Merge commit '0567babb06f45a24120c8137d15de3b499163110' into 'dev'
diff --git a/pkg/analyzer/lib/src/dart/analysis/driver.dart b/pkg/analyzer/lib/src/dart/analysis/driver.dart
index a369c9c..1f4fe07 100644
--- a/pkg/analyzer/lib/src/dart/analysis/driver.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/driver.dart
@@ -85,7 +85,7 @@
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
- static const int DATA_VERSION = 110;
+ static const int DATA_VERSION = 111;
/// The length of the list returned by [_computeDeclaredVariablesSignature].
static const int _declaredVariablesSignatureLength = 4;
diff --git a/pkg/analyzer/lib/src/dart/analysis/file_state.dart b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
index db34b39..0a3dee5 100644
--- a/pkg/analyzer/lib/src/dart/analysis/file_state.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/file_state.dart
@@ -115,7 +115,7 @@
final FeatureSet _contextFeatureSet;
/// The language version for the package that contains this file.
- final Version _packageLanguageVersion;
+ final Version packageLanguageVersion;
int id = fileObjectId++;
int refreshId;
@@ -156,7 +156,7 @@
this.source,
this.workspacePackage,
this._contextFeatureSet,
- this._packageLanguageVersion,
+ this.packageLanguageVersion,
) : isInExternalSummaries = false;
FileState._external(this._fsState, this.uri)
@@ -166,7 +166,7 @@
workspacePackage = null,
_exists = true,
_contextFeatureSet = null,
- _packageLanguageVersion = null {
+ packageLanguageVersion = null {
_apiSignature = Uint8List(16);
_libraryCycle = LibraryCycle.external();
}
@@ -375,7 +375,7 @@
var signature = ApiSignature();
signature.addUint32List(_fsState._saltForUnlinked);
signature.addFeatureSet(_contextFeatureSet);
- signature.addLanguageVersion(_packageLanguageVersion);
+ signature.addLanguageVersion(packageLanguageVersion);
signature.addString(_contentHash);
signature.addBool(_exists);
contentSignature = signature.toByteList();
@@ -510,7 +510,7 @@
unit.lineInfo = LineInfo(const <int>[0]);
unit.languageVersion = LibraryLanguageVersion(
- package: _packageLanguageVersion,
+ package: packageLanguageVersion,
override: null,
);
@@ -561,7 +561,7 @@
..configureFeatures(
featureSetForOverriding: _contextFeatureSet,
featureSet: _contextFeatureSet.restrictToVersion(
- _packageLanguageVersion,
+ packageLanguageVersion,
),
);
Token token = scanner.tokenize(reportScannerErrors: false);
@@ -640,7 +640,7 @@
var unitImpl = unit as CompilationUnitImpl;
unitImpl.languageVersion = LibraryLanguageVersion(
- package: _packageLanguageVersion,
+ package: packageLanguageVersion,
override: overrideVersion,
);
}
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
index 95e4972..dfcfb0d 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_graph.dart
@@ -125,6 +125,7 @@
for (var node in scc) {
cycle.libraries.add(node.file);
+ signature.addLanguageVersion(node.file.packageLanguageVersion);
signature.addString(node.file.uriStr);
signature.addInt(node.file.libraryFiles.length);
diff --git a/pkg/analyzer/lib/src/dart/element/type_system.dart b/pkg/analyzer/lib/src/dart/element/type_system.dart
index f27c23b..e4c683a 100644
--- a/pkg/analyzer/lib/src/dart/element/type_system.dart
+++ b/pkg/analyzer/lib/src/dart/element/type_system.dart
@@ -11,7 +11,7 @@
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/type_provider.dart';
-import 'package:analyzer/dart/element/type_system.dart' as public;
+import 'package:analyzer/dart/element/type_system.dart';
import 'package:analyzer/error/listener.dart' show ErrorReporter;
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/generic_inferrer.dart';
@@ -30,395 +30,15 @@
import 'package:analyzer/src/dart/element/type_schema_elimination.dart';
import 'package:meta/meta.dart';
-/// The interface `TypeSystem` defines the behavior of an object representing
-/// the type system. This provides a common location to put methods that act on
-/// types but may need access to more global data structures, and it paves the
-/// way for a possible future where we may wish to make the type system
-/// pluggable.
-// TODO(brianwilkerson) Rename this class to TypeSystemImpl.
-abstract class TypeSystem2 implements public.TypeSystem {
+/// The [TypeSystem] implementation.
+class TypeSystemImpl implements TypeSystem {
/// If `true`, then NNBD type rules should be used.
/// If `false`, then legacy type rules should be used.
final bool isNonNullableByDefault;
- TypeSystem2({@required this.isNonNullableByDefault});
+ /// The provider of types for the system.
+ final TypeProviderImpl typeProvider;
- /// The provider of types for the system
- TypeProvider get typeProvider;
-
- @override
- TypeImpl flatten(DartType type) {
- if (identical(type, UnknownInferredType.instance)) {
- return type;
- }
-
- // if T is S? then flatten(T) = flatten(S)?
- // if T is S* then flatten(T) = flatten(S)*
- NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
- if (nullabilitySuffix != NullabilitySuffix.none) {
- var S = (type as TypeImpl).withNullability(NullabilitySuffix.none);
- return flatten(S).withNullability(nullabilitySuffix);
- }
-
- if (type is InterfaceType) {
- // Implement the cases:
- // - "If T = FutureOr<S> then flatten(T) = S."
- // - "If T = Future<S> then flatten(T) = S."
- if (type.isDartAsyncFutureOr || type.isDartAsyncFuture) {
- return type.typeArguments.isNotEmpty
- ? type.typeArguments[0]
- : DynamicTypeImpl.instance;
- }
- // Implement the case: "Otherwise if T <: Future then let S be a type
- // such that T << Future<S> and for all R, if T << Future<R> then S << R.
- // Then flatten(T) = S."
- //
- // In other words, given the set of all types R such that T << Future<R>,
- // let S be the most specific of those types, if any such S exists.
- //
- // Since we only care about the most specific type, it is sufficient to
- // look at the types appearing as a parameter to Future in the type
- // hierarchy of T. We don't need to consider the supertypes of those
- // types, since they are by definition less specific.
- List<DartType> candidateTypes =
- _searchTypeHierarchyForFutureTypeParameters(type);
- DartType flattenResult =
- InterfaceTypeImpl.findMostSpecificType(candidateTypes, this);
- if (flattenResult != null) {
- return flattenResult;
- }
- }
- // Implement the case: "In any other circumstance, flatten(T) = T."
- return type;
- }
-
- DartType futureOrBase(DartType type) {
- // If `T` is `FutureOr<S>` for some `S`,
- // then `futureOrBase(T)` = `futureOrBase(S)`
- if (type is InterfaceType && type.isDartAsyncFutureOr) {
- return futureOrBase(
- type.typeArguments[0],
- );
- }
-
- // Otherwise `futureOrBase(T)` = `T`.
- return type;
- }
-
- List<InterfaceType> gatherMixinSupertypeConstraintsForInference(
- ClassElement mixinElement) {
- List<InterfaceType> candidates;
- if (mixinElement.isMixin) {
- candidates = mixinElement.superclassConstraints;
- } else {
- candidates = [mixinElement.supertype];
- candidates.addAll(mixinElement.mixins);
- if (mixinElement.isMixinApplication) {
- candidates.removeLast();
- }
- }
- return candidates
- .where((type) => type.element.typeParameters.isNotEmpty)
- .toList();
- }
-
- /// Compute the least upper bound of two types.
- DartType getLeastUpperBound(DartType type1, DartType type2);
-
- /// Given a [DartType] [type], instantiate it with its bounds.
- ///
- /// The behavior of this method depends on the type system, for example, in
- /// classic Dart `dynamic` will be used for all type arguments, whereas
- /// strong mode prefers the actual bound type if it was specified.
- DartType instantiateToBounds(DartType type, {List<bool> hasError});
-
- /// Given a [DartType] [type] and a list of types
- /// [typeArguments], instantiate the type formals with the
- /// provided actuals. If [type] is not a parameterized type,
- /// no instantiation is done.
- DartType instantiateType(DartType type, List<DartType> typeArguments) {
- if (type is FunctionType) {
- return type.instantiate(typeArguments);
- } else if (type is InterfaceTypeImpl) {
- // TODO(scheglov) Use `ClassElement.instantiate()`, don't use raw types.
- return type.element.instantiate(
- typeArguments: typeArguments,
- nullabilitySuffix: type.nullabilitySuffix,
- );
- } else {
- return type;
- }
- }
-
- /// Given uninstantiated [typeFormals], instantiate them to their bounds.
- List<DartType> instantiateTypeFormalsToBounds(
- List<TypeParameterElement> typeFormals,
- {List<bool> hasError});
-
- /// Return `true` if the [leftType] is assignable to the [rightType] (that is,
- /// if leftType <==> rightType).
- @override
- bool isAssignableTo(DartType leftType, DartType rightType);
-
- /// Return `true` if the [leftType] is more specific than the [rightType]
- /// (that is, if leftType << rightType), as defined in the Dart language spec.
- ///
- /// In strong mode, this is equivalent to [isSubtypeOf].
- @Deprecated('Use isSubtypeOf() instead.')
- bool isMoreSpecificThan(DartType leftType, DartType rightType);
-
- @override
- bool isNonNullable(DartType type) {
- if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
- return false;
- } else if (type is TypeParameterTypeImpl && type.promotedBound != null) {
- return isNonNullable(type.promotedBound);
- } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
- return false;
- } else if (type is InterfaceType && type.isDartAsyncFutureOr) {
- return isNonNullable(type.typeArguments[0]);
- } else if (type is TypeParameterType) {
- var bound = type.element.bound;
- return bound != null && isNonNullable(bound);
- }
- return true;
- }
-
- @override
- bool isNullable(DartType type) {
- if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
- return true;
- } else if (type is TypeParameterTypeImpl && type.promotedBound != null) {
- return isNullable(type.promotedBound);
- } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
- return true;
- } else if (type.isDartAsyncFutureOr) {
- return isNullable((type as InterfaceType).typeArguments[0]);
- }
- return false;
- }
-
- @override
- bool isPotentiallyNonNullable(DartType type) => !isNullable(type);
-
- @override
- bool isPotentiallyNullable(DartType type) => !isNonNullable(type);
-
- @override
- bool isStrictlyNonNullable(DartType type) {
- if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
- return false;
- } else if (type.nullabilitySuffix != NullabilitySuffix.none) {
- return false;
- } else if (type is InterfaceType && type.isDartAsyncFutureOr) {
- return isStrictlyNonNullable(type.typeArguments[0]);
- } else if (type is TypeParameterType) {
- return isStrictlyNonNullable(type.bound);
- }
- return true;
- }
-
- /// Return `true` if the [leftType] is a subtype of the [rightType] (that is,
- /// if leftType <: rightType).
- @override
- bool isSubtypeOf(DartType leftType, DartType rightType);
-
- @override
- DartType leastUpperBound(DartType leftType, DartType rightType) {
- if (!NullSafetyUnderstandingFlag.isEnabled) {
- leftType = NullabilityEliminator.perform(typeProvider, leftType);
- rightType = NullabilityEliminator.perform(typeProvider, rightType);
- }
- return getLeastUpperBound(leftType, rightType);
- }
-
- /// Returns a nullable version of [type]. The result would be equivalent to
- /// the union `type | Null` (if we supported union types).
- DartType makeNullable(TypeImpl type) {
- // TODO(paulberry): handle type parameter types
- return type.withNullability(NullabilitySuffix.question);
- }
-
- /// Attempts to find the appropriate substitution for the [mixinElement]
- /// type parameters that can be applied to [srcTypes] to make it equal to
- /// [destTypes]. If no such substitution can be found, `null` is returned.
- List<DartType> matchSupertypeConstraints(
- ClassElement mixinElement,
- List<DartType> srcTypes,
- List<DartType> destTypes,
- ) {
- var typeParameters = mixinElement.typeParameters;
- var inferrer = GenericInferrer(this, typeParameters);
- for (int i = 0; i < srcTypes.length; i++) {
- inferrer.constrainReturnType(srcTypes[i], destTypes[i]);
- inferrer.constrainReturnType(destTypes[i], srcTypes[i]);
- }
-
- var inferredTypes = inferrer.infer(
- typeParameters,
- considerExtendsClause: false,
- );
- var substitution = Substitution.fromPairs(typeParameters, inferredTypes);
-
- for (int i = 0; i < srcTypes.length; i++) {
- var srcType = substitution.substituteType(srcTypes[i]);
- var destType = destTypes[i];
- if (isNonNullableByDefault) {
- // TODO(scheglov) waiting for the spec
- // https://github.com/dart-lang/sdk/issues/42605
- } else {
- srcType = toLegacyType(srcType);
- destType = toLegacyType(destType);
- }
- if (srcType != destType) {
- // Failed to find an appropriate substitution
- return null;
- }
- }
-
- return inferredTypes;
- }
-
- /// Returns a non-nullable version of [type]. This is equivalent to the
- /// operation `NonNull` defined in the spec.
- @override
- DartType promoteToNonNull(DartType type) {
- if (type.isDartCoreNull) return NeverTypeImpl.instance;
-
- if (type is TypeParameterTypeImpl) {
- var element = type.element;
-
- // NonNull(X & T) = X & NonNull(T)
- if (type.promotedBound != null) {
- var promotedBound = promoteToNonNull(type.promotedBound);
- return TypeParameterTypeImpl(
- element: element,
- nullabilitySuffix: NullabilitySuffix.none,
- promotedBound: promotedBound,
- );
- }
-
- // NonNull(X) = X & NonNull(B), where B is the bound of X
- var promotedBound = element.bound != null
- ? promoteToNonNull(element.bound)
- : typeProvider.objectType;
- if (identical(promotedBound, element.bound)) {
- promotedBound = null;
- }
- return TypeParameterTypeImpl(
- element: element,
- nullabilitySuffix: NullabilitySuffix.none,
- promotedBound: promotedBound,
- );
- }
-
- return (type as TypeImpl).withNullability(NullabilitySuffix.none);
- }
-
- /// Determine the type of a binary expression with the given [operator] whose
- /// left operand has the type [leftType] and whose right operand has the type
- /// [rightType], given that resolution has so far produced the [currentType].
- DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
- DartType rightType, DartType currentType, MethodElement operatorElement);
-
- /// Determines the context type for the parameters of a method invocation
- /// where the type of the target is [targetType], the method being invoked is
- /// [methodElement], the context surrounding the method invocation is
- /// [invocationContext], and the context type produced so far by resolution is
- /// [currentType].
- DartType refineNumericInvocationContext(DartType targetType,
- Element methodElement, DartType invocationContext, DartType currentType);
-
- /// Determines the type of a method invocation where the type of the target is
- /// [targetType], the method being invoked is [methodElement], the types of
- /// the arguments passed to the method are [argumentTypes], and the type
- /// produced so far by resolution is [currentType].
- DartType refineNumericInvocationType(
- DartType targetType,
- MethodElement methodElement,
- List<DartType> argumentTypes,
- DartType currentType);
-
- @override
- DartType resolveToBound(DartType type) {
- if (type is TypeParameterTypeImpl) {
- var element = type.element;
-
- var bound = element.bound;
- if (bound == null) {
- return typeProvider.objectType;
- }
-
- NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
- NullabilitySuffix newNullabilitySuffix;
- if (nullabilitySuffix == NullabilitySuffix.question ||
- bound.nullabilitySuffix == NullabilitySuffix.question) {
- newNullabilitySuffix = NullabilitySuffix.question;
- } else if (nullabilitySuffix == NullabilitySuffix.star ||
- bound.nullabilitySuffix == NullabilitySuffix.star) {
- newNullabilitySuffix = NullabilitySuffix.star;
- } else {
- newNullabilitySuffix = NullabilitySuffix.none;
- }
-
- var resolved = resolveToBound(bound) as TypeImpl;
- return resolved.withNullability(newNullabilitySuffix);
- }
-
- return type;
- }
-
- DartType toLegacyType(DartType type) {
- if (isNonNullableByDefault) return type;
- return NullabilityEliminator.perform(typeProvider, type);
- }
-
- /// Tries to promote from the first type from the second type, and returns the
- /// promoted type if it succeeds, otherwise null.
- DartType tryPromoteToType(DartType to, DartType from);
-
- /// Given a [DartType] type, return the [TypeParameterElement]s corresponding
- /// to its formal type parameters (if any).
- ///
- /// @param type the type whose type arguments are to be returned
- /// @return the type arguments associated with the given type
- List<TypeParameterElement> typeFormalsAsElements(DartType type) {
- if (type is FunctionType) {
- return type.typeFormals;
- } else if (type is InterfaceType) {
- return type.element.typeParameters;
- } else {
- return const <TypeParameterElement>[];
- }
- }
-
- /// Starting from the given [type], search its class hierarchy for types of
- /// the form Future<R>, and return a list of the resulting R's.
- List<DartType> _searchTypeHierarchyForFutureTypeParameters(DartType type) {
- List<DartType> result = <DartType>[];
- HashSet<ClassElement> visitedClasses = HashSet<ClassElement>();
- void recurse(InterfaceTypeImpl type) {
- if (type.isDartAsyncFuture && type.typeArguments.isNotEmpty) {
- result.add(type.typeArguments[0]);
- }
- if (visitedClasses.add(type.element)) {
- if (type.superclass != null) {
- recurse(type.superclass);
- }
- for (InterfaceType interface in type.interfaces) {
- recurse(interface);
- }
- visitedClasses.remove(type.element);
- }
- }
-
- recurse(type);
- return result;
- }
-}
-
-/// The [public.TypeSystem] implementation.
-class TypeSystemImpl extends TypeSystem2 {
/// False if implicit casts should always be disallowed.
///
/// This affects the behavior of [isAssignableTo].
@@ -429,9 +49,6 @@
/// This option is experimental and subject to change.
bool strictInference;
- @override
- final TypeProviderImpl typeProvider;
-
/// The cached instance of `Object?`.
InterfaceTypeImpl _objectQuestion;
@@ -452,11 +69,10 @@
TypeSystemImpl({
@required this.implicitCasts,
- @required bool isNonNullableByDefault,
+ @required this.isNonNullableByDefault,
@required this.strictInference,
@required TypeProvider typeProvider,
- }) : typeProvider = typeProvider as TypeProviderImpl,
- super(isNonNullableByDefault: isNonNullableByDefault) {
+ }) : typeProvider = typeProvider as TypeProviderImpl {
_greatestLowerBoundHelper = GreatestLowerBoundHelper(this);
_leastUpperBoundHelper = LeastUpperBoundHelper(this);
_subtypeHelper = SubtypeHelper(this);
@@ -578,6 +194,65 @@
return T;
}
+ @override
+ TypeImpl flatten(DartType type) {
+ if (identical(type, UnknownInferredType.instance)) {
+ return type;
+ }
+
+ // if T is S? then flatten(T) = flatten(S)?
+ // if T is S* then flatten(T) = flatten(S)*
+ NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
+ if (nullabilitySuffix != NullabilitySuffix.none) {
+ var S = (type as TypeImpl).withNullability(NullabilitySuffix.none);
+ return flatten(S).withNullability(nullabilitySuffix);
+ }
+
+ if (type is InterfaceType) {
+ // Implement the cases:
+ // - "If T = FutureOr<S> then flatten(T) = S."
+ // - "If T = Future<S> then flatten(T) = S."
+ if (type.isDartAsyncFutureOr || type.isDartAsyncFuture) {
+ return type.typeArguments.isNotEmpty
+ ? type.typeArguments[0]
+ : DynamicTypeImpl.instance;
+ }
+ // Implement the case: "Otherwise if T <: Future then let S be a type
+ // such that T << Future<S> and for all R, if T << Future<R> then S << R.
+ // Then flatten(T) = S."
+ //
+ // In other words, given the set of all types R such that T << Future<R>,
+ // let S be the most specific of those types, if any such S exists.
+ //
+ // Since we only care about the most specific type, it is sufficient to
+ // look at the types appearing as a parameter to Future in the type
+ // hierarchy of T. We don't need to consider the supertypes of those
+ // types, since they are by definition less specific.
+ List<DartType> candidateTypes =
+ _searchTypeHierarchyForFutureTypeParameters(type);
+ DartType flattenResult =
+ InterfaceTypeImpl.findMostSpecificType(candidateTypes, this);
+ if (flattenResult != null) {
+ return flattenResult;
+ }
+ }
+ // Implement the case: "In any other circumstance, flatten(T) = T."
+ return type;
+ }
+
+ DartType futureOrBase(DartType type) {
+ // If `T` is `FutureOr<S>` for some `S`,
+ // then `futureOrBase(T)` = `futureOrBase(S)`
+ if (type is InterfaceType && type.isDartAsyncFutureOr) {
+ return futureOrBase(
+ type.typeArguments[0],
+ );
+ }
+
+ // Otherwise `futureOrBase(T)` = `T`.
+ return type;
+ }
+
/// Compute "future value type" of [T].
///
/// https://github.com/dart-lang/language/
@@ -613,6 +288,23 @@
return objectQuestion;
}
+ List<InterfaceType> gatherMixinSupertypeConstraintsForInference(
+ ClassElement mixinElement) {
+ List<InterfaceType> candidates;
+ if (mixinElement.isMixin) {
+ candidates = mixinElement.superclassConstraints;
+ } else {
+ candidates = [mixinElement.supertype];
+ candidates.addAll(mixinElement.mixins);
+ if (mixinElement.isMixinApplication) {
+ candidates.removeLast();
+ }
+ }
+ return candidates
+ .where((type) => type.element.typeParameters.isNotEmpty)
+ .toList();
+ }
+
/// Given a type t, if t is an interface type with a call method defined,
/// return the function type for the call method, otherwise return null.
FunctionType getCallMethodType(DartType t) {
@@ -631,7 +323,6 @@
///
/// https://github.com/dart-lang/language
/// See `resources/type-system/upper-lower-bounds.md`
- @override
DartType getLeastUpperBound(DartType T1, DartType T2) {
return _leastUpperBoundHelper.getLeastUpperBound(T1, T2);
}
@@ -775,7 +466,6 @@
/// https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397
// TODO(scheglov) Move this method to elements for classes, typedefs,
// and generic functions; compute lazily and cache.
- @override
DartType instantiateToBounds(DartType type,
{List<bool> hasError, Map<TypeParameterElement, DartType> knownTypes}) {
List<TypeParameterElement> typeFormals = typeFormalsAsElements(type);
@@ -817,11 +507,28 @@
}
}
+ /// Given a [DartType] [type] and a list of types
+ /// [typeArguments], instantiate the type formals with the
+ /// provided actuals. If [type] is not a parameterized type,
+ /// no instantiation is done.
+ DartType instantiateType(DartType type, List<DartType> typeArguments) {
+ if (type is FunctionType) {
+ return type.instantiate(typeArguments);
+ } else if (type is InterfaceTypeImpl) {
+ // TODO(scheglov) Use `ClassElement.instantiate()`, don't use raw types.
+ return type.element.instantiate(
+ typeArguments: typeArguments,
+ nullabilitySuffix: type.nullabilitySuffix,
+ );
+ } else {
+ return type;
+ }
+ }
+
/// Given uninstantiated [typeFormals], instantiate them to their bounds.
/// See the issue for the algorithm description.
///
/// https://github.com/dart-lang/sdk/issues/27526#issuecomment-260021397
- @override
List<DartType> instantiateTypeFormalsToBounds(
List<TypeParameterElement> typeFormals,
{List<bool> hasError,
@@ -1135,8 +842,14 @@
return false;
}
- @override
- bool isMoreSpecificThan(DartType t1, DartType t2) => isSubtypeOf2(t1, t2);
+ /// Return `true` if the [leftType] is more specific than the [rightType]
+ /// (that is, if leftType << rightType), as defined in the Dart language spec.
+ ///
+ /// In strong mode, this is equivalent to [isSubtypeOf].
+ @Deprecated('Use isSubtypeOf() instead.')
+ bool isMoreSpecificThan(DartType leftType, DartType rightType) {
+ return isSubtypeOf2(leftType, rightType);
+ }
/// Defines a total order on top and Object types.
bool isMoreTop(DartType T, DartType S) {
@@ -1227,6 +940,23 @@
return false;
}
+ @override
+ bool isNonNullable(DartType type) {
+ if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
+ return false;
+ } else if (type is TypeParameterTypeImpl && type.promotedBound != null) {
+ return isNonNullable(type.promotedBound);
+ } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
+ return false;
+ } else if (type is InterfaceType && type.isDartAsyncFutureOr) {
+ return isNonNullable(type.typeArguments[0]);
+ } else if (type is TypeParameterType) {
+ var bound = type.element.bound;
+ return bound != null && isNonNullable(bound);
+ }
+ return true;
+ }
+
/// Return `true` for things in the equivalence class of `Null`.
bool isNull(DartType type) {
var typeImpl = type as TypeImpl;
@@ -1251,6 +981,20 @@
return false;
}
+ @override
+ bool isNullable(DartType type) {
+ if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
+ return true;
+ } else if (type is TypeParameterTypeImpl && type.promotedBound != null) {
+ return isNullable(type.promotedBound);
+ } else if (type.nullabilitySuffix == NullabilitySuffix.question) {
+ return true;
+ } else if (type.isDartAsyncFutureOr) {
+ return isNullable((type as InterfaceType).typeArguments[0]);
+ }
+ return false;
+ }
+
/// Return `true` for any type which is in the equivalence class of `Object`.
bool isObject(DartType type) {
TypeImpl typeImpl = type;
@@ -1273,6 +1017,26 @@
return false;
}
+ @override
+ bool isPotentiallyNonNullable(DartType type) => !isNullable(type);
+
+ @override
+ bool isPotentiallyNullable(DartType type) => !isNonNullable(type);
+
+ @override
+ bool isStrictlyNonNullable(DartType type) {
+ if (type.isDynamic || type.isVoid || type.isDartCoreNull) {
+ return false;
+ } else if (type.nullabilitySuffix != NullabilitySuffix.none) {
+ return false;
+ } else if (type is InterfaceType && type.isDartAsyncFutureOr) {
+ return isStrictlyNonNullable(type.typeArguments[0]);
+ } else if (type is TypeParameterType) {
+ return isStrictlyNonNullable(type.bound);
+ }
+ return true;
+ }
+
/// Check if [leftType] is a subtype of [rightType].
///
/// Implements:
@@ -1361,6 +1125,62 @@
}
}
+ @override
+ DartType leastUpperBound(DartType leftType, DartType rightType) {
+ if (!NullSafetyUnderstandingFlag.isEnabled) {
+ leftType = NullabilityEliminator.perform(typeProvider, leftType);
+ rightType = NullabilityEliminator.perform(typeProvider, rightType);
+ }
+ return getLeastUpperBound(leftType, rightType);
+ }
+
+ /// Returns a nullable version of [type]. The result would be equivalent to
+ /// the union `type | Null` (if we supported union types).
+ DartType makeNullable(TypeImpl type) {
+ // TODO(paulberry): handle type parameter types
+ return type.withNullability(NullabilitySuffix.question);
+ }
+
+ /// Attempts to find the appropriate substitution for the [mixinElement]
+ /// type parameters that can be applied to [srcTypes] to make it equal to
+ /// [destTypes]. If no such substitution can be found, `null` is returned.
+ List<DartType> matchSupertypeConstraints(
+ ClassElement mixinElement,
+ List<DartType> srcTypes,
+ List<DartType> destTypes,
+ ) {
+ var typeParameters = mixinElement.typeParameters;
+ var inferrer = GenericInferrer(this, typeParameters);
+ for (int i = 0; i < srcTypes.length; i++) {
+ inferrer.constrainReturnType(srcTypes[i], destTypes[i]);
+ inferrer.constrainReturnType(destTypes[i], srcTypes[i]);
+ }
+
+ var inferredTypes = inferrer.infer(
+ typeParameters,
+ considerExtendsClause: false,
+ );
+ var substitution = Substitution.fromPairs(typeParameters, inferredTypes);
+
+ for (int i = 0; i < srcTypes.length; i++) {
+ var srcType = substitution.substituteType(srcTypes[i]);
+ var destType = destTypes[i];
+ if (isNonNullableByDefault) {
+ // TODO(scheglov) waiting for the spec
+ // https://github.com/dart-lang/sdk/issues/42605
+ } else {
+ srcType = toLegacyType(srcType);
+ destType = toLegacyType(destType);
+ }
+ if (srcType != destType) {
+ // Failed to find an appropriate substitution
+ return null;
+ }
+ }
+
+ return inferredTypes;
+ }
+
/// Compute the canonical representation of [T].
///
/// https://github.com/dart-lang/language
@@ -1369,7 +1189,45 @@
return NormalizeHelper(this).normalize(T);
}
+ /// Returns a non-nullable version of [type]. This is equivalent to the
+ /// operation `NonNull` defined in the spec.
@override
+ DartType promoteToNonNull(DartType type) {
+ if (type.isDartCoreNull) return NeverTypeImpl.instance;
+
+ if (type is TypeParameterTypeImpl) {
+ var element = type.element;
+
+ // NonNull(X & T) = X & NonNull(T)
+ if (type.promotedBound != null) {
+ var promotedBound = promoteToNonNull(type.promotedBound);
+ return TypeParameterTypeImpl(
+ element: element,
+ nullabilitySuffix: NullabilitySuffix.none,
+ promotedBound: promotedBound,
+ );
+ }
+
+ // NonNull(X) = X & NonNull(B), where B is the bound of X
+ var promotedBound = element.bound != null
+ ? promoteToNonNull(element.bound)
+ : typeProvider.objectType;
+ if (identical(promotedBound, element.bound)) {
+ promotedBound = null;
+ }
+ return TypeParameterTypeImpl(
+ element: element,
+ nullabilitySuffix: NullabilitySuffix.none,
+ promotedBound: promotedBound,
+ );
+ }
+
+ return (type as TypeImpl).withNullability(NullabilitySuffix.none);
+ }
+
+ /// Determine the type of a binary expression with the given [operator] whose
+ /// left operand has the type [leftType] and whose right operand has the type
+ /// [rightType], given that resolution has so far produced the [currentType].
DartType refineBinaryExpressionType(DartType leftType, TokenType operator,
DartType rightType, DartType currentType, MethodElement operatorElement) {
if (isNonNullableByDefault) {
@@ -1382,7 +1240,11 @@
}
}
- @override
+ /// Determines the context type for the parameters of a method invocation
+ /// where the type of the target is [targetType], the method being invoked is
+ /// [methodElement], the context surrounding the method invocation is
+ /// [invocationContext], and the context type produced so far by resolution is
+ /// [currentType].
DartType refineNumericInvocationContext(DartType targetType,
Element methodElement, DartType invocationContext, DartType currentType) {
if (methodElement is MethodElement && isNonNullableByDefault) {
@@ -1394,7 +1256,12 @@
}
}
- @override
+ /// Determines the type of a method invocation where the type of the target is
+ /// [targetType], the method being invoked is [methodElement], the types of
+ /// the arguments passed to the method are [argumentTypes], and the type
+ /// produced so far by resolution is [currentType].
+ ///
+ /// TODO(scheglov) I expected that [methodElement] is [MethodElement].
DartType refineNumericInvocationType(
DartType targetType,
Element methodElement,
@@ -1430,6 +1297,35 @@
}
}
+ @override
+ DartType resolveToBound(DartType type) {
+ if (type is TypeParameterTypeImpl) {
+ var element = type.element;
+
+ var bound = element.bound;
+ if (bound == null) {
+ return typeProvider.objectType;
+ }
+
+ NullabilitySuffix nullabilitySuffix = type.nullabilitySuffix;
+ NullabilitySuffix newNullabilitySuffix;
+ if (nullabilitySuffix == NullabilitySuffix.question ||
+ bound.nullabilitySuffix == NullabilitySuffix.question) {
+ newNullabilitySuffix = NullabilitySuffix.question;
+ } else if (nullabilitySuffix == NullabilitySuffix.star ||
+ bound.nullabilitySuffix == NullabilitySuffix.star) {
+ newNullabilitySuffix = NullabilitySuffix.star;
+ } else {
+ newNullabilitySuffix = NullabilitySuffix.none;
+ }
+
+ var resolved = resolveToBound(bound) as TypeImpl;
+ return resolved.withNullability(newNullabilitySuffix);
+ }
+
+ return type;
+ }
+
/// Return `true` if runtime types [T1] and [T2] are equal.
///
/// nnbd/feature-specification.md#runtime-type-equality-operator
@@ -1437,6 +1333,11 @@
return RuntimeTypeEqualityHelper(this).equal(T1, T2);
}
+ DartType toLegacyType(DartType type) {
+ if (isNonNullableByDefault) return type;
+ return NullabilityEliminator.perform(typeProvider, type);
+ }
+
/// Merges two types into a single type.
/// Compute the canonical representation of [T].
///
@@ -1447,7 +1348,8 @@
return TopMergeHelper(this).topMerge(T, S);
}
- @override
+ /// Tries to promote from the first type from the second type, and returns the
+ /// promoted type if it succeeds, otherwise null.
DartType tryPromoteToType(DartType to, DartType from) {
// Allow promoting to a subtype, for example:
//
@@ -1478,6 +1380,21 @@
return null;
}
+ /// Given a [DartType] type, return the [TypeParameterElement]s corresponding
+ /// to its formal type parameters (if any).
+ ///
+ /// @param type the type whose type arguments are to be returned
+ /// @return the type arguments associated with the given type
+ List<TypeParameterElement> typeFormalsAsElements(DartType type) {
+ if (type is FunctionType) {
+ return type.typeFormals;
+ } else if (type is InterfaceType) {
+ return type.element.typeParameters;
+ } else {
+ return const <TypeParameterElement>[];
+ }
+ }
+
void updateOptions({
@required bool implicitCasts,
@required bool strictInference,
@@ -1785,6 +1702,30 @@
// No special rules apply.
return currentType;
}
+
+ /// Starting from the given [type], search its class hierarchy for types of
+ /// the form Future<R>, and return a list of the resulting R's.
+ List<DartType> _searchTypeHierarchyForFutureTypeParameters(DartType type) {
+ List<DartType> result = <DartType>[];
+ HashSet<ClassElement> visitedClasses = HashSet<ClassElement>();
+ void recurse(InterfaceTypeImpl type) {
+ if (type.isDartAsyncFuture && type.typeArguments.isNotEmpty) {
+ result.add(type.typeArguments[0]);
+ }
+ if (visitedClasses.add(type.element)) {
+ if (type.superclass != null) {
+ recurse(type.superclass);
+ }
+ for (InterfaceType interface in type.interfaces) {
+ recurse(interface);
+ }
+ visitedClasses.remove(type.element);
+ }
+ }
+
+ recurse(type);
+ return result;
+ }
}
class _TypeVariableEliminator extends Substitution {
diff --git a/tools/VERSION b/tools/VERSION
index 5f4d7c5..e081728 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 2
MINOR 10
PATCH 0
-PRERELEASE 119
+PRERELEASE 120
PRERELEASE_PATCH 0
\ No newline at end of file