anchor.diff:      }
     }
   
  -  /// Apply a return type constraint, which asserts that the [declaredType]
  -  /// is a subtype of the [contextType].
  -  void constrainReturnType(DartType declaredType, DartType contextType) {
  -    var origin = new _TypeConstraintFromReturnType(declaredType, contextType);
  -    _matchSubtypeOf(declaredType, contextType, null, origin, covariant: true);
  -  }
  -
  -  /// Constrain a universal function type [fnType] used in a context
  -  /// [contextType].
  -  void constrainGenericFunctionInContext(
  -      FunctionType fnType, DartType contextType) {
  -    var origin = new _TypeConstraintFromFunctionContext(fnType, contextType);
  -
  -    // Since we're trying to infer the instantiation, we want to ignore type
  -    // formals as we check the parameters and return type.
  -    var inferFnType =
  -        fnType.instantiate(TypeParameterTypeImpl.getTypes(fnType.typeFormals));
  -    _matchSubtypeOf(inferFnType, contextType, null, origin, covariant: true);
  -  }
  -
     /// Apply an argument constraint, which asserts that the [argument] staticType
     /// is a subtype of the [parameterType].
     void constrainArgument(
  
positive.code:       }
      }
      return result;
    }
  
    DartType _inferTypeParameterFromContext(
        Iterable<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
      DartType t = _chooseTypeFromConstraints(constraints);
      if (UnknownInferredType.isUnknown(t)) {
        return t;
      }
  
      // If we're about to make our final choice, apply the extends clause.
      // This gives us a chance to refine the choice, in case it would violate
      // the `extends` clause. For example:
      //
      //     Object obj = math.min/*<infer Object, error>*/(1, 2);
      //
      // If we consider the `T extends num` we conclude `<num>`, which works.
      if (extendsClause != null) {
        constraints = constraints.toList()..add(extendsClause);
        return _chooseTypeFromConstraints(constraints);
      }
      return t;
    }
  
    DartType _inferTypeParameterFromAll(
        List<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
      // See if we already fixed this type from downwards inference.
      // If so, then we aren't allowed to change it based on argument types.
      DartType t = _inferTypeParameterFromContext(
          constraints.where((c) => c.isDownwards), extendsClause);
      if (UnknownInferredType.isKnown(t)) {
        // Remove constraints that aren't downward ones; we'll ignore these for
        // error reporting, because inference already succeeded.
        constraints.removeWhere((c) => !c.isDownwards);
        return t;
      }
  
      if (extendsClause != null) {
        constraints = constraints.toList()..add(extendsClause);
      }
  
      var choice = _chooseTypeFromConstraints(constraints, toKnownType: true);
      return choice;
    }
  
    /// Choose the bound that was implied by the return type, if any.
  
