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 |