Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Unified Diff: pkg/analyzer/lib/src/generated/type_system.dart

Issue 2647833002: fix #28008, fix #28009 implement FutureOr<T> (Closed)
Patch Set: Merge remote-tracking branch 'origin/master' into 28008_futureort Created 3 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 6be21c33318cab94d9f74017d2c13b2e307886ca..2b6012a4eb8e61022de5e507ac72e31364719341 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -20,8 +20,6 @@ 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' show ParameterKind;
-import 'package:analyzer/src/generated/utilities_general.dart'
- show JenkinsSmiHash;
bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
return (t.isDynamic && dynamicIsBottom) || t.isBottom || t.isDartCoreNull;
@@ -29,123 +27,15 @@ bool _isBottom(DartType t, {bool dynamicIsBottom: false}) {
bool _isTop(DartType t, {bool dynamicIsBottom: false}) {
// TODO(leafp): Document the rules in play here
+ if (t.isDartAsyncFutureOr) {
+ return _isTop((t as InterfaceType).typeArguments[0]);
+ }
return (t.isDynamic && !dynamicIsBottom) || t.isObject;
}
typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited);
/**
- * 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<T> | T`.
- */
- FutureUnionType._(DartType type, TypeProvider provider, TypeSystem system)
- : _types = [
- provider.futureType.instantiate([type]),
- type
- ],
- super(null, null);
-
- DartType get futureOfType => _types[0];
-
- @override
- int get hashCode {
- int hash = 0;
- for (var t in types) {
- hash = JenkinsSmiHash.combine(hash, t.hashCode);
- }
- return JenkinsSmiHash.finish(hash);
- }
-
- DartType get type => _types[1];
-
- Iterable<DartType> get types => _types;
-
- @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
- 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
- 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 or a
- * future-union, in which case it simply returns `T`.
- *
- * Conceptually this is used as the inverse of the `flatten(T)` operation,
- * defined as:
- *
- * - `flatten(Future<T>) -> T`
- * - `flatten(T) -> T`
- *
- * Thus the inverse will give us `T | Future<T>`.
- *
- * If [type] is top (dynamic or Object) then the resulting union type is
- * equivalent to top, so we simply return it.
- *
- * For a similar reason `Future<T> | Future<Future<T>>` is equivalent to just
- * `Future<T>`, so we return it. Note that it is not possible to get a
- * `Future<T>` as a result of `flatten`, so a this case likely indicates a
- * type error in the code, but it will be reported elsewhere.
- */
- static DartType from(
- DartType type, TypeProvider provider, TypeSystem system) {
- if (_isTop(type)) {
- return type;
- }
- if (!identical(type, type.flattenFutures(system))) {
- // As noted above, this most likely represents erroneous input.
- return type;
- }
-
- if (type is FutureUnionType) {
- return type;
- }
- return new FutureUnionType._(type, provider, system);
- }
-}
-
-/**
* Implementation of [TypeSystem] using the strong mode rules.
* https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md
*/
@@ -173,6 +63,9 @@ class StrongTypeSystemImpl extends TypeSystem {
}
@override
+ bool get isStrong => true;
+
+ @override
FunctionType functionTypeToConcreteType(FunctionType t) {
// TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function
// type? That would allow us to implement this in the subtype relation.
@@ -806,8 +699,7 @@ 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, Set<Element> visited) {
+ bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) {
return false;
}
@@ -933,12 +825,11 @@ class StrongTypeSystemImpl extends TypeSystem {
// Guard recursive calls
_GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
- _GuardedSubtypeChecker<DartType> guardedInferTypeParameter =
- _guard(_inferTypeParameterSubtypeOf);
// The types are void, dynamic, bottom, interface types, function types,
- // and type parameters. We proceed by eliminating these different classes
- // from consideration.
+ // FutureOr<T> and type parameters.
+ //
+ // We proceed by eliminating these different classes from consideration.
// Trivially true.
if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
@@ -949,7 +840,7 @@ class StrongTypeSystemImpl extends TypeSystem {
// Trivially false.
if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
_isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
- return guardedInferTypeParameter(t1, t2, visited);
+ return _inferTypeParameterSubtypeOf(t1, t2);
}
// S <: T where S is a type variable
@@ -962,7 +853,7 @@ class StrongTypeSystemImpl extends TypeSystem {
guardedSubtype(t1.bound, t2.bound, visited)) {
return true;
}
- if (guardedInferTypeParameter(t1, t2, visited)) {
+ if (_inferTypeParameterSubtypeOf(t1, t2)) {
return true;
}
DartType bound = t1.element.bound;
@@ -970,20 +861,30 @@ class StrongTypeSystemImpl extends TypeSystem {
}
if (t2 is TypeParameterType) {
- return guardedInferTypeParameter(t1, t2, visited);
+ return _inferTypeParameterSubtypeOf(t1, t2);
}
- if (t1 is FutureUnionType) {
+ // 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
+ return isSubtypeOf(t1TypeArg, t2TypeArg);
+ }
+
// given t1 is Future<A> | A, then:
- // (Future<A> | A) <: t2 iff t2 <: Future<A> and t2 <: A.
- return guardedSubtype(t1.futureOfType, t2, visited) &&
- guardedSubtype(t1.type, t2, visited);
+ // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2.
+ var t1Future = typeProvider.futureType.instantiate([t1TypeArg]);
+ return isSubtypeOf(t1Future, t2) && isSubtypeOf(t1TypeArg, t2);
}
- if (t2 is FutureUnionType) {
+
+ if (t2 is InterfaceType && t2.isDartAsyncFutureOr) {
// given t2 is Future<A> | A, then:
// t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A
- return guardedSubtype(t1, t2.futureOfType, visited) ||
- guardedSubtype(t1, t2.type, visited);
+ var t2TypeArg = t2.typeArguments[0];
+ var t2Future = typeProvider.futureType.instantiate([t2TypeArg]);
+ return isSubtypeOf(t1, t2Future) || isSubtypeOf(t1, t2TypeArg);
}
// Void only appears as the return type of a function, and we handle it
@@ -996,8 +897,8 @@ class StrongTypeSystemImpl extends TypeSystem {
return t1.isVoid && t2.isVoid;
}
- // We've eliminated void, dynamic, bottom, and type parameters. The only
- // cases are the combinations of interface type and function type.
+ // We've eliminated void, dynamic, bottom, type parameters, and FutureOr.
+ // The only cases are the combinations of interface type and function type.
// A function type can only subtype an interface type if
// the interface type is Function
@@ -1087,6 +988,11 @@ class StrongTypeSystemImpl extends TypeSystem {
*/
abstract class TypeSystem {
/**
+ * Whether the type system is strong or not.
+ */
+ bool get isStrong;
+
+ /**
* The provider of types for the system
*/
TypeProvider get typeProvider;
@@ -1460,6 +1366,8 @@ class TypeSystemImpl extends TypeSystem {
TypeSystemImpl(this.typeProvider);
@override
+ bool get isStrong => false;
+
FunctionType functionTypeToConcreteType(FunctionType t) => t;
/**
@@ -1596,7 +1504,7 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
if (declaredUpperBound != null) {
// Assert that the type parameter is a subtype of its bound.
_inferTypeParameterSubtypeOf(typeParam,
- declaredUpperBound.substitute2(inferredTypes, fnTypeParams), null);
+ declaredUpperBound.substitute2(inferredTypes, fnTypeParams));
}
// Now we've computed lower and upper bounds for each type parameter.
@@ -1615,38 +1523,6 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
DartType lowerBound = bound.lower;
DartType upperBound = bound.upper;
- // Collapse future unions if we inferred them somehow.
- //
- // TODO(jmesserly): in our initial upward phase it would be fine to
- // keep the FutureUnionType for the argument downward context.
- //
- // We need to track in `inferGenericFunctionCall` whether we are going up
- // or down. This would also allow for an improved heuristic: if we are
- // doing our final inference, the downward context can take priority.
- if (lowerBound is FutureUnionType) {
- // lowerBound <: T, where lowerBound is Future<A> | A.
- // So we choose lowerBound as LUB(A, Future<A>).
- //
- // This will typically lead to top with the current rules, but it will
- // work with `bottom` or if we remove Future flattening.
- var f = lowerBound as FutureUnionType;
- lowerBound = _typeSystem.getLeastUpperBound(f.futureOfType, f.type);
- }
- if (upperBound is FutureUnionType) {
- // T <: upperBound, where upperBound is Future<A> | A.
- // Therefore we need T <: Future<A> or T <: A.
- //
- // This is just an arbitrarily heuristic.
- var f = upperBound as FutureUnionType;
- if (_typeSystem.isSubtypeOf(lowerBound, f.type)) {
- upperBound = f.type;
- } else if (_typeSystem.isSubtypeOf(lowerBound, f.futureOfType)) {
- upperBound = f.futureOfType;
- } else {
- upperBound = f.type;
- }
- }
-
// See if the bounds can be satisfied.
// TODO(jmesserly): also we should have an error for unconstrained type
// parameters, rather than silently inferring dynamic.
@@ -1686,8 +1562,7 @@ class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
}
@override
- bool _inferTypeParameterSubtypeOf(
- DartType t1, DartType t2, Set<Element> visited) {
+ bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) {
if (t1 is TypeParameterType) {
_TypeParameterBound bound = _bounds[t1];
if (bound != null) {
« no previous file with comments | « pkg/analyzer/lib/src/generated/testing/element_factory.dart ('k') | pkg/analyzer/lib/src/summary/resynthesize.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698