Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(275)

Side by Side Diff: pkg/analyzer/lib/src/dart/element/type.dart

Issue 2954523002: fix #27259, implement covariance checking for strong mode and DDC (Closed)
Patch Set: rebase Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/lib/src/generated/resolver.dart » ('j') | pkg/analyzer/lib/src/generated/type_system.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698