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

Side by Side Diff: lib/src/checker/rules.dart

Issue 1010893004: Allow S->T <: dynamic->T (Closed) Base URL: https://github.com/dart-lang/dev_compiler.git@master
Patch Set: Add comment Created 5 years, 9 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) 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 dev_compiler.src.checker.rules; 5 library dev_compiler.src.checker.rules;
6 6
7 import 'package:analyzer/src/generated/ast.dart'; 7 import 'package:analyzer/src/generated/ast.dart';
8 import 'package:analyzer/src/generated/element.dart'; 8 import 'package:analyzer/src/generated/element.dart';
9 import 'package:analyzer/src/generated/resolver.dart'; 9 import 'package:analyzer/src/generated/resolver.dart';
10 10
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after
155 FunctionType callType = manager.lookupMemberType(t, "call"); 155 FunctionType callType = manager.lookupMemberType(t, "call");
156 return callType; 156 return callType;
157 } 157 }
158 return null; 158 return null;
159 } 159 }
160 160
161 /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC 161 /// Check that f1 is a subtype of f2. [ignoreReturn] is used in the DDC
162 /// checker to determine whether f1 would be a subtype of f2 if the return 162 /// checker to determine whether f1 would be a subtype of f2 if the return
163 /// type of f1 is set to match f2's return type. 163 /// type of f1 is set to match f2's return type.
164 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2, 164 bool isFunctionSubTypeOf(FunctionType f1, FunctionType f2,
165 {bool ignoreReturn: false}) { 165 {bool dynamicIsBottom: false, bool ignoreReturn: false}) {
166 final r1s = f1.normalParameterTypes; 166 final r1s = f1.normalParameterTypes;
167 final o1s = f1.optionalParameterTypes; 167 final o1s = f1.optionalParameterTypes;
168 final n1s = f1.namedParameterTypes; 168 final n1s = f1.namedParameterTypes;
169 final r2s = f2.normalParameterTypes; 169 final r2s = f2.normalParameterTypes;
170 final o2s = f2.optionalParameterTypes; 170 final o2s = f2.optionalParameterTypes;
171 final n2s = f2.namedParameterTypes; 171 final n2s = f2.namedParameterTypes;
172 final ret1 = ignoreReturn ? f2.returnType : f1.returnType; 172 final ret1 = ignoreReturn ? f2.returnType : f1.returnType;
173 final ret2 = f2.returnType; 173 final ret2 = f2.returnType;
174 174
175 // A -> B <: C -> D if C <: A and 175 // A -> B <: C -> D if C <: A and
176 // either D is void or B <: D 176 // either D is void or B <: D
177 if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false; 177 if (!ret2.isVoid && !isSubTypeOf(ret1, ret2)) return false;
178 178
179 // Reject if one has named and the other has optional 179 // Reject if one has named and the other has optional
180 if (n1s.length > 0 && o2s.length > 0) return false; 180 if (n1s.length > 0 && o2s.length > 0) return false;
181 if (n2s.length > 0 && o1s.length > 0) return false; 181 if (n2s.length > 0 && o1s.length > 0) return false;
182 182
183 // f2 has named parameters 183 // f2 has named parameters
184 if (n2s.length > 0) { 184 if (n2s.length > 0) {
185 // Check that every named parameter in f2 has a match in f1 185 // Check that every named parameter in f2 has a match in f1
186 for (String k2 in n2s.keys) { 186 for (String k2 in n2s.keys) {
187 if (!n1s.containsKey(k2)) return false; 187 if (!n1s.containsKey(k2)) return false;
188 if (!isSubTypeOf(n2s[k2], n1s[k2])) return false; 188 if (!isSubTypeOf(n2s[k2], n1s[k2], dynamicIsBottom: true)) return false;
189 } 189 }
190 } 190 }
191 // If we get here, we either have no named parameters, 191 // If we get here, we either have no named parameters,
192 // or else the named parameters match and we have no optional 192 // or else the named parameters match and we have no optional
193 // parameters 193 // parameters
194 194
195 // If f1 has more required parameters, reject 195 // If f1 has more required parameters, reject
196 if (r1s.length > r2s.length) return false; 196 if (r1s.length > r2s.length) return false;
197 197
198 // If f2 has more required + optional parameters, reject 198 // If f2 has more required + optional parameters, reject
199 if (r2s.length + o2s.length > r1s.length + o1s.length) return false; 199 if (r2s.length + o2s.length > r1s.length + o1s.length) return false;
200 200
201 // The parameter lists must look like the following at this point 201 // The parameter lists must look like the following at this point
202 // where rrr is a region of required, and ooo is a region of optionals. 202 // where rrr is a region of required, and ooo is a region of optionals.
203 // f1: rrr ooo ooo ooo 203 // f1: rrr ooo ooo ooo
204 // f2: rrr rrr ooo 204 // f2: rrr rrr ooo
205 int rr = r1s.length; // required in both 205 int rr = r1s.length; // required in both
206 int or = r2s.length - r1s.length; // optional in f1, required in f2 206 int or = r2s.length - r1s.length; // optional in f1, required in f2
207 int oo = o2s.length; // optional in both 207 int oo = o2s.length; // optional in both
208 208
209 for (int i = 0; i < rr; ++i) { 209 for (int i = 0; i < rr; ++i) {
210 if (!isSubTypeOf(r2s[i], r1s[i])) return false; 210 if (!isSubTypeOf(r2s[i], r1s[i], dynamicIsBottom: true)) return false;
211 } 211 }
212 for (int i = 0, j = rr; i < or; ++i, ++j) { 212 for (int i = 0, j = rr; i < or; ++i, ++j) {
213 if (!isSubTypeOf(r2s[j], o1s[i])) return false; 213 if (!isSubTypeOf(r2s[j], o1s[i], dynamicIsBottom: true)) return false;
214 } 214 }
215 for (int i = or, j = 0; i < oo; ++i, ++j) { 215 for (int i = or, j = 0; i < oo; ++i, ++j) {
216 if (!isSubTypeOf(o2s[j], o1s[i])) return false; 216 if (!isSubTypeOf(o2s[j], o1s[i], dynamicIsBottom: true)) return false;
217 } 217 }
218 return true; 218 return true;
219 } 219 }
220 220
221 bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) { 221 bool _isInterfaceSubTypeOf(InterfaceType i1, InterfaceType i2) {
222 if (i1 == i2) return true; 222 if (i1 == i2) return true;
223 223
224 if (i1.element == i2.element) { 224 if (i1.element == i2.element) {
225 List<DartType> tArgs1 = i1.typeArguments; 225 List<DartType> tArgs1 = i1.typeArguments;
226 List<DartType> tArgs2 = i2.typeArguments; 226 List<DartType> tArgs2 = i2.typeArguments;
(...skipping 26 matching lines...) Expand all
253 if (_isInterfaceSubTypeOf(parent, i2)) return true; 253 if (_isInterfaceSubTypeOf(parent, i2)) return true;
254 } 254 }
255 255
256 for (final parent in i1.mixins) { 256 for (final parent in i1.mixins) {
257 if (_isInterfaceSubTypeOf(parent, i2)) return true; 257 if (_isInterfaceSubTypeOf(parent, i2)) return true;
258 } 258 }
259 259
260 return false; 260 return false;
261 } 261 }
262 262
263 bool isSubTypeOf(DartType t1, DartType t2) { 263 bool isSubTypeOf(DartType t1, DartType t2, {bool dynamicIsBottom: false}) {
264 if (t1 == t2) return true; 264 if (t1 == t2) return true;
265 265
266 if (t2.isDynamic) return !dynamicIsBottom;
267 // In negative state, dynamic acts as bottom as well as top, but in a
Leaf 2015/03/18 22:57:25 This comment I think is left over from the polarit
vsm 2015/03/18 23:40:32 Done.
268 // positive (normal) state, we disallow this subtyping.
269 if (t1.isDynamic) return dynamicIsBottom;
270
266 // Null can be assigned to anything non-primitive. 271 // Null can be assigned to anything non-primitive.
267 // FIXME: Can this be anything besides null? 272 // FIXME: Can this be anything besides null?
268 if (t1.isBottom) { 273 if (t1.isBottom) {
269 // Return false iff t2 *may* be a primitive type. 274 // Return false iff t2 *may* be a primitive type.
270 return !maybeNonNullableType(t2); 275 return !maybeNonNullableType(t2);
271 } 276 }
272 if (t2.isBottom) return false; 277 if (t2.isBottom) return false;
273 278
274 if (t2.isDynamic) return true;
275 if (t1.isDynamic) return false;
276
277 // Trivially true for non-primitives. 279 // Trivially true for non-primitives.
278 if (t2 == provider.objectType) return true; 280 if (t2 == provider.objectType) return true;
279 if (t1 == provider.objectType) return false; 281 if (t1 == provider.objectType) return false;
280 282
281 // S <: T where S is a type variable 283 // S <: T where S is a type variable
282 // T is not dynamic or object (handled above) 284 // T is not dynamic or object (handled above)
283 // S != T (handled above) 285 // S != T (handled above)
284 // So only true if bound of S is S' and 286 // So only true if bound of S is S' and
285 // S' <: T 287 // S' <: T
286 if (t1 is TypeParameterType) { 288 if (t1 is TypeParameterType) {
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 return t.isDynamic || t.isDartCoreFunction; 491 return t.isDynamic || t.isDartCoreFunction;
490 } 492 }
491 493
492 /// Returns `true` if the expression is a dynamic function call or method 494 /// Returns `true` if the expression is a dynamic function call or method
493 /// invocation. 495 /// invocation.
494 bool isDynamicCall(Expression call) { 496 bool isDynamicCall(Expression call) {
495 if (options.ignoreTypes) return true; 497 if (options.ignoreTypes) return true;
496 var t = getStaticType(call); 498 var t = getStaticType(call);
497 // TODO(jmesserly): fix handling of types with `call` methods. These are not 499 // TODO(jmesserly): fix handling of types with `call` methods. These are not
498 // FunctionType, but they also aren't dynamic calls. 500 // FunctionType, but they also aren't dynamic calls.
499 return t.isDynamic || t.isDartCoreFunction || t is! FunctionType; 501 if (t.isDynamic || t.isDartCoreFunction || t is! FunctionType) {
502 return true;
503 }
504 // Dynamic as the parameter type is treated as bottom. A function with
505 // a dynamic parameter type requires a dynamic call in general.
506 // However, as an optimization, if we have an original definition, we know
507 // dynamic is reified as Object - in this case a regular call is fine.
508 if (call is SimpleIdentifier) {
Leaf 2015/03/18 22:57:25 This could probably be done for at least some pref
vsm 2015/03/18 23:40:32 The "call" expression is the method name (not the
509 var element = call.staticElement;
510 if (element is FunctionElement || element is MethodElement) {
511 // An original declaration.
512 return false;
513 }
514 }
515 var ft = t as FunctionType;
516 for (var parameterType in ft.normalParameterTypes) {
517 if (parameterType.isDynamic) return true;
518 }
519 for (var parameterType in ft.optionalParameterTypes) {
520 if (parameterType.isDynamic) return true;
521 }
522 for (var parameterType in ft.namedParameterTypes.values) {
523 if (parameterType.isDynamic) return true;
524 }
525 return false;
500 } 526 }
501 } 527 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698