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; |
11 import 'package:analyzer/dart/element/element.dart'; | 11 import 'package:analyzer/dart/element/element.dart'; |
12 import 'package:analyzer/dart/element/type.dart'; | 12 import 'package:analyzer/dart/element/type.dart'; |
13 import 'package:analyzer/src/dart/element/element.dart'; | 13 import 'package:analyzer/src/dart/element/element.dart'; |
14 import 'package:analyzer/src/dart/element/type.dart'; | 14 import 'package:analyzer/src/dart/element/type.dart'; |
15 import 'package:analyzer/src/generated/engine.dart' | 15 import 'package:analyzer/src/generated/engine.dart' |
16 show AnalysisContext, AnalysisOptionsImpl; | 16 show AnalysisContext, AnalysisOptionsImpl; |
17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 17 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
18 import 'package:analyzer/src/generated/utilities_dart.dart'; | 18 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
19 import 'package:analyzer/src/generated/utilities_general.dart' | |
20 show JenkinsSmiHash; | |
19 | 21 |
20 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | 22 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
21 | 23 |
22 /** | 24 /** |
23 * Implementation of [TypeSystem] using the strong mode rules. | 25 * Implementation of [TypeSystem] using the strong mode rules. |
24 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | 26 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
25 */ | 27 */ |
26 class StrongTypeSystemImpl extends TypeSystem { | 28 class StrongTypeSystemImpl extends TypeSystem { |
27 /** | 29 /** |
28 * True if implicit casts should be allowed, otherwise false. | 30 * True if implicit casts should be allowed, otherwise false. |
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
275 return fnType; | 277 return fnType; |
276 } | 278 } |
277 | 279 |
278 // Create a TypeSystem that will allow certain type parameters to be | 280 // Create a TypeSystem that will allow certain type parameters to be |
279 // inferred. It will optimistically assume these type parameters can be | 281 // inferred. It will optimistically assume these type parameters can be |
280 // subtypes (or supertypes) as necessary, and track the constraints that | 282 // subtypes (or supertypes) as necessary, and track the constraints that |
281 // are implied by this. | 283 // are implied by this. |
282 var inferringTypeSystem = | 284 var inferringTypeSystem = |
283 new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals); | 285 new _StrongInferenceTypeSystem(typeProvider, this, fnType.typeFormals); |
284 | 286 |
285 // Special case inference for Future.then. | |
286 // | |
287 // We don't have union types, so Future<T>.then<S> is typed to take a | |
288 // callback `T -> S`. However, the lambda might actually return a | |
289 // Future<S>. So we handle that special case here. | |
290 if (argumentTypes.isNotEmpty && argumentTypes[0] is FunctionType) { | |
291 Element element = fnType?.element; | |
292 bool isFutureThen = element is MethodElement && | |
293 element.name == 'then' && | |
294 element.enclosingElement.type.isDartAsyncFuture; | |
295 if (isFutureThen) { | |
296 // Ignore return context. We'll let the onValue function's return type | |
297 // drive inference. | |
298 returnContextType = null; | |
299 } | |
300 } | |
301 | |
302 if (returnContextType != null) { | 287 if (returnContextType != null) { |
303 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); | 288 inferringTypeSystem.isSubtypeOf(fnType.returnType, returnContextType); |
304 } | 289 } |
305 | 290 |
306 for (int i = 0; i < argumentTypes.length; i++) { | 291 for (int i = 0; i < argumentTypes.length; i++) { |
307 // Try to pass each argument to each parameter, recording any type | 292 // Try to pass each argument to each parameter, recording any type |
308 // parameter bounds that were implied by this assignment. | 293 // parameter bounds that were implied by this assignment. |
309 inferringTypeSystem.isSubtypeOf( | 294 inferringTypeSystem.isSubtypeOf( |
310 argumentTypes[i], correspondingParameterTypes[i]); | 295 argumentTypes[i], correspondingParameterTypes[i]); |
311 } | 296 } |
(...skipping 432 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
744 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | 729 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, |
745 {bool dynamicIsBottom: false}) { | 730 {bool dynamicIsBottom: false}) { |
746 // Guard recursive calls | 731 // Guard recursive calls |
747 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); | 732 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); |
748 _GuardedSubtypeChecker<DartType> guardedInferTypeParameter = | 733 _GuardedSubtypeChecker<DartType> guardedInferTypeParameter = |
749 _guard(_inferTypeParameterSubtypeOf); | 734 _guard(_inferTypeParameterSubtypeOf); |
750 if (t1 == t2) { | 735 if (t1 == t2) { |
751 return true; | 736 return true; |
752 } | 737 } |
753 | 738 |
754 // The types are void, dynamic, bottom, interface types, function types | 739 // The types are void, dynamic, bottom, interface types, function types, |
755 // and type parameters. We proceed by eliminating these different classes | 740 // and type parameters. We proceed by eliminating these different classes |
756 // from consideration. | 741 // from consideration. |
757 | 742 |
758 // Trivially true. | 743 // Trivially true. |
759 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | 744 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
760 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | 745 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
761 return true; | 746 return true; |
762 } | 747 } |
763 | 748 |
764 // Trivially false. | 749 // Trivially false. |
765 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | 750 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
(...skipping 567 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1333 @override | 1318 @override |
1334 DartType _typeParameterLeastUpperBound( | 1319 DartType _typeParameterLeastUpperBound( |
1335 TypeProvider provider, DartType type1, DartType type2) { | 1320 TypeProvider provider, DartType type1, DartType type2) { |
1336 type1 = type1.resolveToBound(provider.objectType); | 1321 type1 = type1.resolveToBound(provider.objectType); |
1337 type2 = type2.resolveToBound(provider.objectType); | 1322 type2 = type2.resolveToBound(provider.objectType); |
1338 return getLeastUpperBound(provider, type1, type2); | 1323 return getLeastUpperBound(provider, type1, type2); |
1339 } | 1324 } |
1340 } | 1325 } |
1341 | 1326 |
1342 /// Tracks upper and lower type bounds for a set of type parameters. | 1327 /// Tracks upper and lower type bounds for a set of type parameters. |
1328 /// | |
1329 /// This class is used by calling [isSubtypeOf]. When it encounters one of | |
1330 /// the type parameters it is inferring, it will record the constraint, and | |
1331 /// optimistically assume the constraint will be satisfied. | |
1332 /// | |
1333 /// For example if we are inferring type parameter A, and we ask if | |
1334 /// `A <: num`, this will record that A must be a subytpe of `num`. It also | |
1335 /// handles cases when A appears as part of the structure of another type, for | |
1336 /// example `Iterable<A> <: Iterable<num>` would infer the same constraint | |
1337 /// (due to covariant generic types) as would `() -> A <: () -> int`. In | |
vsm
2016/08/09 20:29:33
nit: () -> num not () -> int
Jennifer Messerly
2016/08/09 20:56:57
You have keen eyes my friend ;). Done!
| |
1338 /// contrast `(A) -> void <: (num) -> void`. | |
1339 /// | |
1340 /// Once the lower/upper bounds are determined, [_infer] should be called to | |
1341 /// finish the inference. It will instantiate a generic function type with the | |
1342 /// inferred types for each type parameter. | |
1343 /// | |
1344 /// It can also optionally compute a partial solution, in case some of the type | |
1345 /// parameters could not be inferred (because the constraints cannot be | |
1346 /// satisfied), or bail on the inference when this happens. | |
1347 /// | |
1348 /// As currently designed, an instance of this class should only be used to | |
1349 /// infer a single call and discarded immediately afterwards. | |
1343 class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { | 1350 class _StrongInferenceTypeSystem extends StrongTypeSystemImpl { |
1344 final TypeProvider _typeProvider; | 1351 final TypeProvider _typeProvider; |
1345 | 1352 |
1346 /// The outer strong mode type system, used for GLB and LUB, so we don't | 1353 /// The outer strong mode type system, used for GLB and LUB, so we don't |
1347 /// recurse into our constraint solving code. | 1354 /// recurse into our constraint solving code. |
1348 final StrongTypeSystemImpl _typeSystem; | 1355 final StrongTypeSystemImpl _typeSystem; |
1349 final Map<TypeParameterType, _TypeParameterBound> _bounds; | 1356 final Map<TypeParameterType, _TypeParameterBound> _bounds; |
1350 | 1357 |
1351 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, | 1358 _StrongInferenceTypeSystem(this._typeProvider, this._typeSystem, |
1352 Iterable<TypeParameterElement> typeFormals) | 1359 Iterable<TypeParameterElement> typeFormals) |
(...skipping 218 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1571 passedOut = true; | 1578 passedOut = true; |
1572 } | 1579 } |
1573 } else if (type is FunctionType) { | 1580 } else if (type is FunctionType) { |
1574 _visitFunctionType(typeParam, type, paramIn); | 1581 _visitFunctionType(typeParam, type, paramIn); |
1575 } else if (type is InterfaceType) { | 1582 } else if (type is InterfaceType) { |
1576 _visitInterfaceType(typeParam, type, paramIn); | 1583 _visitInterfaceType(typeParam, type, paramIn); |
1577 } | 1584 } |
1578 } | 1585 } |
1579 } | 1586 } |
1580 | 1587 |
1588 /** | |
1589 * A special union type of `Future<T> | T` used for Strong Mode inference. | |
1590 */ | |
1591 class FutureUnionType extends TypeImpl { | |
1592 // TODO(jmesserly): a Set would be better. | |
1593 // | |
1594 // For now we know `Future<T> | T` is the only valid use, so we can rely on | |
1595 // the order, which simplifies some things. | |
1596 // | |
1597 // This will need clean up before this can function as a real union type. | |
1598 final List<DartType> types; | |
1599 | |
1600 /** | |
1601 * Creates a union of `Future< flatten(T) > | flatten(T)`. | |
1602 */ | |
1603 factory FutureUnionType( | |
1604 DartType type, TypeProvider provider, TypeSystem system) { | |
1605 type = type.flattenFutures(system); | |
1606 | |
1607 // The order of these types is important: T could be a type variable, so | |
1608 // we want to try and match `Future<T>` before we try and match `T`. | |
1609 return new FutureUnionType._([ | |
vsm
2016/08/09 20:29:33
maybe wrap the list in an UnmodifiableListView?
Jennifer Messerly
2016/08/09 20:56:57
yeah I tend to agree and I think we should use imm
| |
1610 provider.futureType.instantiate([type]), | |
1611 type | |
1612 ]); | |
1613 } | |
1614 | |
1615 FutureUnionType._(this.types) : super(null, null); | |
1616 | |
1617 DartType get futureOfType => types[0]; | |
1618 | |
1619 DartType get type => types[1]; | |
1620 | |
1621 @override | |
1622 void appendTo(StringBuffer buffer) { | |
1623 buffer.write('('); | |
1624 for (int i = 0; i < types.length; i++) { | |
1625 if (i != 0) { | |
1626 buffer.write(' | '); | |
1627 } | |
1628 (types[i] as TypeImpl).appendTo(buffer); | |
1629 } | |
1630 buffer.write(')'); | |
1631 } | |
1632 | |
1633 @override | |
1634 int get hashCode { | |
1635 int hash = 0; | |
1636 for (var t in types) { | |
1637 hash = JenkinsSmiHash.combine(hash, t.hashCode); | |
1638 } | |
1639 return JenkinsSmiHash.finish(hash); | |
1640 } | |
1641 | |
1642 @override | |
1643 bool operator ==(Object obj) { | |
1644 if (obj is FutureUnionType) { | |
1645 if (identical(obj, this)) return true; | |
1646 return types.length == obj.types.length && | |
1647 types.toSet().containsAll(obj.types); | |
1648 } | |
1649 return false; | |
1650 } | |
1651 | |
1652 @override | |
1653 bool isMoreSpecificThan(DartType type, | |
1654 [bool withDynamic = false, Set<Element> visitedElements]) => | |
1655 throw new UnsupportedError( | |
1656 'Future unions are not part of the Dart 1 type system'); | |
1657 | |
1658 @override | |
1659 TypeImpl pruned(List<FunctionTypeAliasElement> prune) => | |
1660 throw new UnsupportedError('Future unions are not substituted'); | |
1661 | |
1662 @override | |
1663 DartType substitute2(List<DartType> args, List<DartType> params, | |
1664 [List<FunctionTypeAliasElement> prune]) => | |
1665 throw new UnsupportedError('Future unions are not used in typedefs'); | |
1666 | |
1667 /** | |
1668 * Creates a union of `T | Future<T>`, unless `T` is already a future-union, | |
1669 * in which case it simply returns `T` | |
1670 */ | |
1671 static DartType from( | |
1672 DartType type, TypeProvider provider, TypeSystem system) { | |
1673 if (type is FutureUnionType) { | |
1674 return type; | |
1675 } | |
1676 return new FutureUnionType(type, provider, system); | |
1677 } | |
1678 } | |
1679 | |
1581 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | 1680 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
1582 return (t.isDynamic && dynamicIsBottom) || t.isBottom; | 1681 return (t.isDynamic && dynamicIsBottom) || t.isBottom; |
1583 } | 1682 } |
1584 | 1683 |
1585 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | 1684 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
1586 // TODO(leafp): Document the rules in play here | 1685 // TODO(leafp): Document the rules in play here |
1587 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | 1686 return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
1588 } | 1687 } |
OLD | NEW |