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

Side by Side Diff: pkg/analyzer/lib/src/generated/type_system.dart

Issue 2208953002: fix #25944, improve Future.then inference (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: cleanup unused code Created 4 years, 4 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library analyzer.src.generated.type_system; 5 library analyzer.src.generated.type_system;
6 6
7 import 'dart:collection'; 7 import 'dart:collection';
8 import 'dart:math' as math; 8 import 'dart:math' as math;
9 9
10 import 'package:analyzer/dart/ast/token.dart' show TokenType; 10 import 'package:analyzer/dart/ast/token.dart' show TokenType;
(...skipping 189 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 /// 200 ///
201 /// As a simplification, we do not actually store all constraints on each type 201 /// As a simplification, we do not actually store all constraints on each type
202 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and 202 /// parameter Tj. Instead we track Uj and Lj where U is the upper bound and
203 /// L is the lower bound of that type parameter. 203 /// L is the lower bound of that type parameter.
204 FunctionType inferGenericFunctionCall( 204 FunctionType inferGenericFunctionCall(
205 TypeProvider typeProvider, 205 TypeProvider typeProvider,
206 FunctionType fnType, 206 FunctionType fnType,
207 List<DartType> correspondingParameterTypes, 207 List<DartType> correspondingParameterTypes,
208 List<DartType> argumentTypes, 208 List<DartType> argumentTypes,
209 DartType returnContextType) { 209 DartType returnContextType) {
210
210 if (fnType.typeFormals.isEmpty) { 211 if (fnType.typeFormals.isEmpty) {
211 return fnType; 212 return fnType;
212 } 213 }
213 214
214 // Create a TypeSystem that will allow certain type parameters to be 215 // Create a TypeSystem that will allow certain type parameters to be
215 // inferred. It will optimistically assume these type parameters can be 216 // inferred. It will optimistically assume these type parameters can be
216 // subtypes (or supertypes) as necessary, and track the constraints that 217 // subtypes (or supertypes) as necessary, and track the constraints that
217 // are implied by this. 218 // are implied by this.
218 var inferringTypeSystem = 219 var inferringTypeSystem =
219 new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals); 220 new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals);
220 221
221 // Special case inference for Future.then.
222 //
223 // We don't have union types, so Future<T>.then<S> is typed to take a
224 // callback `T -> S`. However, the lambda might actually return a
225 // Future<S>. So we handle that special case here.
226 if (argumentTypes.isNotEmpty && argumentTypes[0] is FunctionType) {
227 Element element = fnType?.element;
228 bool isFutureThen = element is MethodElement &&
229 element.name == 'then' &&
230 element.enclosingElement.type.isDartAsyncFuture;
231 if (isFutureThen) {
232 // Ignore return context. We'll let the onValue function's return type
233 // drive inference.
234 returnContextType = null;
235 }
236 }
237
238 if (returnContextType != null) { 222 if (returnContextType != null) {
239 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); 223 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType);
240 } 224 }
241 225
242 for (int i = 0; i < argumentTypes.length; i++) { 226 for (int i = 0; i < argumentTypes.length; i++) {
243 // Try to pass each argument to each parameter, recording any type 227 // Try to pass each argument to each parameter, recording any type
244 // parameter bounds that were implied by this assignment. 228 // parameter bounds that were implied by this assignment.
245 inferringTypeSystem.isSubtypeOf( 229 inferringTypeSystem.isSubtypeOf(
246 argumentTypes[i], correspondingParameterTypes[i]); 230 argumentTypes[i], correspondingParameterTypes[i]);
247 } 231 }
(...skipping 435 matching lines...) Expand 10 before | Expand all | Expand 10 after
683 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, 667 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited,
684 {bool dynamicIsBottom: false}) { 668 {bool dynamicIsBottom: false}) {
685 // Guard recursive calls 669 // Guard recursive calls
686 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); 670 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf);
687 _GuardedSubtypeChecker<DartType> guardedInferTypeParameter = 671 _GuardedSubtypeChecker<DartType> guardedInferTypeParameter =
688 _guard(_inferTypeParameterSubtypeOf); 672 _guard(_inferTypeParameterSubtypeOf);
689 if (t1 == t2) { 673 if (t1 == t2) {
690 return true; 674 return true;
691 } 675 }
692 676
693 // The types are void, dynamic, bottom, interface types, function types 677 // The types are void, dynamic, bottom, interface types, function types,
694 // and type parameters. We proceed by eliminating these different classes 678 // and type parameters.
695 // from consideration. 679 //
680 // 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
681 // (T | Future<T> for some T).
682 //
683 // We proceed by eliminating these different classes from consideration.
696 684
697 // Trivially true. 685 // Trivially true.
698 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || 686 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) ||
699 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { 687 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) {
700 return true; 688 return true;
701 } 689 }
702 690
703 // Trivially false. 691 // Trivially false.
704 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || 692 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) ||
705 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { 693 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) {
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after
1262 @override 1250 @override
1263 DartType _typeParameterLeastUpperBound( 1251 DartType _typeParameterLeastUpperBound(
1264 TypeProvider provider, DartType type1, DartType type2) { 1252 TypeProvider provider, DartType type1, DartType type2) {
1265 type1 = type1.resolveToBound(provider.objectType); 1253 type1 = type1.resolveToBound(provider.objectType);
1266 type2 = type2.resolveToBound(provider.objectType); 1254 type2 = type2.resolveToBound(provider.objectType);
1267 return getLeastUpperBound(provider, type1, type2); 1255 return getLeastUpperBound(provider, type1, type2);
1268 } 1256 }
1269 } 1257 }
1270 1258
1271 /// Tracks upper and lower type bounds for a set of type parameters. 1259 /// Tracks upper and lower type bounds for a set of type parameters.
1260 ///
1261 /// This class is used by calling [isSubtypeOf]. When it encounters one of
1262 /// the type parameters it is inferring, it will record the constraint, and
1263 /// optimistically assume the constraint will be satisfied.
1264 ///
1265 /// For example if we are inferring type parameter A, and we ask if
1266 /// `A <: num`, this will record that A must be a subytpe of `num`. It also
1267 /// handles cases when A appears as part of the structure of another type, for
1268 /// example `Iterable<A> <: Iterable<num>` would infer the same constraint
1269 /// (due to covariant generic types) as would `() -> A <: () -> int`. In
1270 /// contrast `(A) -> void <: (num) -> void`.
1271 ///
1272 /// Once the lower/upper bounds are determined, [_infer] should be called to
1273 /// finish the inference. It will instantiate a generic function type with the
1274 /// inferred types for each type parameter.
1275 ///
1276 /// It can also optionally compute a partial solution, in case some of the type
1277 /// parameters could not be inferred (because the constraints cannot be
1278 /// satisfied), or bail on the inference when this happens.
1279 ///
1280 /// As currently designed, an instance of this class should only be used to
1281 /// infer a single call and discarded immediately afterwards.
1272 class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { 1282 class _StrongInferenceTypeSystem extends StrongTypeSystemImpl {
1273 final TypeProvider _typeProvider; 1283 final TypeProvider _typeProvider;
1274 1284
1275 /// The outer strong mode type system, used for GLB and LUB, so we don't 1285 /// The outer strong mode type system, used for GLB and LUB, so we don't
1276 /// recurse into our constraint solving code. 1286 /// recurse into our constraint solving code.
1277 final StrongTypeSystemImpl _typeSystem; 1287 final StrongTypeSystemImpl _typeSystem;
1278 final Map<TypeParameterType, _TypeParameterBound> _bounds; 1288 final Map<TypeParameterType, _TypeParameterBound> _bounds;
1279 1289
1280 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, 1290 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem,
1281 Iterable<TypeParameterElement> typeFormals) 1291 Iterable<TypeParameterElement> typeFormals)
(...skipping 217 matching lines...) Expand 10 before | Expand all | Expand 10 after
1499 } else { 1509 } else {
1500 passedOut = true; 1510 passedOut = true;
1501 } 1511 }
1502 } else if (type is FunctionType) { 1512 } else if (type is FunctionType) {
1503 _visitFunctionType(typeParam, type, paramIn); 1513 _visitFunctionType(typeParam, type, paramIn);
1504 } else if (type is InterfaceType) { 1514 } else if (type is InterfaceType) {
1505 _visitInterfaceType(typeParam, type, paramIn); 1515 _visitInterfaceType(typeParam, type, paramIn);
1506 } 1516 }
1507 } 1517 }
1508 } 1518 }
1519
1520 /**
1521 * This is a marker interface for [DartType] and [FutureUnionTypeContext].
1522 *
1523 * Both of those types are valid context types in strong mode's type inference.
1524 */
1525 abstract class TypeContext {}
1526
1527 /**
1528 * A special union type of `Future<T> | T` used for Strong Mode inference.
1529 */
1530 class FutureUnionTypeContext implements TypeContext {
1531
1532 // TODO(jmesserly): a Set would be better.
1533 //
1534 // For now we know `Future<T> | T` is the only valid use, so we can rely on
1535 // the order, which simplifies some things.
1536 //
1537 // This will need clean up before this can function as a real union type.
1538 final List<DartType> types;
1539
1540 @override
1541 String toString() {
1542 var buffer = new StringBuffer();
1543 buffer.write('(');
1544 for (int i = 0; i < types.length; i++) {
1545 if (i != 0) {
1546 buffer.write(' | ');
1547 }
1548 (types[i] as TypeImpl).appendTo(buffer);
1549 }
1550 buffer.write(')');
1551 return buffer.toString();
1552 }
1553
1554
1555 /**
1556 * Creates a union of `Future< flatten(T) > | flatten(T)`.
1557 */
1558 factory FutureUnionTypeContext(
1559 DartType type, TypeProvider provider, TypeSystem system) {
1560 type = type.flattenFutures(system);
1561
1562 // The order of these types is important: T could be a type variable, so
1563 // we want to try and match `Future<T>` before we try and match `T`.
1564 return new FutureUnionTypeContext._([
1565 provider.futureType.instantiate([type]),
1566 type
1567 ]);
1568 }
1569
1570 FutureUnionTypeContext._(this.types);
1571
1572 DartType get futureOfType => types[0];
1573
1574 DartType get type => types[1];
1575
1576 /**
1577 * Creates a union of `T | Future<T>`, unless `T` is already a future-union,
1578 * in which case it simply returns `T`
1579 */
1580 static FutureUnionTypeContext from(
1581 TypeContext type, TypeProvider provider, TypeSystem system) {
1582 if (type is FutureUnionTypeContext) {
1583 return type;
1584 }
1585 return new FutureUnionTypeContext(type as DartType, provider, system);
1586 }
1587 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698