| 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/ast.dart' show AstNode; | 10 import 'package:analyzer/dart/ast/ast.dart' show AstNode; |
| 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; | 11 import 'package:analyzer/dart/ast/token.dart' show TokenType; |
| 12 import 'package:analyzer/dart/element/element.dart'; | 12 import 'package:analyzer/dart/element/element.dart'; |
| 13 import 'package:analyzer/dart/element/type.dart'; | 13 import 'package:analyzer/dart/element/type.dart'; |
| 14 import 'package:analyzer/error/listener.dart' show ErrorReporter; | 14 import 'package:analyzer/error/listener.dart' show ErrorReporter; |
| 15 import 'package:analyzer/src/dart/element/element.dart'; | 15 import 'package:analyzer/src/dart/element/element.dart'; |
| 16 import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember; | 16 import 'package:analyzer/src/dart/element/member.dart' show TypeParameterMember; |
| 17 import 'package:analyzer/src/dart/element/type.dart'; | 17 import 'package:analyzer/src/dart/element/type.dart'; |
| 18 import 'package:analyzer/src/error/codes.dart' show StrongModeCode; | 18 import 'package:analyzer/src/error/codes.dart' show StrongModeCode; |
| 19 import 'package:analyzer/src/generated/engine.dart' | 19 import 'package:analyzer/src/generated/engine.dart' |
| 20 show AnalysisContext, AnalysisOptionsImpl; | 20 show AnalysisContext, AnalysisOptionsImpl; |
| 21 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; | 21 import 'package:analyzer/src/generated/resolver.dart' show TypeProvider; |
| 22 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; | 22 import 'package:analyzer/src/generated/utilities_dart.dart' show ParameterKind; |
| 23 import 'package:analyzer/src/generated/utilities_general.dart' | |
| 24 show JenkinsSmiHash; | |
| 25 | 23 |
| 26 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { | 24 bool _isBottom(DartType t, {bool dynamicIsBottom: false}) { |
| 27 return (t.isDynamic && dynamicIsBottom) || t.isBottom || t.isDartCoreNull; | 25 return (t.isDynamic && dynamicIsBottom) || t.isBottom || t.isDartCoreNull; |
| 28 } | 26 } |
| 29 | 27 |
| 30 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { | 28 bool _isTop(DartType t, {bool dynamicIsBottom: false}) { |
| 31 // TODO(leafp): Document the rules in play here | 29 // TODO(leafp): Document the rules in play here |
| 30 if (t.isDartAsyncFutureOr) { |
| 31 return _isTop((t as InterfaceType).typeArguments[0]); |
| 32 } |
| 32 return (t.isDynamic && !dynamicIsBottom) || t.isObject; | 33 return (t.isDynamic && !dynamicIsBottom) || t.isObject; |
| 33 } | 34 } |
| 34 | 35 |
| 35 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); | 36 typedef bool _GuardedSubtypeChecker<T>(T t1, T t2, Set<Element> visited); |
| 36 | 37 |
| 37 /** | 38 /** |
| 38 * A special union type of `Future<T> | T` used for Strong Mode inference. | |
| 39 */ | |
| 40 class FutureUnionType extends TypeImpl { | |
| 41 // TODO(jmesserly): a Set would be better. | |
| 42 // | |
| 43 // For now we know `Future<T> | T` is the only valid use, so we can rely on | |
| 44 // the order, which simplifies some things. | |
| 45 // | |
| 46 // This will need clean up before this can function as a real union type. | |
| 47 final List<DartType> _types; | |
| 48 | |
| 49 /** | |
| 50 * Creates a union of `Future<T> | T`. | |
| 51 */ | |
| 52 FutureUnionType._(DartType type, TypeProvider provider, TypeSystem system) | |
| 53 : _types = [ | |
| 54 provider.futureType.instantiate([type]), | |
| 55 type | |
| 56 ], | |
| 57 super(null, null); | |
| 58 | |
| 59 DartType get futureOfType => _types[0]; | |
| 60 | |
| 61 @override | |
| 62 int get hashCode { | |
| 63 int hash = 0; | |
| 64 for (var t in types) { | |
| 65 hash = JenkinsSmiHash.combine(hash, t.hashCode); | |
| 66 } | |
| 67 return JenkinsSmiHash.finish(hash); | |
| 68 } | |
| 69 | |
| 70 DartType get type => _types[1]; | |
| 71 | |
| 72 Iterable<DartType> get types => _types; | |
| 73 | |
| 74 @override | |
| 75 bool operator ==(Object obj) { | |
| 76 if (obj is FutureUnionType) { | |
| 77 if (identical(obj, this)) return true; | |
| 78 return types.length == obj.types.length && | |
| 79 types.toSet().containsAll(obj.types); | |
| 80 } | |
| 81 return false; | |
| 82 } | |
| 83 | |
| 84 @override | |
| 85 void appendTo(StringBuffer buffer) { | |
| 86 buffer.write('('); | |
| 87 for (int i = 0; i < _types.length; i++) { | |
| 88 if (i != 0) { | |
| 89 buffer.write(' | '); | |
| 90 } | |
| 91 (_types[i] as TypeImpl).appendTo(buffer); | |
| 92 } | |
| 93 buffer.write(')'); | |
| 94 } | |
| 95 | |
| 96 @override | |
| 97 bool isMoreSpecificThan(DartType type, | |
| 98 [bool withDynamic = false, Set<Element> visitedElements]) => | |
| 99 throw new UnsupportedError( | |
| 100 'Future unions are not part of the Dart 1 type system'); | |
| 101 | |
| 102 @override | |
| 103 TypeImpl pruned(List<FunctionTypeAliasElement> prune) => | |
| 104 throw new UnsupportedError('Future unions are not substituted'); | |
| 105 | |
| 106 @override | |
| 107 DartType substitute2(List<DartType> args, List<DartType> params, | |
| 108 [List<FunctionTypeAliasElement> prune]) => | |
| 109 throw new UnsupportedError('Future unions are not used in typedefs'); | |
| 110 | |
| 111 /** | |
| 112 * Creates a union of `T | Future<T>`, unless `T` is already a future or a | |
| 113 * future-union, in which case it simply returns `T`. | |
| 114 * | |
| 115 * Conceptually this is used as the inverse of the `flatten(T)` operation, | |
| 116 * defined as: | |
| 117 * | |
| 118 * - `flatten(Future<T>) -> T` | |
| 119 * - `flatten(T) -> T` | |
| 120 * | |
| 121 * Thus the inverse will give us `T | Future<T>`. | |
| 122 * | |
| 123 * If [type] is top (dynamic or Object) then the resulting union type is | |
| 124 * equivalent to top, so we simply return it. | |
| 125 * | |
| 126 * For a similar reason `Future<T> | Future<Future<T>>` is equivalent to just | |
| 127 * `Future<T>`, so we return it. Note that it is not possible to get a | |
| 128 * `Future<T>` as a result of `flatten`, so a this case likely indicates a | |
| 129 * type error in the code, but it will be reported elsewhere. | |
| 130 */ | |
| 131 static DartType from( | |
| 132 DartType type, TypeProvider provider, TypeSystem system) { | |
| 133 if (_isTop(type)) { | |
| 134 return type; | |
| 135 } | |
| 136 if (!identical(type, type.flattenFutures(system))) { | |
| 137 // As noted above, this most likely represents erroneous input. | |
| 138 return type; | |
| 139 } | |
| 140 | |
| 141 if (type is FutureUnionType) { | |
| 142 return type; | |
| 143 } | |
| 144 return new FutureUnionType._(type, provider, system); | |
| 145 } | |
| 146 } | |
| 147 | |
| 148 /** | |
| 149 * Implementation of [TypeSystem] using the strong mode rules. | 39 * Implementation of [TypeSystem] using the strong mode rules. |
| 150 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md | 40 * https://github.com/dart-lang/dev_compiler/blob/master/STRONG_MODE.md |
| 151 */ | 41 */ |
| 152 class StrongTypeSystemImpl extends TypeSystem { | 42 class StrongTypeSystemImpl extends TypeSystem { |
| 153 /** | 43 /** |
| 154 * True if implicit casts should be allowed, otherwise false. | 44 * True if implicit casts should be allowed, otherwise false. |
| 155 * | 45 * |
| 156 * This affects the behavior of [isAssignableTo]. | 46 * This affects the behavior of [isAssignableTo]. |
| 157 */ | 47 */ |
| 158 final bool implicitCasts; | 48 final bool implicitCasts; |
| 159 | 49 |
| 160 /** | 50 /** |
| 161 * A list of non-nullable type names (e.g., 'int', 'bool', etc.). | 51 * A list of non-nullable type names (e.g., 'int', 'bool', etc.). |
| 162 */ | 52 */ |
| 163 final List<String> nonnullableTypes; | 53 final List<String> nonnullableTypes; |
| 164 | 54 |
| 165 final TypeProvider typeProvider; | 55 final TypeProvider typeProvider; |
| 166 | 56 |
| 167 StrongTypeSystemImpl(this.typeProvider, | 57 StrongTypeSystemImpl(this.typeProvider, |
| 168 {this.implicitCasts: true, | 58 {this.implicitCasts: true, |
| 169 this.nonnullableTypes: AnalysisOptionsImpl.NONNULLABLE_TYPES}); | 59 this.nonnullableTypes: AnalysisOptionsImpl.NONNULLABLE_TYPES}); |
| 170 | 60 |
| 171 bool anyParameterType(FunctionType ft, bool predicate(DartType t)) { | 61 bool anyParameterType(FunctionType ft, bool predicate(DartType t)) { |
| 172 return ft.parameters.any((p) => predicate(p.type)); | 62 return ft.parameters.any((p) => predicate(p.type)); |
| 173 } | 63 } |
| 174 | 64 |
| 175 @override | 65 @override |
| 66 bool get isStrong => true; |
| 67 |
| 68 @override |
| 176 FunctionType functionTypeToConcreteType(FunctionType t) { | 69 FunctionType functionTypeToConcreteType(FunctionType t) { |
| 177 // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function | 70 // TODO(jmesserly): should we use a real "fuzzyArrow" bit on the function |
| 178 // type? That would allow us to implement this in the subtype relation. | 71 // type? That would allow us to implement this in the subtype relation. |
| 179 // TODO(jmesserly): we'll need to factor this differently if we want to | 72 // TODO(jmesserly): we'll need to factor this differently if we want to |
| 180 // move CodeChecker's functionality into existing analyzer. Likely we can | 73 // move CodeChecker's functionality into existing analyzer. Likely we can |
| 181 // let the Expression have a strict arrow, then in places were we do | 74 // let the Expression have a strict arrow, then in places were we do |
| 182 // inference, convert back to a fuzzy arrow. | 75 // inference, convert back to a fuzzy arrow. |
| 183 | 76 |
| 184 if (!t.parameters.any((p) => p.type.isDynamic)) { | 77 if (!t.parameters.any((p) => p.type.isDynamic)) { |
| 185 return t; | 78 return t; |
| (...skipping 613 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 return check(t1, t2, visited); | 692 return check(t1, t2, visited); |
| 800 } finally { | 693 } finally { |
| 801 visited.remove(element); | 694 visited.remove(element); |
| 802 } | 695 } |
| 803 }; | 696 }; |
| 804 } | 697 } |
| 805 | 698 |
| 806 /// If [t1] or [t2] is a type parameter we are inferring, update its bound. | 699 /// If [t1] or [t2] is a type parameter we are inferring, update its bound. |
| 807 /// Returns `true` if we could possibly find a compatible type, | 700 /// Returns `true` if we could possibly find a compatible type, |
| 808 /// otherwise `false`. | 701 /// otherwise `false`. |
| 809 bool _inferTypeParameterSubtypeOf( | 702 bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) { |
| 810 DartType t1, DartType t2, Set<Element> visited) { | |
| 811 return false; | 703 return false; |
| 812 } | 704 } |
| 813 | 705 |
| 814 /** | 706 /** |
| 815 * This currently does not implement a very complete least upper bound | 707 * This currently does not implement a very complete least upper bound |
| 816 * algorithm, but handles a couple of the very common cases that are | 708 * algorithm, but handles a couple of the very common cases that are |
| 817 * causing pain in real code. The current algorithm is: | 709 * causing pain in real code. The current algorithm is: |
| 818 * 1. If either of the types is a supertype of the other, return it. | 710 * 1. If either of the types is a supertype of the other, return it. |
| 819 * This is in fact the best result in this case. | 711 * This is in fact the best result in this case. |
| 820 * 2. If the two types have the same class element, then take the | 712 * 2. If the two types have the same class element, then take the |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 926 } | 818 } |
| 927 | 819 |
| 928 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, | 820 bool _isSubtypeOf(DartType t1, DartType t2, Set<Element> visited, |
| 929 {bool dynamicIsBottom: false}) { | 821 {bool dynamicIsBottom: false}) { |
| 930 if (identical(t1, t2)) { | 822 if (identical(t1, t2)) { |
| 931 return true; | 823 return true; |
| 932 } | 824 } |
| 933 | 825 |
| 934 // Guard recursive calls | 826 // Guard recursive calls |
| 935 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); | 827 _GuardedSubtypeChecker<DartType> guardedSubtype = _guard(_isSubtypeOf); |
| 936 _GuardedSubtypeChecker<DartType> guardedInferTypeParameter = | |
| 937 _guard(_inferTypeParameterSubtypeOf); | |
| 938 | 828 |
| 939 // The types are void, dynamic, bottom, interface types, function types, | 829 // The types are void, dynamic, bottom, interface types, function types, |
| 940 // and type parameters. We proceed by eliminating these different classes | 830 // FutureOr<T> and type parameters. |
| 941 // from consideration. | 831 // |
| 832 // We proceed by eliminating these different classes from consideration. |
| 942 | 833 |
| 943 // Trivially true. | 834 // Trivially true. |
| 944 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || | 835 if (_isTop(t2, dynamicIsBottom: dynamicIsBottom) || |
| 945 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { | 836 _isBottom(t1, dynamicIsBottom: dynamicIsBottom)) { |
| 946 return true; | 837 return true; |
| 947 } | 838 } |
| 948 | 839 |
| 949 // Trivially false. | 840 // Trivially false. |
| 950 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || | 841 if (_isTop(t1, dynamicIsBottom: dynamicIsBottom) || |
| 951 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { | 842 _isBottom(t2, dynamicIsBottom: dynamicIsBottom)) { |
| 952 return guardedInferTypeParameter(t1, t2, visited); | 843 return _inferTypeParameterSubtypeOf(t1, t2); |
| 953 } | 844 } |
| 954 | 845 |
| 955 // S <: T where S is a type variable | 846 // S <: T where S is a type variable |
| 956 // T is not dynamic or object (handled above) | 847 // T is not dynamic or object (handled above) |
| 957 // True if T == S | 848 // True if T == S |
| 958 // Or true if bound of S is S' and S' <: T | 849 // Or true if bound of S is S' and S' <: T |
| 959 if (t1 is TypeParameterType) { | 850 if (t1 is TypeParameterType) { |
| 960 if (t2 is TypeParameterType && | 851 if (t2 is TypeParameterType && |
| 961 t1.definition == t2.definition && | 852 t1.definition == t2.definition && |
| 962 guardedSubtype(t1.bound, t2.bound, visited)) { | 853 guardedSubtype(t1.bound, t2.bound, visited)) { |
| 963 return true; | 854 return true; |
| 964 } | 855 } |
| 965 if (guardedInferTypeParameter(t1, t2, visited)) { | 856 if (_inferTypeParameterSubtypeOf(t1, t2)) { |
| 966 return true; | 857 return true; |
| 967 } | 858 } |
| 968 DartType bound = t1.element.bound; | 859 DartType bound = t1.element.bound; |
| 969 return bound == null ? false : guardedSubtype(bound, t2, visited); | 860 return bound == null ? false : guardedSubtype(bound, t2, visited); |
| 970 } | 861 } |
| 971 | 862 |
| 972 if (t2 is TypeParameterType) { | 863 if (t2 is TypeParameterType) { |
| 973 return guardedInferTypeParameter(t1, t2, visited); | 864 return _inferTypeParameterSubtypeOf(t1, t2); |
| 974 } | 865 } |
| 975 | 866 |
| 976 if (t1 is FutureUnionType) { | 867 // Handle FutureOr<T> union type. |
| 868 if (t1 is InterfaceType && t1.isDartAsyncFutureOr) { |
| 869 var t1TypeArg = t1.typeArguments[0]; |
| 870 if (t2 is InterfaceType && t2.isDartAsyncFutureOr) { |
| 871 var t2TypeArg = t2.typeArguments[0]; |
| 872 // FutureOr<A> <: FutureOr<B> iff A <: B |
| 873 return isSubtypeOf(t1TypeArg, t2TypeArg); |
| 874 } |
| 875 |
| 977 // given t1 is Future<A> | A, then: | 876 // given t1 is Future<A> | A, then: |
| 978 // (Future<A> | A) <: t2 iff t2 <: Future<A> and t2 <: A. | 877 // (Future<A> | A) <: t2 iff Future<A> <: t2 and A <: t2. |
| 979 return guardedSubtype(t1.futureOfType, t2, visited) && | 878 var t1Future = typeProvider.futureType.instantiate([t1TypeArg]); |
| 980 guardedSubtype(t1.type, t2, visited); | 879 return isSubtypeOf(t1Future, t2) && isSubtypeOf(t1TypeArg, t2); |
| 981 } | 880 } |
| 982 if (t2 is FutureUnionType) { | 881 |
| 882 if (t2 is InterfaceType && t2.isDartAsyncFutureOr) { |
| 983 // given t2 is Future<A> | A, then: | 883 // given t2 is Future<A> | A, then: |
| 984 // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A | 884 // t1 <: (Future<A> | A) iff t1 <: Future<A> or t1 <: A |
| 985 return guardedSubtype(t1, t2.futureOfType, visited) || | 885 var t2TypeArg = t2.typeArguments[0]; |
| 986 guardedSubtype(t1, t2.type, visited); | 886 var t2Future = typeProvider.futureType.instantiate([t2TypeArg]); |
| 887 return isSubtypeOf(t1, t2Future) || isSubtypeOf(t1, t2TypeArg); |
| 987 } | 888 } |
| 988 | 889 |
| 989 // Void only appears as the return type of a function, and we handle it | 890 // Void only appears as the return type of a function, and we handle it |
| 990 // directly in the function subtype rules. We should not get to a point | 891 // directly in the function subtype rules. We should not get to a point |
| 991 // where we're doing a subtype test on a "bare" void, but just in case we | 892 // where we're doing a subtype test on a "bare" void, but just in case we |
| 992 // do, handle it safely. | 893 // do, handle it safely. |
| 993 // TODO(rnystrom): Determine how this can ever be reached. If it can't, | 894 // TODO(rnystrom): Determine how this can ever be reached. If it can't, |
| 994 // remove it. | 895 // remove it. |
| 995 if (t1.isVoid || t2.isVoid) { | 896 if (t1.isVoid || t2.isVoid) { |
| 996 return t1.isVoid && t2.isVoid; | 897 return t1.isVoid && t2.isVoid; |
| 997 } | 898 } |
| 998 | 899 |
| 999 // We've eliminated void, dynamic, bottom, and type parameters. The only | 900 // We've eliminated void, dynamic, bottom, type parameters, and FutureOr. |
| 1000 // cases are the combinations of interface type and function type. | 901 // The only cases are the combinations of interface type and function type. |
| 1001 | 902 |
| 1002 // A function type can only subtype an interface type if | 903 // A function type can only subtype an interface type if |
| 1003 // the interface type is Function | 904 // the interface type is Function |
| 1004 if (t1 is FunctionType && t2 is InterfaceType) { | 905 if (t1 is FunctionType && t2 is InterfaceType) { |
| 1005 return t2.isDartCoreFunction; | 906 return t2.isDartCoreFunction; |
| 1006 } | 907 } |
| 1007 | 908 |
| 1008 // An interface type can only subtype a function type if | 909 // An interface type can only subtype a function type if |
| 1009 // the interface type declares a call method with a type | 910 // the interface type declares a call method with a type |
| 1010 // which is a super type of the function type. | 911 // which is a super type of the function type. |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1080 | 981 |
| 1081 /** | 982 /** |
| 1082 * The interface `TypeSystem` defines the behavior of an object representing | 983 * The interface `TypeSystem` defines the behavior of an object representing |
| 1083 * the type system. This provides a common location to put methods that act on | 984 * the type system. This provides a common location to put methods that act on |
| 1084 * types but may need access to more global data structures, and it paves the | 985 * types but may need access to more global data structures, and it paves the |
| 1085 * way for a possible future where we may wish to make the type system | 986 * way for a possible future where we may wish to make the type system |
| 1086 * pluggable. | 987 * pluggable. |
| 1087 */ | 988 */ |
| 1088 abstract class TypeSystem { | 989 abstract class TypeSystem { |
| 1089 /** | 990 /** |
| 991 * Whether the type system is strong or not. |
| 992 */ |
| 993 bool get isStrong; |
| 994 |
| 995 /** |
| 1090 * The provider of types for the system | 996 * The provider of types for the system |
| 1091 */ | 997 */ |
| 1092 TypeProvider get typeProvider; | 998 TypeProvider get typeProvider; |
| 1093 | 999 |
| 1094 /** | 1000 /** |
| 1095 * Make a function type concrete. | 1001 * Make a function type concrete. |
| 1096 * | 1002 * |
| 1097 * Normally we treat dynamically typed parameters as bottom for function | 1003 * Normally we treat dynamically typed parameters as bottom for function |
| 1098 * types. This allows type tests such as `if (f is SingleArgFunction)`. | 1004 * types. This allows type tests such as `if (f is SingleArgFunction)`. |
| 1099 * It also requires a dynamic check on the parameter type to call these | 1005 * It also requires a dynamic check on the parameter type to call these |
| (...skipping 353 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1453 | 1359 |
| 1454 /** | 1360 /** |
| 1455 * Implementation of [TypeSystem] using the rules in the Dart specification. | 1361 * Implementation of [TypeSystem] using the rules in the Dart specification. |
| 1456 */ | 1362 */ |
| 1457 class TypeSystemImpl extends TypeSystem { | 1363 class TypeSystemImpl extends TypeSystem { |
| 1458 final TypeProvider typeProvider; | 1364 final TypeProvider typeProvider; |
| 1459 | 1365 |
| 1460 TypeSystemImpl(this.typeProvider); | 1366 TypeSystemImpl(this.typeProvider); |
| 1461 | 1367 |
| 1462 @override | 1368 @override |
| 1369 bool get isStrong => false; |
| 1370 |
| 1463 FunctionType functionTypeToConcreteType(FunctionType t) => t; | 1371 FunctionType functionTypeToConcreteType(FunctionType t) => t; |
| 1464 | 1372 |
| 1465 /** | 1373 /** |
| 1466 * Instantiate a parameterized type using `dynamic` for all generic | 1374 * Instantiate a parameterized type using `dynamic` for all generic |
| 1467 * parameters. Returns the type unchanged if there are no parameters. | 1375 * parameters. Returns the type unchanged if there are no parameters. |
| 1468 */ | 1376 */ |
| 1469 DartType instantiateToBounds(DartType type, {List<bool> hasError}) { | 1377 DartType instantiateToBounds(DartType type, {List<bool> hasError}) { |
| 1470 List<DartType> typeFormals = typeFormalsAsTypes(type); | 1378 List<DartType> typeFormals = typeFormalsAsTypes(type); |
| 1471 int count = typeFormals.length; | 1379 int count = typeFormals.length; |
| 1472 if (count > 0) { | 1380 if (count > 0) { |
| (...skipping 116 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1589 // | 1497 // |
| 1590 // <TFrom, TTo extends Iterable<TFrom>> | 1498 // <TFrom, TTo extends Iterable<TFrom>> |
| 1591 // | 1499 // |
| 1592 // Or if the type parameter's bound depends on itself such as: | 1500 // Or if the type parameter's bound depends on itself such as: |
| 1593 // | 1501 // |
| 1594 // <T extends Clonable<T>> | 1502 // <T extends Clonable<T>> |
| 1595 DartType declaredUpperBound = typeParam.element.bound; | 1503 DartType declaredUpperBound = typeParam.element.bound; |
| 1596 if (declaredUpperBound != null) { | 1504 if (declaredUpperBound != null) { |
| 1597 // Assert that the type parameter is a subtype of its bound. | 1505 // Assert that the type parameter is a subtype of its bound. |
| 1598 _inferTypeParameterSubtypeOf(typeParam, | 1506 _inferTypeParameterSubtypeOf(typeParam, |
| 1599 declaredUpperBound.substitute2(inferredTypes, fnTypeParams), null); | 1507 declaredUpperBound.substitute2(inferredTypes, fnTypeParams)); |
| 1600 } | 1508 } |
| 1601 | 1509 |
| 1602 // Now we've computed lower and upper bounds for each type parameter. | 1510 // Now we've computed lower and upper bounds for each type parameter. |
| 1603 // | 1511 // |
| 1604 // To decide on which type to assign, we look at the return type and see | 1512 // To decide on which type to assign, we look at the return type and see |
| 1605 // if the type parameter occurs in covariant or contravariant positions. | 1513 // if the type parameter occurs in covariant or contravariant positions. |
| 1606 // | 1514 // |
| 1607 // If the type is "passed in" at all, or if our lower bound was bottom, | 1515 // If the type is "passed in" at all, or if our lower bound was bottom, |
| 1608 // we choose the upper bound as being the most useful. | 1516 // we choose the upper bound as being the most useful. |
| 1609 // | 1517 // |
| 1610 // Otherwise we choose the more precise lower bound. | 1518 // Otherwise we choose the more precise lower bound. |
| 1611 _TypeParameterVariance variance = | 1519 _TypeParameterVariance variance = |
| 1612 new _TypeParameterVariance.from(typeParam, declaredReturnType); | 1520 new _TypeParameterVariance.from(typeParam, declaredReturnType); |
| 1613 | 1521 |
| 1614 _TypeParameterBound bound = _bounds[typeParam]; | 1522 _TypeParameterBound bound = _bounds[typeParam]; |
| 1615 DartType lowerBound = bound.lower; | 1523 DartType lowerBound = bound.lower; |
| 1616 DartType upperBound = bound.upper; | 1524 DartType upperBound = bound.upper; |
| 1617 | 1525 |
| 1618 // Collapse future unions if we inferred them somehow. | |
| 1619 // | |
| 1620 // TODO(jmesserly): in our initial upward phase it would be fine to | |
| 1621 // keep the FutureUnionType for the argument downward context. | |
| 1622 // | |
| 1623 // We need to track in `inferGenericFunctionCall` whether we are going up | |
| 1624 // or down. This would also allow for an improved heuristic: if we are | |
| 1625 // doing our final inference, the downward context can take priority. | |
| 1626 if (lowerBound is FutureUnionType) { | |
| 1627 // lowerBound <: T, where lowerBound is Future<A> | A. | |
| 1628 // So we choose lowerBound as LUB(A, Future<A>). | |
| 1629 // | |
| 1630 // This will typically lead to top with the current rules, but it will | |
| 1631 // work with `bottom` or if we remove Future flattening. | |
| 1632 var f = lowerBound as FutureUnionType; | |
| 1633 lowerBound = _typeSystem.getLeastUpperBound(f.futureOfType, f.type); | |
| 1634 } | |
| 1635 if (upperBound is FutureUnionType) { | |
| 1636 // T <: upperBound, where upperBound is Future<A> | A. | |
| 1637 // Therefore we need T <: Future<A> or T <: A. | |
| 1638 // | |
| 1639 // This is just an arbitrarily heuristic. | |
| 1640 var f = upperBound as FutureUnionType; | |
| 1641 if (_typeSystem.isSubtypeOf(lowerBound, f.type)) { | |
| 1642 upperBound = f.type; | |
| 1643 } else if (_typeSystem.isSubtypeOf(lowerBound, f.futureOfType)) { | |
| 1644 upperBound = f.futureOfType; | |
| 1645 } else { | |
| 1646 upperBound = f.type; | |
| 1647 } | |
| 1648 } | |
| 1649 | |
| 1650 // See if the bounds can be satisfied. | 1526 // See if the bounds can be satisfied. |
| 1651 // TODO(jmesserly): also we should have an error for unconstrained type | 1527 // TODO(jmesserly): also we should have an error for unconstrained type |
| 1652 // parameters, rather than silently inferring dynamic. | 1528 // parameters, rather than silently inferring dynamic. |
| 1653 if (upperBound.isBottom || | 1529 if (upperBound.isBottom || |
| 1654 !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { | 1530 !_typeSystem.isSubtypeOf(lowerBound, upperBound)) { |
| 1655 // Inference failed. | 1531 // Inference failed. |
| 1656 if (errorReporter == null) { | 1532 if (errorReporter == null) { |
| 1657 return null; | 1533 return null; |
| 1658 } | 1534 } |
| 1659 errorReporter.reportErrorForNode(StrongModeCode.COULD_NOT_INFER, | 1535 errorReporter.reportErrorForNode(StrongModeCode.COULD_NOT_INFER, |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1679 variance.passedIn && !upperBound.isDynamic || lowerBound.isBottom | 1555 variance.passedIn && !upperBound.isDynamic || lowerBound.isBottom |
| 1680 ? upperBound | 1556 ? upperBound |
| 1681 : lowerBound; | 1557 : lowerBound; |
| 1682 } | 1558 } |
| 1683 | 1559 |
| 1684 // Return the instantiated type. | 1560 // Return the instantiated type. |
| 1685 return genericType.instantiate(inferredTypes) as dynamic/*=T*/; | 1561 return genericType.instantiate(inferredTypes) as dynamic/*=T*/; |
| 1686 } | 1562 } |
| 1687 | 1563 |
| 1688 @override | 1564 @override |
| 1689 bool _inferTypeParameterSubtypeOf( | 1565 bool _inferTypeParameterSubtypeOf(DartType t1, DartType t2) { |
| 1690 DartType t1, DartType t2, Set<Element> visited) { | |
| 1691 if (t1 is TypeParameterType) { | 1566 if (t1 is TypeParameterType) { |
| 1692 _TypeParameterBound bound = _bounds[t1]; | 1567 _TypeParameterBound bound = _bounds[t1]; |
| 1693 if (bound != null) { | 1568 if (bound != null) { |
| 1694 // Ensure T1 <: T2, where T1 is a type parameter we are inferring. | 1569 // Ensure T1 <: T2, where T1 is a type parameter we are inferring. |
| 1695 // T2 is an upper bound, so merge it with our existing upper bound. | 1570 // T2 is an upper bound, so merge it with our existing upper bound. |
| 1696 // | 1571 // |
| 1697 // We already know T1 <: U, for some U. | 1572 // We already know T1 <: U, for some U. |
| 1698 // So update U to reflect the new constraint T1 <: GLB(U, T2) | 1573 // So update U to reflect the new constraint T1 <: GLB(U, T2) |
| 1699 // | 1574 // |
| 1700 bound.upper = _typeSystem.getGreatestLowerBound(bound.upper, t2); | 1575 bound.upper = _typeSystem.getGreatestLowerBound(bound.upper, t2); |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1823 } else { | 1698 } else { |
| 1824 passedOut = true; | 1699 passedOut = true; |
| 1825 } | 1700 } |
| 1826 } else if (type is FunctionType) { | 1701 } else if (type is FunctionType) { |
| 1827 _visitFunctionType(typeParam, type, paramIn); | 1702 _visitFunctionType(typeParam, type, paramIn); |
| 1828 } else if (type is InterfaceType) { | 1703 } else if (type is InterfaceType) { |
| 1829 _visitInterfaceType(typeParam, type, paramIn); | 1704 _visitInterfaceType(typeParam, type, paramIn); |
| 1830 } | 1705 } |
| 1831 } | 1706 } |
| 1832 } | 1707 } |
| OLD | NEW |