Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2014, 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.dart.element.type; | 5 library analyzer.src.dart.element.type; |
| 6 | 6 |
| 7 import 'dart:collection'; | 7 import 'dart:collection'; |
| 8 | 8 |
| 9 import 'package:analyzer/dart/ast/token.dart'; | 9 import 'package:analyzer/dart/ast/token.dart'; |
| 10 import 'package:analyzer/dart/element/element.dart'; | 10 import 'package:analyzer/dart/element/element.dart'; |
| (...skipping 700 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 711 bool operator ==(Object object) { | 711 bool operator ==(Object object) { |
| 712 if (object is FunctionTypeImpl) { | 712 if (object is FunctionTypeImpl) { |
| 713 if (typeFormals.length != object.typeFormals.length) { | 713 if (typeFormals.length != object.typeFormals.length) { |
| 714 return false; | 714 return false; |
| 715 } | 715 } |
| 716 // `<T>T -> T` should be equal to `<U>U -> U` | 716 // `<T>T -> T` should be equal to `<U>U -> U` |
| 717 // To test this, we instantiate both types with the same (unique) type | 717 // To test this, we instantiate both types with the same (unique) type |
| 718 // variables, and see if the result is equal. | 718 // variables, and see if the result is equal. |
| 719 if (typeFormals.isNotEmpty) { | 719 if (typeFormals.isNotEmpty) { |
| 720 List<DartType> freshVariables = | 720 List<DartType> freshVariables = |
| 721 relateTypeFormals(this, object, (t, s) => t == s); | 721 relateTypeFormals(this, object, (t, s, _, __) => t == s); |
| 722 if (freshVariables == null) { | 722 if (freshVariables == null) { |
| 723 return false; | 723 return false; |
| 724 } | 724 } |
| 725 return instantiate(freshVariables) == | 725 return instantiate(freshVariables) == |
| 726 object.instantiate(freshVariables); | 726 object.instantiate(freshVariables); |
| 727 } | 727 } |
| 728 | 728 |
| 729 return returnType == object.returnType && | 729 return returnType == object.returnType && |
| 730 TypeImpl.equalArrays( | 730 TypeImpl.equalArrays( |
| 731 normalParameterTypes, object.normalParameterTypes) && | 731 normalParameterTypes, object.normalParameterTypes) && |
| (...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 888 } | 888 } |
| 889 | 889 |
| 890 @override | 890 @override |
| 891 bool isMoreSpecificThan(DartType type, | 891 bool isMoreSpecificThan(DartType type, |
| 892 [bool withDynamic = false, Set<Element> visitedElements]) { | 892 [bool withDynamic = false, Set<Element> visitedElements]) { |
| 893 // Note: visitedElements is only used for breaking recursion in the type | 893 // Note: visitedElements is only used for breaking recursion in the type |
| 894 // hierarchy; we don't use it when recursing into the function type. | 894 // hierarchy; we don't use it when recursing into the function type. |
| 895 return relate( | 895 return relate( |
| 896 this, | 896 this, |
| 897 type, | 897 type, |
| 898 (DartType t, DartType s, _, __) => | 898 (DartType t, DartType s) => |
| 899 (t as TypeImpl).isMoreSpecificThan(s, withDynamic), | 899 (t as TypeImpl).isMoreSpecificThan(s, withDynamic), |
| 900 new TypeSystemImpl(null).instantiateToBounds); | 900 new TypeSystemImpl(null).instantiateToBounds); |
| 901 } | 901 } |
| 902 | 902 |
| 903 @override | 903 @override |
| 904 bool isSubtypeOf(DartType type) { | 904 bool isSubtypeOf(DartType type) { |
| 905 var typeSystem = new TypeSystemImpl(null); | 905 var typeSystem = new TypeSystemImpl(null); |
| 906 return relate( | 906 return relate( |
| 907 typeSystem.instantiateToBounds(this), | 907 typeSystem.instantiateToBounds(this), |
| 908 typeSystem.instantiateToBounds(type), | 908 typeSystem.instantiateToBounds(type), |
| 909 (DartType t, DartType s, _, __) => t.isAssignableTo(s), | 909 (DartType t, DartType s) => t.isAssignableTo(s), |
| 910 typeSystem.instantiateToBounds); | 910 typeSystem.instantiateToBounds); |
| 911 } | 911 } |
| 912 | 912 |
| 913 @override | 913 @override |
| 914 FunctionTypeImpl pruned(List<FunctionTypeAliasElement> prune) { | 914 FunctionTypeImpl pruned(List<FunctionTypeAliasElement> prune) { |
| 915 if (prune == null) { | 915 if (prune == null) { |
| 916 return this; | 916 return this; |
| 917 } else if (prune.contains(element)) { | 917 } else if (prune.contains(element)) { |
| 918 // Circularity found. Prune the type declaration. | 918 // Circularity found. Prune the type declaration. |
| 919 return new CircularFunctionTypeImpl(); | 919 return new CircularFunctionTypeImpl(); |
| (...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1069 | 1069 |
| 1070 /** | 1070 /** |
| 1071 * Compares two function types [t] and [s] to see if their corresponding | 1071 * Compares two function types [t] and [s] to see if their corresponding |
| 1072 * parameter types match [parameterRelation] and their return types match | 1072 * parameter types match [parameterRelation] and their return types match |
| 1073 * [returnRelation]. | 1073 * [returnRelation]. |
| 1074 * | 1074 * |
| 1075 * Used for the various relations on function types which have the same | 1075 * Used for the various relations on function types which have the same |
| 1076 * structural rules for handling optional parameters and arity, but use their | 1076 * structural rules for handling optional parameters and arity, but use their |
| 1077 * own relation for comparing corresponding parameters or return types. | 1077 * own relation for comparing corresponding parameters or return types. |
| 1078 * | 1078 * |
| 1079 * If [returnRelation] is omitted, uses [parameterRelation] for both. | 1079 * If [parameterRelation] is omitted, uses [returnRelation] for both. This |
| 1080 * is convenient for Dart 1 type system methods. | |
| 1080 */ | 1081 */ |
| 1081 static bool relate( | 1082 static bool relate( |
| 1082 FunctionType t, | 1083 FunctionType t, |
| 1083 DartType other, | 1084 DartType other, |
| 1084 bool parameterRelation( | 1085 bool returnRelation(DartType t, DartType s), |
| 1085 DartType t, DartType s, bool tIsCovariant, bool sIsCovariant), | |
| 1086 DartType instantiateToBounds(DartType t), | 1086 DartType instantiateToBounds(DartType t), |
| 1087 {bool returnRelation(DartType t, DartType s)}) { | 1087 {bool parameterRelation(ParameterElement t, ParameterElement s)}) { |
| 1088 returnRelation ??= (t, s) => parameterRelation(t, s, false, false); | 1088 parameterRelation ??= (t, s) => returnRelation(t.type, s.type); |
| 1089 | 1089 |
| 1090 // Trivial base cases. | 1090 // Trivial base cases. |
| 1091 if (other == null) { | 1091 if (other == null) { |
| 1092 return false; | 1092 return false; |
| 1093 } else if (identical(t, other) || | 1093 } else if (identical(t, other) || |
| 1094 other.isDynamic || | 1094 other.isDynamic || |
| 1095 other.isDartCoreFunction || | 1095 other.isDartCoreFunction || |
| 1096 other.isObject) { | 1096 other.isObject) { |
| 1097 return true; | 1097 return true; |
| 1098 } else if (other is! FunctionType) { | 1098 } else if (other is! FunctionType) { |
| 1099 return false; | 1099 return false; |
| 1100 } | 1100 } |
| 1101 | 1101 |
| 1102 // This type cast is safe, because we checked it above. | 1102 // This type cast is safe, because we checked it above. |
| 1103 FunctionType s = other as FunctionType; | 1103 FunctionType s = other as FunctionType; |
| 1104 if (t.typeFormals.isNotEmpty) { | 1104 if (t.typeFormals.isNotEmpty) { |
| 1105 List<DartType> freshVariables = relateTypeFormals(t, s, returnRelation); | 1105 List<DartType> freshVariables = |
| 1106 relateTypeFormals(t, s, (s, t, _, __) => returnRelation(s, t)); | |
| 1106 if (freshVariables == null) { | 1107 if (freshVariables == null) { |
| 1107 return false; | 1108 return false; |
| 1108 } | 1109 } |
| 1109 t = t.instantiate(freshVariables); | 1110 t = t.instantiate(freshVariables); |
| 1110 s = s.instantiate(freshVariables); | 1111 s = s.instantiate(freshVariables); |
| 1111 } else if (s.typeFormals.isNotEmpty) { | 1112 } else if (s.typeFormals.isNotEmpty) { |
| 1112 return false; | 1113 return false; |
| 1113 } | 1114 } |
| 1114 | 1115 |
| 1115 // Test the return types. | 1116 // Test the return types. |
| 1116 DartType sRetType = s.returnType; | 1117 DartType sRetType = s.returnType; |
| 1117 if (!sRetType.isVoid && !returnRelation(t.returnType, sRetType)) { | 1118 if (!sRetType.isVoid && !returnRelation(t.returnType, sRetType)) { |
| 1118 return false; | 1119 return false; |
| 1119 } | 1120 } |
| 1120 | 1121 |
| 1121 // Test the parameter types. | 1122 // Test the parameter types. |
| 1123 return relateParameters(t.parameters, s.parameters, parameterRelation); | |
| 1124 } | |
| 1122 | 1125 |
| 1126 /** | |
| 1127 * Compares two function types [t] and [s] to see if their corresponding | |
|
Leaf
2017/06/28 18:12:30
Nit: [t] and [s] aren't really parameters to this
Jennifer Messerly
2017/07/05 20:11:21
Done.
| |
| 1128 * parameter types match [parameterRelation]. | |
| 1129 * | |
| 1130 * Used for the various relations on function types which have the same | |
| 1131 * structural rules for handling optional parameters and arity, but use their | |
| 1132 * own relation for comparing corresponding parameter types. | |
| 1133 */ | |
| 1134 static bool relateParameters( | |
| 1135 List<ParameterElement> tParams, | |
| 1136 List<ParameterElement> sParams, | |
| 1137 bool parameterRelation(ParameterElement p1, ParameterElement p2)) { | |
| 1123 // TODO(jmesserly): this could be implemented with less allocation if we | 1138 // TODO(jmesserly): this could be implemented with less allocation if we |
| 1124 // wanted, by taking advantage of the fact that positional arguments must | 1139 // wanted, by taking advantage of the fact that positional arguments must |
| 1125 // appear before named ones. | 1140 // appear before named ones. |
| 1126 var tRequired = <ParameterElement>[]; | 1141 var tRequired = <ParameterElement>[]; |
| 1127 var tOptional = <ParameterElement>[]; | 1142 var tOptional = <ParameterElement>[]; |
| 1128 var tNamed = <String, ParameterElement>{}; | 1143 var tNamed = <String, ParameterElement>{}; |
| 1129 for (var p in t.parameters) { | 1144 for (var p in tParams) { |
| 1130 var kind = p.parameterKind; | 1145 var kind = p.parameterKind; |
| 1131 if (kind == ParameterKind.REQUIRED) { | 1146 if (kind == ParameterKind.REQUIRED) { |
| 1132 tRequired.add(p); | 1147 tRequired.add(p); |
| 1133 } else if (kind == ParameterKind.POSITIONAL) { | 1148 } else if (kind == ParameterKind.POSITIONAL) { |
| 1134 tOptional.add(p); | 1149 tOptional.add(p); |
| 1135 } else { | 1150 } else { |
| 1136 assert(kind == ParameterKind.NAMED); | 1151 assert(kind == ParameterKind.NAMED); |
| 1137 tNamed[p.name] = p; | 1152 tNamed[p.name] = p; |
| 1138 } | 1153 } |
| 1139 } | 1154 } |
| 1140 | 1155 |
| 1141 var sRequired = <ParameterElement>[]; | 1156 var sRequired = <ParameterElement>[]; |
| 1142 var sOptional = <ParameterElement>[]; | 1157 var sOptional = <ParameterElement>[]; |
| 1143 var sNamed = <String, ParameterElement>{}; | 1158 var sNamed = <String, ParameterElement>{}; |
| 1144 for (var p in s.parameters) { | 1159 for (var p in sParams) { |
| 1145 var kind = p.parameterKind; | 1160 var kind = p.parameterKind; |
| 1146 if (kind == ParameterKind.REQUIRED) { | 1161 if (kind == ParameterKind.REQUIRED) { |
| 1147 sRequired.add(p); | 1162 sRequired.add(p); |
| 1148 } else if (kind == ParameterKind.POSITIONAL) { | 1163 } else if (kind == ParameterKind.POSITIONAL) { |
| 1149 sOptional.add(p); | 1164 sOptional.add(p); |
| 1150 } else { | 1165 } else { |
| 1151 assert(kind == ParameterKind.NAMED); | 1166 assert(kind == ParameterKind.NAMED); |
| 1152 sNamed[p.name] = p; | 1167 sNamed[p.name] = p; |
| 1153 } | 1168 } |
| 1154 } | 1169 } |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 1167 } | 1182 } |
| 1168 | 1183 |
| 1169 // For each named parameter in s, make sure we have a corresponding one | 1184 // For each named parameter in s, make sure we have a corresponding one |
| 1170 // that relates. | 1185 // that relates. |
| 1171 for (String key in sNamed.keys) { | 1186 for (String key in sNamed.keys) { |
| 1172 var tParam = tNamed[key]; | 1187 var tParam = tNamed[key]; |
| 1173 if (tParam == null) { | 1188 if (tParam == null) { |
| 1174 return false; | 1189 return false; |
| 1175 } | 1190 } |
| 1176 var sParam = sNamed[key]; | 1191 var sParam = sNamed[key]; |
| 1177 if (!parameterRelation( | 1192 if (!parameterRelation(tParam, sParam)) { |
| 1178 tParam.type, sParam.type, tParam.isCovariant, sParam.isCovariant)) { | |
| 1179 return false; | 1193 return false; |
| 1180 } | 1194 } |
| 1181 } | 1195 } |
| 1182 | 1196 |
| 1183 // Make sure all of the positional parameters (both required and optional) | 1197 // Make sure all of the positional parameters (both required and optional) |
| 1184 // relate to each other. | 1198 // relate to each other. |
| 1185 var tPositional = tRequired; | 1199 var tPositional = tRequired; |
| 1186 var sPositional = sRequired; | 1200 var sPositional = sRequired; |
| 1187 | 1201 |
| 1188 if (tOptional.isNotEmpty) { | 1202 if (tOptional.isNotEmpty) { |
| 1189 tPositional = tPositional.toList()..addAll(tOptional); | 1203 tPositional = tPositional.toList()..addAll(tOptional); |
| 1190 } | 1204 } |
| 1191 | 1205 |
| 1192 if (sOptional.isNotEmpty) { | 1206 if (sOptional.isNotEmpty) { |
| 1193 sPositional = sPositional.toList()..addAll(sOptional); | 1207 sPositional = sPositional.toList()..addAll(sOptional); |
| 1194 } | 1208 } |
| 1195 | 1209 |
| 1196 // Check that s has enough required parameters. | 1210 // Check that s has enough required parameters. |
| 1197 if (sRequired.length < tRequired.length) { | 1211 if (sRequired.length < tRequired.length) { |
| 1198 return false; | 1212 return false; |
| 1199 } | 1213 } |
| 1200 | 1214 |
| 1201 // Check that s does not include more positional parameters than we do. | 1215 // Check that s does not include more positional parameters than we do. |
| 1202 if (tPositional.length < sPositional.length) { | 1216 if (tPositional.length < sPositional.length) { |
| 1203 return false; | 1217 return false; |
| 1204 } | 1218 } |
| 1205 | 1219 |
| 1206 for (int i = 0; i < sPositional.length; i++) { | 1220 for (int i = 0; i < sPositional.length; i++) { |
| 1207 var tParam = tPositional[i]; | 1221 if (!parameterRelation(tPositional[i], sPositional[i])) { |
| 1208 var sParam = sPositional[i]; | |
| 1209 if (!parameterRelation( | |
| 1210 tParam.type, sParam.type, tParam.isCovariant, sParam.isCovariant)) { | |
| 1211 return false; | 1222 return false; |
| 1212 } | 1223 } |
| 1213 } | 1224 } |
| 1214 | 1225 |
| 1215 return true; | 1226 return true; |
| 1216 } | 1227 } |
| 1217 | 1228 |
| 1218 /** | 1229 /** |
| 1219 * Given two functions [f1] and [f2] where f1 and f2 are known to be | 1230 * Given two functions [f1] and [f2] where f1 and f2 are known to be |
| 1220 * generic function types (both have type formals), this checks that they | 1231 * generic function types (both have type formals), this checks that they |
| 1221 * have the same number of formals, and that those formals have bounds | 1232 * have the same number of formals, and that those formals have bounds |
| 1222 * (e.g. `<T extends LowerBound>`) that satisfy [relation]. | 1233 * (e.g. `<T extends LowerBound>`) that satisfy [relation]. |
| 1223 * | 1234 * |
| 1224 * The return value will be a new list of fresh type variables, that can be | 1235 * The return value will be a new list of fresh type variables, that can be |
| 1225 * used to instantiate both function types, allowing further comparison. | 1236 * used to instantiate both function types, allowing further comparison. |
| 1226 * For example, given `<T>T -> T` and `<U>U -> U` we can instantiate them with | 1237 * For example, given `<T>T -> T` and `<U>U -> U` we can instantiate them with |
| 1227 * `F` to get `F -> F` and `F -> F`, which we can see are equal. | 1238 * `F` to get `F -> F` and `F -> F`, which we can see are equal. |
| 1228 */ | 1239 */ |
| 1229 static List<DartType> relateTypeFormals( | 1240 static List<DartType> relateTypeFormals( |
| 1230 FunctionType f1, FunctionType f2, bool relation(DartType t, DartType s)) { | 1241 FunctionType f1, |
| 1242 FunctionType f2, | |
| 1243 bool relation(DartType bound2, DartType bound1, | |
| 1244 TypeParameterElement formal2, TypeParameterElement formal1)) { | |
| 1231 List<TypeParameterElement> params1 = f1.typeFormals; | 1245 List<TypeParameterElement> params1 = f1.typeFormals; |
| 1232 List<TypeParameterElement> params2 = f2.typeFormals; | 1246 List<TypeParameterElement> params2 = f2.typeFormals; |
| 1233 int count = params1.length; | 1247 int count = params1.length; |
| 1234 if (params2.length != count) { | 1248 if (params2.length != count) { |
| 1235 return null; | 1249 return null; |
| 1236 } | 1250 } |
| 1237 // We build up a substitution matching up the type parameters | 1251 // We build up a substitution matching up the type parameters |
| 1238 // from the two types, {variablesFresh/variables1} and | 1252 // from the two types, {variablesFresh/variables1} and |
| 1239 // {variablesFresh/variables2} | 1253 // {variablesFresh/variables2} |
| 1240 List<DartType> variables1 = <DartType>[]; | 1254 List<DartType> variables1 = <DartType>[]; |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 1251 DartType variableFresh = new TypeParameterTypeImpl(pFresh); | 1265 DartType variableFresh = new TypeParameterTypeImpl(pFresh); |
| 1252 | 1266 |
| 1253 variables1.add(variable1); | 1267 variables1.add(variable1); |
| 1254 variables2.add(variable2); | 1268 variables2.add(variable2); |
| 1255 variablesFresh.add(variableFresh); | 1269 variablesFresh.add(variableFresh); |
| 1256 DartType bound1 = p1.bound ?? DynamicTypeImpl.instance; | 1270 DartType bound1 = p1.bound ?? DynamicTypeImpl.instance; |
| 1257 DartType bound2 = p2.bound ?? DynamicTypeImpl.instance; | 1271 DartType bound2 = p2.bound ?? DynamicTypeImpl.instance; |
| 1258 bound1 = bound1.substitute2(variablesFresh, variables1); | 1272 bound1 = bound1.substitute2(variablesFresh, variables1); |
| 1259 bound2 = bound2.substitute2(variablesFresh, variables2); | 1273 bound2 = bound2.substitute2(variablesFresh, variables2); |
| 1260 pFresh.bound = bound2; | 1274 pFresh.bound = bound2; |
| 1261 if (!relation(bound2, bound1)) { | 1275 if (!relation(bound2, bound1, p2, p1)) { |
| 1262 return null; | 1276 return null; |
| 1263 } | 1277 } |
| 1264 } | 1278 } |
| 1265 return variablesFresh; | 1279 return variablesFresh; |
| 1266 } | 1280 } |
| 1267 | 1281 |
| 1268 /** | 1282 /** |
| 1269 * Return `true` if all of the name/type pairs in the first map ([firstTypes]) | 1283 * Return `true` if all of the name/type pairs in the first map ([firstTypes]) |
| 1270 * are equal to the corresponding name/type pairs in the second map | 1284 * are equal to the corresponding name/type pairs in the second map |
| 1271 * ([secondTypes]). The maps are expected to iterate over their entries in the | 1285 * ([secondTypes]). The maps are expected to iterate over their entries in the |
| (...skipping 1666 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2938 | 2952 |
| 2939 @override | 2953 @override |
| 2940 TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this; | 2954 TypeImpl pruned(List<FunctionTypeAliasElement> prune) => this; |
| 2941 | 2955 |
| 2942 @override | 2956 @override |
| 2943 VoidTypeImpl substitute2( | 2957 VoidTypeImpl substitute2( |
| 2944 List<DartType> argumentTypes, List<DartType> parameterTypes, | 2958 List<DartType> argumentTypes, List<DartType> parameterTypes, |
| 2945 [List<FunctionTypeAliasElement> prune]) => | 2959 [List<FunctionTypeAliasElement> prune]) => |
| 2946 this; | 2960 this; |
| 2947 } | 2961 } |
| OLD | NEW |