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 78d246f91a1648b515b6a582df5978ee70eb5138..6fcb63b250af71a920bee403b6a0c2075905a09f 100644 |
--- a/pkg/analyzer/lib/src/generated/type_system.dart |
+++ b/pkg/analyzer/lib/src/generated/type_system.dart |
@@ -15,7 +15,9 @@ import 'package:analyzer/src/dart/element/type.dart'; |
import 'package:analyzer/src/generated/engine.dart' |
show AnalysisContext, AnalysisOptionsImpl; |
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
-import 'package:analyzer/src/generated/utilities_dart.dart'; |
+import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
+import 'package:analyzer/src/generated/utilities_general.dart' |
+ show JenkinsSmiHash; |
typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
@@ -282,23 +284,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); |
} |
@@ -751,8 +736,8 @@ 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 |
+ // The types are void, dynamic, bottom, interface types, function types, |
+ // and type parameters. We proceed by eliminating these different classes |
// from consideration. |
// Trivially true. |
@@ -1340,6 +1325,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 <: () -> num`. 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; |
@@ -1578,6 +1585,100 @@ class _TypeParameterVariance { |
} |
} |
+/** |
+ * A special union type of `Future<T> | T` used for Strong Mode inference. |
+ */ |
+class FutureUnionType extends TypeImpl { |
+ // 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; |
+ |
+ /** |
+ * Creates a union of `Future< flatten(T) > | flatten(T)`. |
+ */ |
+ factory FutureUnionType( |
+ 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 FutureUnionType._([ |
+ provider.futureType.instantiate([type]), |
+ type |
+ ]); |
+ } |
+ |
+ FutureUnionType._(this._types) : super(null, null); |
+ |
+ DartType get futureOfType => _types[0]; |
+ |
+ DartType get type => _types[1]; |
+ |
+ Iterable<DartType> get types => _types; |
+ |
+ @override |
+ void appendTo(StringBuffer buffer) { |
+ buffer.write('('); |
+ for (int i = 0; i < _types.length; i++) { |
+ if (i != 0) { |
+ buffer.write(' | '); |
+ } |
+ (_types[i] as TypeImpl).appendTo(buffer); |
+ } |
+ buffer.write(')'); |
+ } |
+ |
+ @override |
+ int get hashCode { |
+ int hash = 0; |
+ for (var t in types) { |
+ hash = JenkinsSmiHash.combine(hash, t.hashCode); |
+ } |
+ return JenkinsSmiHash.finish(hash); |
+ } |
+ |
+ @override |
+ bool operator ==(Object obj) { |
+ if (obj is FutureUnionType) { |
+ if (identical(obj, this)) return true; |
+ return types.length == obj.types.length && |
+ types.toSet().containsAll(obj.types); |
+ } |
+ return false; |
+ } |
+ |
+ @override |
+ bool isMoreSpecificThan(DartType type, |
+ [bool withDynamic = false, Set<Element> visitedElements]) => |
+ throw new UnsupportedError( |
+ 'Future unions are not part of the Dart 1 type system'); |
+ |
+ @override |
+ TypeImpl pruned(List<FunctionTypeAliasElement> prune) => |
+ throw new UnsupportedError('Future unions are not substituted'); |
+ |
+ @override |
+ DartType substitute2(List<DartType> args, List<DartType> params, |
+ [List<FunctionTypeAliasElement> prune]) => |
+ throw new UnsupportedError('Future unions are not used in typedefs'); |
+ |
+ /** |
+ * Creates a union of `T | Future<T>`, unless `T` is already a future-union, |
+ * in which case it simply returns `T` |
+ */ |
+ static DartType from( |
+ DartType type, TypeProvider provider, TypeSystem system) { |
+ if (type is FutureUnionType) { |
+ return type; |
+ } |
+ return new FutureUnionType(type, provider, system); |
+ } |
+} |
+ |
bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
} |