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