Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 } | |
| OLD | NEW |