negative.code:     return result;
    }
  
    DartType _inferTypeParameterFromAll(
        List<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
      // See if we already fixed this type from downwards inference.
      // If so, then we aren't allowed to change it based on argument types.
      DartType t = _inferTypeParameterFromContext(
          constraints.where((c) => c.isDownwards), extendsClause);
      if (UnknownInferredType.isKnown(t)) {
        // Remove constraints that aren't downward ones; we'll ignore these for
        // error reporting, because inference already succeeded.
        constraints.removeWhere((c) => !c.isDownwards);
        return t;
      }
  
      if (extendsClause != null) {
        constraints = constraints.toList()..add(extendsClause);
      }
  
      var choice = _chooseTypeFromConstraints(constraints, toKnownType: true);
      return choice;
    }
  
    DartType _inferTypeParameterFromContext(
        Iterable<_TypeConstraint> constraints, _TypeConstraint extendsClause) {
      DartType t = _chooseTypeFromConstraints(constraints);
      if (UnknownInferredType.isUnknown(t)) {
        return t;
      }
  
      // If we're about to make our final choice, apply the extends clause.
      // This gives us a chance to refine the choice, in case it would violate
      // the `extends` clause. For example:
      //
      //     Object obj = math.min/*<infer Object, error>*/(1, 2);
      //
      // If we consider the `T extends num` we conclude `<num>`, which works.
      if (extendsClause != null) {
        constraints = constraints.toList()..add(extendsClause);
        return _chooseTypeFromConstraints(constraints);
      }
      return t;
    }
  
    void _matchInterfaceSubtypeOf(InterfaceType i1, InterfaceType i2,
        Set<Element> visited, _TypeConstraintOrigin origin,
        {bool covariant}) {
      if (identical(i1, i2)) {
        return;
      }
  
      if (i1.element == i2.element) {
        List<DartType> tArgs1 = i1.typeArguments;
        List<DartType> tArgs2 = i2.typeArguments;
        assert(tArgs1.length == tArgs2.length);
        for (int i = 0; i < tArgs1.length; i++) {
          _matchSubtypeOf(tArgs1[i], tArgs2[i], visited, origin,
              covariant: covariant);
        }
        return;
      }
      if (i2.isDartCoreFunction && i1.element.getMethod("call") != null) {
        return;
      }
      if (i1.isObject) {
        return;
      }
  
      // Guard against loops in the class hierarchy
      void guardedInterfaceSubtype(InterfaceType t1) {
        var visitedSet = visited ?? new HashSet<Element>();
        if (visitedSet.add(t1.element)) {
          _matchInterfaceSubtypeOf(t1, i2, visited, origin, covariant: covariant);
          visitedSet.remove(t1.element);
        }
      }
  
      guardedInterfaceSubtype(i1.superclass);
      for (final parent in i1.interfaces) {
        guardedInterfaceSubtype(parent);
      }
      for (final parent in i1.mixins) {
        guardedInterfaceSubtype(parent);
      }
    }
  
    /// Assert that [t1] will be a subtype of [t2], and returns if the constraint
    /// can be satisfied.
    ///
    /// [covariant] must be true if [t1] is a declared type of the generic
    /// function and [t2] is the context type, or false if the reverse. For
    /// example [covariant] is used when [t1] is the declared return type
    /// and [t2] is the context type. Contravariant would be used if [t1] is the
    /// argument type (i.e. passed in to the generic function) and [t2] is the
    /// declared parameter type.
    ///
    /// [origin] indicates where the constraint came from, for example an argument
    /// or return type.
    void _matchSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
        _TypeConstraintOrigin origin,
        {bool covariant, bool dynamicIsBottom: false}) {
      // TODO(jmesserly): I think we should handle `dynamicIsBottom`
      // https://github.com/dart-lang/sdk/issues/29041
      if (covariant && t1 is TypeParameterType) {
        var constraints = _constraints[t1.element];
        if (constraints != null) {
          if (!identical(t2, UnknownInferredType.instance)) {
            constraints.add(new _TypeConstraint(origin, t1, upper: t2));
            _constraintCount++;
          }
          return;
        }
      }
      if (!covariant && t2 is TypeParameterType) {
        var constraints = _constraints[t2.element];
        if (constraints != null) {
          if (!identical(t1, UnknownInferredType.instance)) {
            constraints.add(new _TypeConstraint(origin, t2, lower: t1));
            _constraintCount++;
          }
          return;
        }
      }
  
      if (identical(t1, t2)) {
        return;
      }
  
      // TODO(jmesserly): this logic is taken from subtype.
      void matchSubtype(DartType t1, DartType t2) {
        _matchSubtypeOf(t1, t2, null, origin, covariant: covariant);
      }
  
      // Handle FutureOr<T> union type.
      if (t1 is InterfaceType && t1.isDartAsyncFutureOr) {
        var t1TypeArg = t1.typeArguments[0];
        if (t2 is InterfaceType && t2.isDartAsyncFutureOr) {
          var t2TypeArg = t2.typeArguments[0];
          // FutureOr<A> <: FutureOr<B> iff A <: B
          matchSubtype(t1TypeArg, t2TypeArg);
          return;
        }
  
        // given t1 is Future<A> | A, then:
        // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
        var t1Future = typeProvider.futureType.instantiate([t1TypeArg]);
        matchSubtype(t1Future, t2);
        matchSubtype(t1TypeArg, t2);
        return;
      }
  
      if (t2 is InterfaceType && t2.isDartAsyncFutureOr) {
        // given t2 is Future<A> | A, then:
        // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
        var t2TypeArg = t2.typeArguments[0];
        var t2Future = typeProvider.futureType.instantiate([t2TypeArg]);
  
        int constraintCount = _constraintCount;
        matchSubtype(t1, t2Future);
  
        // We only want to record these as "or" constraints, so if we matched
        // the `t1 <: Future<A>` constraint, don't add `t1 <: A` constraint, as
        // that would be interpreted incorrectly as `t1 <: Future<A> && t1 <: A`.
        if (constraintCount == _constraintCount) {
          matchSubtype(t1, t2TypeArg);
        }
        return;
      }
  
      // S <: T where S is a type variable
      //  T is not dynamic or object (handled above)
      //  True if T == S
      //  Or true if bound of S is S' and S' <: T
  
      if (t1 is TypeParameterType) {
        // Guard against recursive type parameters
        void guardedSubtype(DartType t1, DartType t2) {
          var visitedSet = visited ?? new HashSet<Element>();
          if (visitedSet.add(t1.element)) {
            matchSubtype(t1, t2);
            visitedSet.remove(t1.element);
          }
        }
  
        if (t2 is TypeParameterType && t1.definition == t2.definition) {
          guardedSubtype(t1.bound, t2.bound);
          return;
        }
        guardedSubtype(t1.bound, t2);
        return;
      }
      if (t2 is TypeParameterType) {
        return;
      }
  
      if (t1 is InterfaceType && t2 is InterfaceType) {
        _matchInterfaceSubtypeOf(t1, t2, visited, origin, covariant: covariant);
        return;
      }
  
      // An interface type can only subtype a function type if
      // the interface type declares a call method with a type
      // which is a super type of the function type.
      if (t1 is InterfaceType) {
        t1 = _typeSystem.getCallMethodDefiniteType(t1);
        if (t1 == null) return;
      }
  
      if (t1 is FunctionType && t2 is FunctionType) {
        FunctionTypeImpl.relate(
            t1,
            t2,
            (t1, t2, _, __) {
              _matchSubtypeOf(t2, t1, null, origin,
                  covariant: !covariant, dynamicIsBottom: true);
              return true;
            },
            _typeSystem.instantiateToBounds,
            returnRelation: (t1, t2) {
              matchSubtype(t1, t2);
              return true;
            });
      }
    }
  
    static String _formatConstraints(Iterable<_TypeConstraint> constraints) {
  