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

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: Rebase and address comments 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
« no previous file with comments | « lib/runtime/dart_runtime.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 if (t1.isDynamic) return dynamicIsBottom;
268
266 // Null can be assigned to anything non-primitive. 269 // Null can be assigned to anything non-primitive.
267 // FIXME: Can this be anything besides null? 270 // FIXME: Can this be anything besides null?
268 if (t1.isBottom) { 271 if (t1.isBottom) {
269 // Return false iff t2 *may* be a primitive type. 272 // Return false iff t2 *may* be a primitive type.
270 return !maybeNonNullableType(t2); 273 return !maybeNonNullableType(t2);
271 } 274 }
272 if (t2.isBottom) return false; 275 if (t2.isBottom) return false;
273 276
274 if (t2.isDynamic) return true;
275 if (t1.isDynamic) return false;
276
277 // Trivially true for non-primitives. 277 // Trivially true for non-primitives.
278 if (t2 == provider.objectType) return true; 278 if (t2 == provider.objectType) return true;
279 if (t1 == provider.objectType) return false; 279 if (t1 == provider.objectType) return false;
280 280
281 // S <: T where S is a type variable 281 // S <: T where S is a type variable
282 // T is not dynamic or object (handled above) 282 // T is not dynamic or object (handled above)
283 // S != T (handled above) 283 // S != T (handled above)
284 // So only true if bound of S is S' and 284 // So only true if bound of S is S' and
285 // S' <: T 285 // S' <: T
286 if (t1 is TypeParameterType) { 286 if (t1 is TypeParameterType) {
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
489 return t.isDynamic || t.isDartCoreFunction; 489 return t.isDynamic || t.isDartCoreFunction;
490 } 490 }
491 491
492 /// Returns `true` if the expression is a dynamic function call or method 492 /// Returns `true` if the expression is a dynamic function call or method
493 /// invocation. 493 /// invocation.
494 bool isDynamicCall(Expression call) { 494 bool isDynamicCall(Expression call) {
495 if (options.ignoreTypes) return true; 495 if (options.ignoreTypes) return true;
496 var t = getStaticType(call); 496 var t = getStaticType(call);
497 // TODO(jmesserly): fix handling of types with `call` methods. These are not 497 // TODO(jmesserly): fix handling of types with `call` methods. These are not
498 // FunctionType, but they also aren't dynamic calls. 498 // FunctionType, but they also aren't dynamic calls.
499 return t.isDynamic || t.isDartCoreFunction || t is! FunctionType; 499 if (t.isDynamic || t.isDartCoreFunction || t is! FunctionType) {
500 return true;
501 }
502 // Dynamic as the parameter type is treated as bottom. A function with
503 // a dynamic parameter type requires a dynamic call in general.
504 // However, as an optimization, if we have an original definition, we know
505 // dynamic is reified as Object - in this case a regular call is fine.
506 if (call is SimpleIdentifier) {
507 var element = call.staticElement;
508 if (element is FunctionElement || element is MethodElement) {
509 // An original declaration.
510 return false;
511 }
512 }
513 var ft = t as FunctionType;
514 for (var parameterType in ft.normalParameterTypes) {
515 if (parameterType.isDynamic) return true;
516 }
517 for (var parameterType in ft.optionalParameterTypes) {
518 if (parameterType.isDynamic) return true;
519 }
520 for (var parameterType in ft.namedParameterTypes.values) {
521 if (parameterType.isDynamic) return true;
522 }
523 return false;
500 } 524 }
501 } 525 }
OLDNEW
« no previous file with comments | « lib/runtime/dart_runtime.js ('k') | lib/src/codegen/js_codegen.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698