anchor.diff:    }
   }
   
  +/**
  + * Base class for testing LUB and GLB in spec and strong mode.
  + */
  +abstract class BoundTestBase {
  +  TypeProvider typeProvider;
  +  Dart2TypeSystem typeSystem;
  +  FunctionType simpleFunctionType;
  +
  +  DartType get bottomType => typeProvider.bottomType;
  +  InterfaceType get doubleType => typeProvider.doubleType;
  +  DartType get dynamicType => typeProvider.dynamicType;
  +  InterfaceType get functionType => typeProvider.functionType;
  +  InterfaceType get futureOrType => typeProvider.futureOrType;
  +  InterfaceType get intType => typeProvider.intType;
  +  InterfaceType get iterableType => typeProvider.iterableType;
  +  InterfaceType get listType => typeProvider.listType;
  +  InterfaceType get nullType => typeProvider.nullType;
  +  InterfaceType get numType => typeProvider.numType;
  +  InterfaceType get objectType => typeProvider.objectType;
  +  InterfaceType get stringType => typeProvider.stringType;
  +
  +  DartType get voidType => VoidTypeImpl.instance;
  +
  +  void setUp() {
  +    InternalAnalysisContext context = AnalysisContextFactory.contextWithCore(
  +        resourceProvider: new MemoryResourceProvider());
  +    typeProvider = context.typeProvider;
  +    var simpleFunctionElement =
  +        ElementFactory.genericTypeAliasElement('A', returnType: voidType);
  +    simpleFunctionType = simpleFunctionElement.type;
  +  }
  +
  +  void _checkGreatestLowerBound(
  +      DartType type1, DartType type2, DartType expectedResult) {
  +    DartType glb = typeSystem.getGreatestLowerBound(type1, type2);
  +    expect(glb, expectedResult);
  +    // Check that the result is a lower bound.
  +    expect(typeSystem.isSubtypeOf(glb, type1), true);
  +    expect(typeSystem.isSubtypeOf(glb, type2), true);
  +    // Check for symmetry while we're at it.  Unfortunately,
  +    // for function types, the current version of equality
  +    // does not respect re-ordering of named parameters, so
  +    // for function types we just check if they are mutual subtypes.
  +    // https://github.com/dart-lang/sdk/issues/26126
  +    // TODO(leafp): Fix this.
  +    glb = typeSystem.getGreatestLowerBound(type2, type1);
  +    if (glb is FunctionTypeImpl) {
  +      expect(typeSystem.isSubtypeOf(glb, expectedResult), true);
  +      expect(typeSystem.isSubtypeOf(expectedResult, glb), true);
  +    } else {
  +      expect(glb, expectedResult);
  +    }
  +  }
  +
  +  void _checkLeastUpperBound(
  +      DartType type1, DartType type2, DartType expectedResult) {
  +    DartType lub = typeSystem.getLeastUpperBound(type1, type2);
  +    expect(lub, expectedResult);
  +    // Check that the result is an upper bound.
  +    expect(typeSystem.isSubtypeOf(type1, lub), true);
  +    expect(typeSystem.isSubtypeOf(type2, lub), true);
  +
  +    // Check for symmetry while we're at it.  Unfortunately,
  +    // for function types, the current version of equality
  +    // does not respect re-ordering of named parameters, so
  +    // for function types we just check if they are mutual subtypes.
  +    // https://github.com/dart-lang/sdk/issues/26126
  +    // TODO(leafp): Fix this.
  +    lub = typeSystem.getLeastUpperBound(type2, type1);
  +    if (lub is FunctionTypeImpl) {
  +      expect(typeSystem.isSubtypeOf(lub, expectedResult), true);
  +      expect(typeSystem.isSubtypeOf(expectedResult, lub), true);
  +    } else {
  +      expect(lub, expectedResult);
  +    }
  +  }
  +
  +  /**
  +   * Creates a function type with the given parameter and return types.
  +   *
  +   * The return type defaults to `void` if omitted.
  +   */
  +  FunctionType _functionType(List<DartType> required,
  +      {List<DartType> optional,
  +      Map<String, DartType> named,
  +      DartType returns}) {
  +    if (returns == null) {
  +      returns = voidType;
  +    }
  +
  +    return ElementFactory.functionElement8(required, returns,
  +            optional: optional, named: named)
  +        .type;
  +  }
  +}
  +
   @reflectiveTest
  -class StrongGenericFunctionInferenceTest extends AbstractTypeSystemTest {
  +class ConstraintMatchingTest {
  +  TypeProvider typeProvider;
  +  TypeSystem typeSystem;
  +  TypeParameterType T;
  +
  +  DartType get dynamicType => DynamicTypeImpl.instance;
  +
  +  InterfaceType get functionType => typeProvider.functionType;
  +
  +  InterfaceType get intType => typeProvider.intType;
  +
  +  InterfaceType get nullType => typeProvider.nullType;
  +
  +  InterfaceType get objectType => typeProvider.objectType;
  +
  +  InterfaceType get stringType => typeProvider.stringType;
  +
  +  DartType get voidType => VoidTypeImpl.instance;
  +
  +  DartType fn(DartType paramType, DartType returnType) =>
  +      new FunctionElementImpl.synthetic([
  +        new ParameterElementImpl.synthetic(
  +            'value', paramType, ParameterKind.REQUIRED)
  +      ], returnType)
  +          .type;
  +
  +  DartType future(DartType T) => typeProvider.futureType.instantiate([T]);
  +
  +  DartType futureOr(DartType T) => typeProvider.futureOrType.instantiate([T]);
  +
  +  DartType iterable(DartType T) => typeProvider.iterableType.instantiate([T]);
  +
  +  DartType list(DartType T) => typeProvider.listType.instantiate([T]);
  +
  +  void setUp() {
  +    typeProvider = AnalysisContextFactory.contextWithCore(
  +            resourceProvider: new MemoryResourceProvider())
  +        .typeProvider;
  +    typeSystem = new Dart2TypeSystem(typeProvider);
  +    T = _newTypeParameter('T');
  +  }
  +
  +  void test_function_coreFunction() {
  +    _checkOrdinarySubtypeMatch(fn(intType, stringType), functionType, [T],
  +        covariant: true);
  +  }
  +
  +  void test_function_parameter_types() {
  +    _checkIsSubtypeMatchOf(
  +        fn(T, intType), fn(stringType, intType), [T], ['String <: T'],
  +        covariant: true);
  +  }
  +
  +  void test_function_return_types() {
  +    _checkIsSubtypeMatchOf(
  +        fn(intType, T), fn(intType, stringType), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_futureOr_futureOr() {
  +    _checkIsSubtypeMatchOf(
  +        futureOr(T), futureOr(stringType), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_futureOr_x_fail_future_branch() {
  +    // FutureOr<List<T>> <: List<String> can't be satisfied because
  +    // Future<List<T>> <: List<String> can't be satisfied
  +    _checkIsNotSubtypeMatchOf(futureOr(list(T)), list(stringType), [T],
  +        covariant: true);
  +  }
  +
  +  void test_futureOr_x_fail_nonFuture_branch() {
  +    // FutureOr<List<T>> <: Future<List<String>> can't be satisfied because
  +    // List<T> <: Future<List<String>> can't be satisfied
  +    _checkIsNotSubtypeMatchOf(futureOr(list(T)), future(list(stringType)), [T],
  +        covariant: true);
  +  }
  +
  +  void test_futureOr_x_success() {
  +    // FutureOr<T> <: Future<T> can be satisfied by T=Null.  At this point in
  +    // the type inference algorithm all we figure out is that T must be a
  +    // subtype of both String and Future<String>.
  +    _checkIsSubtypeMatchOf(futureOr(T), future(stringType), [T],
  +        ['T <: String', 'T <: Future<String>'],
  +        covariant: true);
  +  }
  +
  +  void test_lhs_null() {
  +    // Null <: T is trivially satisfied by the constraint Null <: T.
  +    _checkIsSubtypeMatchOf(nullType, T, [T], ['Null <: T'], covariant: false);
  +    // For any other type X, Null <: X is satisfied without the need for any
  +    // constraints.
  +    _checkOrdinarySubtypeMatch(nullType, list(T), [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, stringType, [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, voidType, [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, dynamicType, [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, objectType, [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, nullType, [T], covariant: false);
  +    _checkOrdinarySubtypeMatch(nullType, fn(intType, stringType), [T],
  +        covariant: false);
  +  }
  +
  +  void test_param_on_lhs_contravariant_direct() {
  +    // When doing a contravariant match, the type parameters we're trying to
  +    // find types for are on the right hand side.  Is a type parameter also
  +    // appears on the left hand side, there is a condition in which the
  +    // constraint can be satisfied without consulting the bound of the LHS type
  +    // parameter: the condition where both parameters appear at corresponding
  +    // locations in the type tree.
  +    //
  +    // In other words, List<S> <: List<T> is satisfied provided that
  +    // S <: T.
  +    var S = _newTypeParameter('S');
  +    _checkIsSubtypeMatchOf(list(S), list(T), [T], ['S <: T'], covariant: false);
  +  }
  +
  +  void test_param_on_lhs_contravariant_via_bound() {
  +    // When doing a contravariant match, the type parameters we're trying to
  +    // find types for are on the right hand side.  Is a type parameter also
  +    // appears on the left hand side, we may have to constrain the RHS type
  +    // parameter using the bounds of the LHS type parameter.
  +    //
  +    // In other words, S <: List<T> is satisfied provided that
  +    // bound(S) <: List<T>.
  +    var S = _newTypeParameter('S', list(stringType));
  +    _checkIsSubtypeMatchOf(S, list(T), [T], ['String <: T'], covariant: false);
  +  }
  +
  +  void test_param_on_lhs_covariant() {
  +    // When doing a covariant match, the type parameters we're trying to find
  +    // types for are on the left hand side.
  +    _checkIsSubtypeMatchOf(T, stringType, [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_param_on_rhs_contravariant() {
  +    // When doing a contravariant match, the type parameters we're trying to
  +    // find types for are on the right hand side.
  +    _checkIsSubtypeMatchOf(stringType, T, [T], ['String <: T'],
  +        covariant: false);
  +  }
  +
  +  void test_param_on_rhs_covariant_match() {
  +    // When doing a covariant match, the type parameters we're trying to find
  +    // types for are on the left hand side.  If a type parameter appears on the
  +    // right hand side, there is a condition in which the constraint can be
  +    // satisfied: where both parameters appear at corresponding locations in the
  +    // type tree.
  +    //
  +    // In other words, T <: S can be satisfied trivially by the constraint
  +    // T <: S.
  +    var S = _newTypeParameter('S');
  +    _checkIsSubtypeMatchOf(T, S, [T], ['T <: S'], covariant: true);
  +  }
  +
  +  void test_param_on_rhs_covariant_no_match() {
  +    // When doing a covariant match, the type parameters we're trying to find
  +    // types for are on the left hand side.  If a type parameter appears on the
  +    // right hand side, it's probable that the constraint can't be satisfied,
  +    // because there is no possible type for the LHS (other than bottom)
  +    // that's guaranteed to satisfy the relation for all possible assignments of
  +    // the RHS type parameter.
  +    //
  +    // In other words, no match can be found for List<T> <: S because regardless
  +    // of T, we can't guarantee that List<T> <: S for all S.
  +    var S = _newTypeParameter('S');
  +    _checkIsNotSubtypeMatchOf(list(T), S, [T], covariant: true);
  +  }
  +
  +  void test_related_interface_types_failure() {
  +    _checkIsNotSubtypeMatchOf(iterable(T), list(stringType), [T],
  +        covariant: true);
  +  }
  +
  +  void test_related_interface_types_success() {
  +    _checkIsSubtypeMatchOf(list(T), iterable(stringType), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_rhs_dynamic() {
  +    // T <: dynamic is trivially satisfied by the constraint T <: dynamic.
  +    _checkIsSubtypeMatchOf(T, dynamicType, [T], ['T <: dynamic'],
  +        covariant: true);
  +    // For any other type X, X <: dynamic is satisfied without the need for any
  +    // constraints.
  +    _checkOrdinarySubtypeMatch(list(T), dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(stringType, dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(voidType, dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(dynamicType, dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(objectType, dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(nullType, dynamicType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(fn(intType, stringType), dynamicType, [T],
  +        covariant: true);
  +  }
  +
  +  void test_rhs_object() {
  +    // T <: Object is trivially satisfied by the constraint T <: Object.
  +    _checkIsSubtypeMatchOf(T, objectType, [T], ['T <: Object'],
  +        covariant: true);
  +    // For any other type X, X <: Object is satisfied without the need for any
  +    // constraints.
  +    _checkOrdinarySubtypeMatch(list(T), objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(stringType, objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(voidType, objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(dynamicType, objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(objectType, objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(nullType, objectType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(fn(intType, stringType), objectType, [T],
  +        covariant: true);
  +  }
  +
  +  void test_rhs_void() {
  +    // T <: void is trivially satisfied by the constraint T <: void.
  +    _checkIsSubtypeMatchOf(T, voidType, [T], ['T <: void'], covariant: true);
  +    // For any other type X, X <: void is satisfied without the need for any
  +    // constraints.
  +    _checkOrdinarySubtypeMatch(list(T), voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(stringType, voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(voidType, voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(dynamicType, voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(objectType, voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(nullType, voidType, [T], covariant: true);
  +    _checkOrdinarySubtypeMatch(fn(intType, stringType), voidType, [T],
  +        covariant: true);
  +  }
  +
  +  void test_same_interface_types() {
  +    _checkIsSubtypeMatchOf(list(T), list(stringType), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_x_futureOr_fail_both_branches() {
  +    // List<T> <: FutureOr<String> can't be satisfied because neither
  +    // List<T> <: Future<String> nor List<T> <: int can be satisfied
  +    _checkIsNotSubtypeMatchOf(list(T), futureOr(stringType), [T],
  +        covariant: true);
  +  }
  +
  +  void test_x_futureOr_pass_both_branches_constraints_from_both_branches() {
  +    // Future<String> <: FutureOr<T> can be satisfied because both
  +    // Future<String> <: Future<T> and Future<String> <: T can be satisfied.
  +    // Trying to match Future<String> <: Future<T> generates the constraint
  +    // String <: T, whereas trying to match Future<String> <: T generates the
  +    // constraint Future<String> <: T.  We keep the constraint based on trying
  +    // to match Future<String> <: Future<T>, so String <: T.
  +    _checkIsSubtypeMatchOf(
  +        future(stringType), futureOr(T), [T], ['String <: T'],
  +        covariant: false);
  +  }
  +
  +  void test_x_futureOr_pass_both_branches_constraints_from_future_branch() {
  +    // Future<T> <: FutureOr<Object> can be satisfied because both
  +    // Future<T> <: Future<Object> and Future<T> <: Object can be satisfied.
  +    // Trying to match Future<T> <: Future<Object> generates the constraint
  +    // T <: Object, whereas trying to match Future<T> <: Object generates no
  +    // constraints, so we keep the constraint T <: Object.
  +    _checkIsSubtypeMatchOf(
  +        future(T), futureOr(objectType), [T], ['T <: Object'],
  +        covariant: true);
  +  }
  +
  +  void test_x_futureOr_pass_both_branches_constraints_from_nonFuture_branch() {
  +    // Null <: FutureOr<T> can be satisfied because both
  +    // Null <: Future<T> and Null <: T can be satisfied.
  +    // Trying to match Null <: FutureOr<T> generates no constraints, whereas
  +    // trying to match Null <: T generates the constraint Null <: T,
  +    // so we keep the constraint Null <: T.
  +    _checkIsSubtypeMatchOf(nullType, futureOr(T), [T], ['Null <: T'],
  +        covariant: false);
  +  }
  +
  +  void test_x_futureOr_pass_both_branches_no_constraints() {
  +    // Future<String> <: FutureOr<Object> is satisfied because both
  +    // Future<String> <: Future<Object> and Future<String> <: Object.
  +    // No constraints are recorded.
  +    _checkIsSubtypeMatchOf(future(stringType), futureOr(objectType), [T], [],
  +        covariant: true);
  +  }
  +
  +  void test_x_futureOr_pass_future_branch() {
  +    // Future<T> <: FutureOr<String> can be satisfied because
  +    // Future<T> <: Future<String> can be satisfied
  +    _checkIsSubtypeMatchOf(
  +        future(T), futureOr(stringType), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void test_x_futureOr_pass_nonFuture_branch() {
  +    // List<T> <: FutureOr<List<String>> can be satisfied because
  +    // List<T> <: List<String> can be satisfied
  +    _checkIsSubtypeMatchOf(
  +        list(T), futureOr(list(stringType)), [T], ['T <: String'],
  +        covariant: true);
  +  }
  +
  +  void _checkIsNotSubtypeMatchOf(
  +      DartType t1, DartType t2, Iterable<TypeParameterType> typeFormals,
  +      {bool covariant}) {
  +    var inferrer = new GenericInferrer(
  +        typeProvider, typeSystem, typeFormals.map((t) => t.element));
  +    var success =
  +        inferrer.tryMatchSubtypeOf(t1, t2, null, covariant: covariant);
  +    expect(success, isFalse);
  +    inferrer.constraints.forEach((typeParameter, constraintsForTypeParameter) {
  +      expect(constraintsForTypeParameter, isEmpty);
  +    });
  +  }
  +
  +  void _checkIsSubtypeMatchOf(
  +      DartType t1,
  +      DartType t2,
  +      Iterable<TypeParameterType> typeFormals,
  +      Iterable<String> expectedConstraints,
  +      {bool covariant}) {
  +    var inferrer = new GenericInferrer(
  +        typeProvider, typeSystem, typeFormals.map((t) => t.element));
  +    var success =
  +        inferrer.tryMatchSubtypeOf(t1, t2, null, covariant: covariant);
  +    expect(success, isTrue);
  +    var formattedConstraints = <String>[];
  +    inferrer.constraints.forEach((typeParameter, constraintsForTypeParameter) {
  +      for (var constraint in constraintsForTypeParameter) {
  +        formattedConstraints.add(constraint.format(typeParameter.toString()));
  +      }
  +    });
  +    expect(formattedConstraints, unorderedEquals(expectedConstraints));
  +  }
  +
  +  void _checkOrdinarySubtypeMatch(
  +      DartType t1, DartType t2, Iterable<TypeParameterType> typeFormals,
  +      {bool covariant}) {
  +    bool expectSuccess = typeSystem.isSubtypeOf(t1, t2);
  +    if (expectSuccess) {
  +      _checkIsSubtypeMatchOf(t1, t2, typeFormals, [], covariant: covariant);
  +    } else {
  +      _checkIsNotSubtypeMatchOf(t1, t2, typeFormals);
  +    }
  +  }
  +
  +  TypeParameterType _newTypeParameter(String name, [DartType bound]) {
  +    var element = new TypeParameterElementImpl(name, 0);
  +    if (bound != null) {
  +      element.bound = bound;
  +    }
  +    return new TypeParameterTypeImpl(element);
  +  }
  +}
  +
  +@reflectiveTest
  +class GenericFunctionInferenceTest extends AbstractTypeSystemTest {
     void test_boundedByAnotherTypeParameter() {
       // <TFrom, TTo extends Iterable<TFrom>>(TFrom) -> TTo
       var tFrom = TypeBuilder.variable('TFrom');
  
positive.code:   }
  }
  
  /**
   * Tests GLB, which only exists in strong mode.
   */
  @reflectiveTest
  class StrongGreatestLowerBoundTest extends BoundTestBase {
    void setUp() {
      super.setUp();
      typeSystem = new Dart2TypeSystem(typeProvider);
  
negative.code:     // TODO(leafp): this should be iterableOfNumType
      _checkLeastUpperBound(listOfIntType, iterableOfDoubleType, objectType);
    }
  
    void test_void() {
      List<DartType> types = [
        bottomType,
        simpleFunctionType,
        ElementFactory.classElement2('A', []).type,
        ElementFactory.typeParameterElement('T').type
      ];
      for (DartType type in types) {
        _checkLeastUpperBound(
            _functionType([], returns: voidType),
            _functionType([], returns: type),
            _functionType([], returns: voidType));
      }
    }
  }
  
  @reflectiveTest
  class NonNullableSubtypingTest extends SubtypingTestBase {
    @override
    void setUp() {
      typeProvider = AnalysisContextFactory.contextWithCoreAndOptions(
              new AnalysisOptionsImpl()
                ..contextFeatures = FeatureSet.forTesting(
                    additionalFeatures: [Feature.non_nullable]),
              resourceProvider: new MemoryResourceProvider())
          .typeProvider;
  
      // TypeSystem should use the context type provider.
      typeSystem = new Dart2TypeSystem(typeProvider);
  
      LibraryElement coreLibrary = typeProvider.objectType.element.library;
      LibraryElement asyncLibrary = typeProvider.streamType.element.library;
  
      // Get a non-nullable type provider for convience during the test.
      typeProvider = new NonNullableTypeProvider(coreLibrary, asyncLibrary);
    }
  
    void test_int_nullableTypes() {
      List<DartType> equivalents = <DartType>[
        intType,
        _star(intType),
      ];
      List<DartType> supertypes = <DartType>[
        _question(intType),
        objectType,
        _question(objectType),
      ];
      List<DartType> unrelated = <DartType>[doubleType, nullType];
      _checkGroups(intType,
          equivalents: equivalents, supertypes: supertypes, unrelated: unrelated);
    }
  
    void test_intQuestion_nullableTypes() {
      List<DartType> equivalents = <DartType>[
        _question(intType),
        _star(intType),
      ];
      List<DartType> subtypes = <DartType>[
        intType,
        nullType,
      ];
      List<DartType> supertypes = <DartType>[
        _question(numType),
        _star(numType),
        _question(objectType),
        _star(objectType),
      ];
      List<DartType> unrelated = <DartType>[doubleType, numType, objectType];
      _checkGroups(_question(intType),
          equivalents: equivalents,
          supertypes: supertypes,
          unrelated: unrelated,
          subtypes: subtypes);
    }
  
    void test_intStar_nullableTypes() {
      List<DartType> equivalents = <DartType>[
        intType,
        _question(intType),
        _star(intType),
      ];
      List<DartType> subtypes = <DartType>[nullType];
      List<DartType> supertypes = <DartType>[
        numType,
        _question(numType),
        _star(numType),
        objectType,
        _question(objectType),
      ];
      List<DartType> unrelated = <DartType>[doubleType];
      _checkGroups(_star(intType),
          equivalents: equivalents,
          supertypes: supertypes,
          unrelated: unrelated,
          subtypes: subtypes);
    }
  
    DartType _question(DartType dartType) =>
        (dartType as TypeImpl).withNullability(NullabilitySuffix.question);
  
    DartType _star(DartType dartType) =>
        (dartType as TypeImpl).withNullability(NullabilitySuffix.star);
  }
  
  @reflectiveTest
  class SubtypingTest extends SubtypingTestBase {
    void test_bottom_isBottom() {
      DartType interfaceType = ElementFactory.classElement2('A', []).type;
      List<DartType> equivalents = <DartType>[bottomType];
  