Chromium Code Reviews| Index: pkg/analyzer/lib/src/generated/type_system.dart | 
| diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart | 
| index 2b6012a4eb8e61022de5e507ac72e31364719341..f9e5e7d427611c40b255117cde2e97d8499a958c 100644 | 
| --- a/pkg/analyzer/lib/src/generated/type_system.dart | 
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart | 
| @@ -696,13 +696,6 @@ class StrongTypeSystemImpl extends TypeSystem { | 
| }; | 
| } | 
| - /// If [t1] or [t2] is a type parameter we are inferring, update its bound. | 
| - /// Returns `true` if we could possibly find a compatible type, | 
| - /// otherwise `false`. | 
| - bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) { | 
| - return false; | 
| - } | 
| - | 
| /** | 
| * This currently does not implement a very complete least upper bound | 
| * algorithm, but handles a couple of the very common cases that are | 
| @@ -840,28 +833,7 @@ class StrongTypeSystemImpl extends TypeSystem { | 
| // Trivially false. | 
| if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | 
| _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | 
| - return _inferTypeParameterSubtypeOf(t1, t2); | 
| - } | 
| - | 
| - // 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) { | 
| - if (t2 is TypeParameterType && | 
| - t1.definition == t2.definition && | 
| - guardedSubtype(t1.bound, t2.bound, visited)) { | 
| - return true; | 
| - } | 
| - if (_inferTypeParameterSubtypeOf(t1, t2)) { | 
| - return true; | 
| - } | 
| - DartType bound = t1.element.bound; | 
| - return bound == null ? false : guardedSubtype(bound, t2, visited); | 
| - } | 
| - | 
| - if (t2 is TypeParameterType) { | 
| - return _inferTypeParameterSubtypeOf(t1, t2); | 
| + return false; | 
| } | 
| // Handle FutureOr<T> union type. | 
| @@ -887,6 +859,23 @@ class StrongTypeSystemImpl extends TypeSystem { | 
| return isSubtypeOf(t1, t2Future) || isSubtypeOf(t1, t2TypeArg); | 
| } | 
| + // 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) { | 
| + if (t2 is TypeParameterType && | 
| + t1.definition == t2.definition && | 
| + guardedSubtype(t1.bound, t2.bound, visited)) { | 
| + return true; | 
| + } | 
| + DartType bound = t1.element.bound; | 
| + return bound == null ? false : guardedSubtype(bound, t2, visited); | 
| + } | 
| + if (t2 is TypeParameterType) { | 
| + return false; | 
| + } | 
| + | 
| // Void only appears as the return type of a function, and we handle it | 
| // directly in the function subtype rules. We should not get to a point | 
| // where we're doing a subtype test on a "bare" void, but just in case we | 
| @@ -1503,8 +1492,8 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { | 
| DartType declaredUpperBound = typeParam.element.bound; | 
| if (declaredUpperBound != null) { | 
| // Assert that the type parameter is a subtype of its bound. | 
| - _inferTypeParameterSubtypeOf(typeParam, | 
| - declaredUpperBound.substitute2(inferredTypes, fnTypeParams)); | 
| + _isSubtypeOf(typeParam, | 
| + declaredUpperBound.substitute2(inferredTypes, fnTypeParams), null); | 
| } | 
| // Now we've computed lower and upper bounds for each type parameter. | 
| @@ -1562,8 +1551,18 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { | 
| } | 
| @override | 
| - bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) { | 
| + bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | 
| + {bool dynamicIsBottom: false}) { | 
| + // TODO(jmesserly): to match old behavior, the trivial constraints are | 
| 
 
Leaf
2017/01/27 21:34:54
What's the thing to be done in in this TODO?
 
Jennifer Messerly
2017/01/27 22:39:19
it's not right once we pin based on downward const
 
 | 
| + // not treated as adding to the constraint set. | 
| + if (identical(t1, t2) || | 
| + _isTop(t2, dynamicIsBottom: dynamicIsBottom) || | 
| + _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | 
| + return true; | 
| + } | 
| + | 
| if (t1 is TypeParameterType) { | 
| + // TODO(jmesserly): we ignore `dynamicIsBottom` here, is that correct? | 
| _TypeParameterBound bound = _bounds[t1]; | 
| if (bound != null) { | 
| // Ensure T1 <: T2, where T1 is a type parameter we are inferring. | 
| @@ -1591,7 +1590,8 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { | 
| return true; | 
| } | 
| } | 
| - return false; | 
| + return super | 
| + ._isSubtypeOf(t1, t2, visited, dynamicIsBottom: dynamicIsBottom); | 
| } | 
| } |