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 efe8e16908058e96ff4e52722307a6c4231b19b2..d9e66c67457982a585a9b41e4991ca3111d3c74c 100644 |
| --- a/pkg/analyzer/lib/src/generated/type_system.dart |
| +++ b/pkg/analyzer/lib/src/generated/type_system.dart |
| @@ -207,6 +207,7 @@ class StrongTypeSystemImpl extends TypeSystem { |
| List<DartType> correspondingParameterTypes, |
| List<DartType> argumentTypes, |
| DartType returnContextType) { |
| + |
| if (fnType.typeFormals.isEmpty) { |
| return fnType; |
| } |
| @@ -218,23 +219,6 @@ class StrongTypeSystemImpl extends TypeSystem { |
| var inferringTypeSystem = |
| new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals); |
| - // Special case inference for Future.then. |
| - // |
| - // We don't have union types, so Future<T>.then<S> is typed to take a |
| - // callback `T -> S`. However, the lambda might actually return a |
| - // Future<S>. So we handle that special case here. |
| - if (argumentTypes.isNotEmpty && argumentTypes[0] is FunctionType) { |
| - Element element = fnType?.element; |
| - bool isFutureThen = element is MethodElement && |
| - element.name == 'then' && |
| - element.enclosingElement.type.isDartAsyncFuture; |
| - if (isFutureThen) { |
| - // Ignore return context. We'll let the onValue function's return type |
| - // drive inference. |
| - returnContextType = null; |
| - } |
| - } |
| - |
| if (returnContextType != null) { |
| inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); |
| } |
| @@ -690,9 +674,13 @@ class StrongTypeSystemImpl extends TypeSystem { |
| return true; |
| } |
| - // The types are void, dynamic, bottom, interface types, function types |
| - // and type parameters. We proceed by eliminating these different classes |
| - // from consideration. |
| + // The types are void, dynamic, bottom, interface types, function types, |
| + // and type parameters. |
| + // |
| + // Union types can also arise in some cases relating to the Future type |
|
Leaf
2016/08/05 22:32:35
Is this vestigial? I don't see any new code to ha
Jennifer Messerly
2016/08/08 21:59:26
Eeeek, good catch, done!
(yes for a while I had t
|
| + // (T | Future<T> for some T). |
| + // |
| + // We proceed by eliminating these different classes from consideration. |
| // Trivially true. |
| if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
| @@ -1269,6 +1257,28 @@ class TypeSystemImpl extends TypeSystem { |
| } |
| /// Tracks upper and lower type bounds for a set of type parameters. |
| +/// |
| +/// This class is used by calling [isSubtypeOf]. When it encounters one of |
| +/// the type parameters it is inferring, it will record the constraint, and |
| +/// optimistically assume the constraint will be satisfied. |
| +/// |
| +/// For example if we are inferring type parameter A, and we ask if |
| +/// `A <: num`, this will record that A must be a subytpe of `num`. It also |
| +/// handles cases when A appears as part of the structure of another type, for |
| +/// example `Iterable<A> <: Iterable<num>` would infer the same constraint |
| +/// (due to covariant generic types) as would `() -> A <: () -> int`. In |
| +/// contrast `(A) -> void <: (num) -> void`. |
| +/// |
| +/// Once the lower/upper bounds are determined, [_infer] should be called to |
| +/// finish the inference. It will instantiate a generic function type with the |
| +/// inferred types for each type parameter. |
| +/// |
| +/// It can also optionally compute a partial solution, in case some of the type |
| +/// parameters could not be inferred (because the constraints cannot be |
| +/// satisfied), or bail on the inference when this happens. |
| +/// |
| +/// As currently designed, an instance of this class should only be used to |
| +/// infer a single call and discarded immediately afterwards. |
| class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { |
| final TypeProvider _typeProvider; |
| @@ -1506,3 +1516,72 @@ class _TypeParameterVariance { |
| } |
| } |
| } |
| + |
| +/** |
| + * This is a marker interface for [DartType] and [FutureUnionTypeContext]. |
| + * |
| + * Both of those types are valid context types in strong mode's type inference. |
| + */ |
| +abstract class TypeContext {} |
| + |
| +/** |
| + * A special union type of `Future<T> | T` used for Strong Mode inference. |
| + */ |
| +class FutureUnionTypeContext implements TypeContext { |
| + |
| + // TODO(jmesserly): a Set would be better. |
| + // |
| + // For now we know `Future<T> | T` is the only valid use, so we can rely on |
| + // the order, which simplifies some things. |
| + // |
| + // This will need clean up before this can function as a real union type. |
| + final List<DartType> types; |
| + |
| + @override |
| + String toString() { |
| + var buffer = new StringBuffer(); |
| + buffer.write('('); |
| + for (int i = 0; i < types.length; i++) { |
| + if (i != 0) { |
| + buffer.write(' | '); |
| + } |
| + (types[i] as TypeImpl).appendTo(buffer); |
| + } |
| + buffer.write(')'); |
| + return buffer.toString(); |
| + } |
| + |
| + |
| + /** |
| + * Creates a union of `Future< flatten(T) > | flatten(T)`. |
| + */ |
| + factory FutureUnionTypeContext( |
| + DartType type, TypeProvider provider, TypeSystem system) { |
| + type = type.flattenFutures(system); |
| + |
| + // The order of these types is important: T could be a type variable, so |
| + // we want to try and match `Future<T>` before we try and match `T`. |
| + return new FutureUnionTypeContext._([ |
| + provider.futureType.instantiate([type]), |
| + type |
| + ]); |
| + } |
| + |
| + FutureUnionTypeContext._(this.types); |
| + |
| + DartType get futureOfType => types[0]; |
| + |
| + DartType get type => types[1]; |
| + |
| + /** |
| + * Creates a union of `T | Future<T>`, unless `T` is already a future-union, |
| + * in which case it simply returns `T` |
| + */ |
| + static FutureUnionTypeContext from( |
| + TypeContext type, TypeProvider provider, TypeSystem system) { |
| + if (type is FutureUnionTypeContext) { |
| + return type; |
| + } |
| + return new FutureUnionTypeContext(type as DartType, provider, system); |
| + } |
| +} |