OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 dart2js.world; | 5 library dart2js.world; |
6 | 6 |
7 import 'closure.dart' show SynthesizedCallMethodElementX; | 7 import 'closure.dart' show SynthesizedCallMethodElementX; |
8 import 'common/backend_api.dart' show Backend; | 8 import 'common/backend_api.dart' show Backend; |
9 import 'common.dart'; | 9 import 'common.dart'; |
10 import 'compiler.dart' show Compiler; | 10 import 'compiler.dart' show Compiler; |
(...skipping 23 matching lines...) Expand all Loading... | |
34 /// it, what functions are called, what classes are allocated, which native | 34 /// it, what functions are called, what classes are allocated, which native |
35 /// JavaScript types are touched, what language features are used, and so on. | 35 /// JavaScript types are touched, what language features are used, and so on. |
36 /// This precise knowledge about what's live in the program is later used in | 36 /// This precise knowledge about what's live in the program is later used in |
37 /// optimizations and other compiler decisions during code generation. | 37 /// optimizations and other compiler decisions during code generation. |
38 abstract class ClassWorld { | 38 abstract class ClassWorld { |
39 // TODO(johnniwinther): Refine this into a `BackendClasses` interface. | 39 // TODO(johnniwinther): Refine this into a `BackendClasses` interface. |
40 Backend get backend; | 40 Backend get backend; |
41 | 41 |
42 CoreClasses get coreClasses; | 42 CoreClasses get coreClasses; |
43 | 43 |
44 /// Returns `true` if the class world is closed. | |
45 bool get isClosed; | |
46 | |
47 /// Returns `true` if closed-world assumptions can be made, that is, | |
48 /// incremental compilation isn't enabled. | |
49 bool get hasClosedWorldAssumption; | |
50 | |
51 /// Returns a string representation of the closed world. | |
52 /// | |
53 /// If [cls] is provided, the dump will contain only classes related to [cls]. | |
54 String dump([ClassElement cls]); | |
Harry Terkelsen
2016/09/23 17:20:27
@OnlyForTesting? Or whatever the annotation is?
Johnni Winther
2016/09/26 14:02:47
Haven't heard of it. Can you find its exactly loca
| |
55 | |
56 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies | |
57 /// of known classes. | |
58 /// | |
59 /// This method is only provided for testing. For queries on classes, use the | |
60 /// methods defined in [ClassWorld]. | |
61 ClassHierarchyNode getClassHierarchyNode(ClassElement cls); | |
62 | |
63 /// Returns [ClassSet] for [cls] used to model the extends and implements | |
64 /// relations of known classes. | |
65 /// | |
66 /// This method is only provided for testing. For queries on classes, use the | |
67 /// methods defined in [ClassWorld]. | |
68 ClassSet getClassSet(ClassElement cls); | |
69 | |
70 // TODO(johnniwinther): Find a better strategy for caching these. | |
71 @deprecated | |
72 List<Map<ClassElement, TypeMask>> get canonicalizedTypeMasks; | |
73 } | |
74 | |
75 /// The [ClosedWorld] represents the information known about a program when | |
76 /// compiling with closed-world semantics. | |
77 /// | |
78 /// This expands [ClassWorld] with information about live functions, | |
79 /// side effects, and selectors with known single targets. | |
80 abstract class ClosedWorld extends ClassWorld { | |
44 /// Returns `true` if [cls] is either directly or indirectly instantiated. | 81 /// Returns `true` if [cls] is either directly or indirectly instantiated. |
45 bool isInstantiated(ClassElement cls); | 82 bool isInstantiated(ClassElement cls); |
46 | 83 |
47 /// Returns `true` if [cls] is directly instantiated. | 84 /// Returns `true` if [cls] is directly instantiated. |
48 bool isDirectlyInstantiated(ClassElement cls); | 85 bool isDirectlyInstantiated(ClassElement cls); |
49 | 86 |
50 /// Returns `true` if [cls] is indirectly instantiated, that is through a | 87 /// Returns `true` if [cls] is indirectly instantiated, that is through a |
51 /// subclass. | 88 /// subclass. |
52 bool isIndirectlyInstantiated(ClassElement cls); | 89 bool isIndirectlyInstantiated(ClassElement cls); |
53 | 90 |
54 /// Returns `true` if [cls] is implemented by an instantiated class. | 91 /// Returns `true` if [cls] is implemented by an instantiated class. |
55 bool isImplemented(ClassElement cls); | 92 bool isImplemented(ClassElement cls); |
56 | 93 |
57 /// Returns `true` if the class world is closed. | |
58 bool get isClosed; | |
59 | |
60 /// Return `true` if [x] is a subclass of [y]. | 94 /// Return `true` if [x] is a subclass of [y]. |
61 bool isSubclassOf(ClassElement x, ClassElement y); | 95 bool isSubclassOf(ClassElement x, ClassElement y); |
62 | 96 |
63 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an | 97 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an |
64 /// instance of [y]. | 98 /// instance of [y]. |
65 bool isSubtypeOf(ClassElement x, ClassElement y); | 99 bool isSubtypeOf(ClassElement x, ClassElement y); |
66 | 100 |
67 /// Returns an iterable over the live classes that extend [cls] including | 101 /// Returns an iterable over the live classes that extend [cls] including |
68 /// [cls] itself. | 102 /// [cls] itself. |
69 Iterable<ClassElement> subclassesOf(ClassElement cls); | 103 Iterable<ClassElement> subclassesOf(ClassElement cls); |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
148 /// Returns `true` if [cls] or any superclass mixes in [mixin]. | 182 /// Returns `true` if [cls] or any superclass mixes in [mixin]. |
149 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin); | 183 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin); |
150 | 184 |
151 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass | 185 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass |
152 /// of a mixin application of [y]. | 186 /// of a mixin application of [y]. |
153 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y); | 187 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y); |
154 | 188 |
155 /// Returns `true` if any subclass of [superclass] implements [type]. | 189 /// Returns `true` if any subclass of [superclass] implements [type]. |
156 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type); | 190 bool hasAnySubclassThatImplements(ClassElement superclass, ClassElement type); |
157 | 191 |
158 /// Returns `true` if closed-world assumptions can be made, that is, | |
159 /// incremental compilation isn't enabled. | |
160 bool get hasClosedWorldAssumption; | |
161 | |
162 /// Returns a string representation of the closed world. | |
163 /// | |
164 /// If [cls] is provided, the dump will contain only classes related to [cls]. | |
165 String dump([ClassElement cls]); | |
166 | |
167 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies | |
168 /// of known classes. | |
169 /// | |
170 /// This method is only provided for testing. For queries on classes, use the | |
171 /// methods defined in [ClassWorld]. | |
172 ClassHierarchyNode getClassHierarchyNode(ClassElement cls); | |
173 | |
174 /// Returns [ClassSet] for [cls] used to model the extends and implements | |
175 /// relations of known classes. | |
176 /// | |
177 /// This method is only provided for testing. For queries on classes, use the | |
178 /// methods defined in [ClassWorld]. | |
179 ClassSet getClassSet(ClassElement cls); | |
180 | |
181 // TODO(johnniwinther): Find a better strategy for caching these. | |
182 @deprecated | |
183 List<Map<ClassElement, TypeMask>> get canonicalizedTypeMasks; | |
184 } | |
185 | |
186 /// The [ClosedWorld] represents the information known about a program when | |
187 /// compiling with closed-world semantics. | |
188 /// | |
189 /// This expands [ClassWorld] with information about live functions, | |
190 /// side effects, and selectors with known single targets. | |
191 abstract class ClosedWorld extends ClassWorld { | |
192 /// Returns the [FunctionSet] containing all live functions in the closed | 192 /// Returns the [FunctionSet] containing all live functions in the closed |
193 /// world. | 193 /// world. |
194 FunctionSet get allFunctions; | 194 FunctionSet get allFunctions; |
195 | 195 |
196 /// Returns `true` if the field [element] is known to be effectively final. | 196 /// Returns `true` if the field [element] is known to be effectively final. |
197 bool fieldNeverChanges(Element element); | 197 bool fieldNeverChanges(Element element); |
198 | 198 |
199 /// Extends the receiver type [mask] for calling [selector] to take live | 199 /// Extends the receiver type [mask] for calling [selector] to take live |
200 /// `noSuchMethod` handlers into account. | 200 /// `noSuchMethod` handlers into account. |
201 TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask); | 201 TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
298 // TODO(johnniwinther): Reinsert this or similar invariant. | 298 // TODO(johnniwinther): Reinsert this or similar invariant. |
299 (!mustBeInstantiated || | 299 (!mustBeInstantiated || |
300 invariant(cls, isInstantiated(cls), | 300 invariant(cls, isInstantiated(cls), |
301 message: '$cls is not instantiated.'))*/ | 301 message: '$cls is not instantiated.'))*/ |
302 ; | 302 ; |
303 } | 303 } |
304 | 304 |
305 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an | 305 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an |
306 /// instance of [y]. | 306 /// instance of [y]. |
307 bool isSubtypeOf(ClassElement x, ClassElement y) { | 307 bool isSubtypeOf(ClassElement x, ClassElement y) { |
308 assert(isClosed); | |
308 assert(checkInvariants(x)); | 309 assert(checkInvariants(x)); |
309 assert(checkInvariants(y, mustBeInstantiated: false)); | 310 assert(checkInvariants(y, mustBeInstantiated: false)); |
310 | 311 |
311 if (y == coreClasses.objectClass) return true; | 312 if (y == coreClasses.objectClass) return true; |
312 if (x == coreClasses.objectClass) return false; | 313 if (x == coreClasses.objectClass) return false; |
313 if (x.asInstanceOf(y) != null) return true; | 314 if (x.asInstanceOf(y) != null) return true; |
314 if (y != coreClasses.functionClass) return false; | 315 if (y != coreClasses.functionClass) return false; |
315 return x.callType != null; | 316 return x.callType != null; |
316 } | 317 } |
317 | 318 |
318 /// Return `true` if [x] is a (non-strict) subclass of [y]. | 319 /// Return `true` if [x] is a (non-strict) subclass of [y]. |
319 bool isSubclassOf(ClassElement x, ClassElement y) { | 320 bool isSubclassOf(ClassElement x, ClassElement y) { |
321 assert(isClosed); | |
320 assert(checkInvariants(x)); | 322 assert(checkInvariants(x)); |
321 assert(checkInvariants(y)); | 323 assert(checkInvariants(y)); |
322 | 324 |
323 if (y == coreClasses.objectClass) return true; | 325 if (y == coreClasses.objectClass) return true; |
324 if (x == coreClasses.objectClass) return false; | 326 if (x == coreClasses.objectClass) return false; |
325 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { | 327 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { |
326 if (x == y) return true; | 328 if (x == y) return true; |
327 x = x.superclass; | 329 x = x.superclass; |
328 } | 330 } |
329 return false; | 331 return false; |
330 } | 332 } |
331 | 333 |
332 @override | 334 @override |
333 bool isInstantiated(ClassElement cls) { | 335 bool isInstantiated(ClassElement cls) { |
336 assert(isClosed); | |
334 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 337 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; |
335 return node != null && node.isInstantiated; | 338 return node != null && node.isInstantiated; |
336 } | 339 } |
337 | 340 |
338 @override | 341 @override |
339 bool isDirectlyInstantiated(ClassElement cls) { | 342 bool isDirectlyInstantiated(ClassElement cls) { |
343 assert(isClosed); | |
340 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 344 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; |
341 return node != null && node.isDirectlyInstantiated; | 345 return node != null && node.isDirectlyInstantiated; |
342 } | 346 } |
343 | 347 |
344 @override | 348 @override |
345 bool isIndirectlyInstantiated(ClassElement cls) { | 349 bool isIndirectlyInstantiated(ClassElement cls) { |
350 assert(isClosed); | |
346 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 351 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; |
347 return node != null && node.isIndirectlyInstantiated; | 352 return node != null && node.isIndirectlyInstantiated; |
348 } | 353 } |
349 | 354 |
350 /// Returns `true` if [cls] is implemented by an instantiated class. | 355 /// Returns `true` if [cls] is implemented by an instantiated class. |
351 bool isImplemented(ClassElement cls) { | 356 bool isImplemented(ClassElement cls) { |
357 assert(isClosed); | |
352 return _compiler.resolverWorld.isImplemented(cls); | 358 return _compiler.resolverWorld.isImplemented(cls); |
353 } | 359 } |
354 | 360 |
355 /// Returns an iterable over the directly instantiated classes that extend | 361 /// Returns an iterable over the directly instantiated classes that extend |
356 /// [cls] possibly including [cls] itself, if it is live. | 362 /// [cls] possibly including [cls] itself, if it is live. |
357 Iterable<ClassElement> subclassesOf(ClassElement cls) { | 363 Iterable<ClassElement> subclassesOf(ClassElement cls) { |
364 assert(isClosed); | |
358 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 365 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; |
359 if (hierarchy == null) return const <ClassElement>[]; | 366 if (hierarchy == null) return const <ClassElement>[]; |
360 return hierarchy.subclassesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED); | 367 return hierarchy.subclassesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED); |
361 } | 368 } |
362 | 369 |
363 /// Returns an iterable over the directly instantiated classes that extend | 370 /// Returns an iterable over the directly instantiated classes that extend |
364 /// [cls] _not_ including [cls] itself. | 371 /// [cls] _not_ including [cls] itself. |
365 Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { | 372 Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { |
373 assert(isClosed); | |
366 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 374 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
367 if (subclasses == null) return const <ClassElement>[]; | 375 if (subclasses == null) return const <ClassElement>[]; |
368 return subclasses.subclassesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 376 return subclasses.subclassesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
369 strict: true); | 377 strict: true); |
370 } | 378 } |
371 | 379 |
372 /// Returns the number of live classes that extend [cls] _not_ | 380 /// Returns the number of live classes that extend [cls] _not_ |
373 /// including [cls] itself. | 381 /// including [cls] itself. |
374 int strictSubclassCount(ClassElement cls) { | 382 int strictSubclassCount(ClassElement cls) { |
383 assert(isClosed); | |
375 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 384 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
376 if (subclasses == null) return 0; | 385 if (subclasses == null) return 0; |
377 return subclasses.instantiatedSubclassCount; | 386 return subclasses.instantiatedSubclassCount; |
378 } | 387 } |
379 | 388 |
380 /// Applies [f] to each live class that extend [cls] _not_ including [cls] | 389 /// Applies [f] to each live class that extend [cls] _not_ including [cls] |
381 /// itself. | 390 /// itself. |
382 void forEachStrictSubclassOf( | 391 void forEachStrictSubclassOf( |
383 ClassElement cls, IterationStep f(ClassElement cls)) { | 392 ClassElement cls, IterationStep f(ClassElement cls)) { |
393 assert(isClosed); | |
384 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 394 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
385 if (subclasses == null) return; | 395 if (subclasses == null) return; |
386 subclasses.forEachSubclass(f, ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 396 subclasses.forEachSubclass(f, ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
387 strict: true); | 397 strict: true); |
388 } | 398 } |
389 | 399 |
390 /// Returns `true` if [predicate] applies to any live class that extend [cls] | 400 /// Returns `true` if [predicate] applies to any live class that extend [cls] |
391 /// _not_ including [cls] itself. | 401 /// _not_ including [cls] itself. |
392 bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls)) { | 402 bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls)) { |
403 assert(isClosed); | |
393 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 404 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
394 if (subclasses == null) return false; | 405 if (subclasses == null) return false; |
395 return subclasses.anySubclass( | 406 return subclasses.anySubclass( |
396 predicate, ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 407 predicate, ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
397 strict: true); | 408 strict: true); |
398 } | 409 } |
399 | 410 |
400 /// Returns an iterable over the directly instantiated that implement [cls] | 411 /// Returns an iterable over the directly instantiated that implement [cls] |
401 /// possibly including [cls] itself, if it is live. | 412 /// possibly including [cls] itself, if it is live. |
402 Iterable<ClassElement> subtypesOf(ClassElement cls) { | 413 Iterable<ClassElement> subtypesOf(ClassElement cls) { |
414 assert(isClosed); | |
403 ClassSet classSet = _classSets[cls.declaration]; | 415 ClassSet classSet = _classSets[cls.declaration]; |
404 if (classSet == null) { | 416 if (classSet == null) { |
405 return const <ClassElement>[]; | 417 return const <ClassElement>[]; |
406 } else { | 418 } else { |
407 return classSet.subtypesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED); | 419 return classSet.subtypesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED); |
408 } | 420 } |
409 } | 421 } |
410 | 422 |
411 /// Returns an iterable over the directly instantiated that implement [cls] | 423 /// Returns an iterable over the directly instantiated that implement [cls] |
412 /// _not_ including [cls]. | 424 /// _not_ including [cls]. |
413 Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { | 425 Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { |
426 assert(isClosed); | |
414 ClassSet classSet = _classSets[cls.declaration]; | 427 ClassSet classSet = _classSets[cls.declaration]; |
415 if (classSet == null) { | 428 if (classSet == null) { |
416 return const <ClassElement>[]; | 429 return const <ClassElement>[]; |
417 } else { | 430 } else { |
418 return classSet.subtypesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 431 return classSet.subtypesByMask(ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
419 strict: true); | 432 strict: true); |
420 } | 433 } |
421 } | 434 } |
422 | 435 |
423 /// Returns the number of live classes that implement [cls] _not_ | 436 /// Returns the number of live classes that implement [cls] _not_ |
424 /// including [cls] itself. | 437 /// including [cls] itself. |
425 int strictSubtypeCount(ClassElement cls) { | 438 int strictSubtypeCount(ClassElement cls) { |
439 assert(isClosed); | |
426 ClassSet classSet = _classSets[cls.declaration]; | 440 ClassSet classSet = _classSets[cls.declaration]; |
427 if (classSet == null) return 0; | 441 if (classSet == null) return 0; |
428 return classSet.instantiatedSubtypeCount; | 442 return classSet.instantiatedSubtypeCount; |
429 } | 443 } |
430 | 444 |
431 /// Applies [f] to each live class that implements [cls] _not_ including [cls] | 445 /// Applies [f] to each live class that implements [cls] _not_ including [cls] |
432 /// itself. | 446 /// itself. |
433 void forEachStrictSubtypeOf( | 447 void forEachStrictSubtypeOf( |
434 ClassElement cls, IterationStep f(ClassElement cls)) { | 448 ClassElement cls, IterationStep f(ClassElement cls)) { |
449 assert(isClosed); | |
435 ClassSet classSet = _classSets[cls.declaration]; | 450 ClassSet classSet = _classSets[cls.declaration]; |
436 if (classSet == null) return; | 451 if (classSet == null) return; |
437 classSet.forEachSubtype(f, ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 452 classSet.forEachSubtype(f, ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
438 strict: true); | 453 strict: true); |
439 } | 454 } |
440 | 455 |
441 /// Returns `true` if [predicate] applies to any live class that extend [cls] | 456 /// Returns `true` if [predicate] applies to any live class that extend [cls] |
442 /// _not_ including [cls] itself. | 457 /// _not_ including [cls] itself. |
443 bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls)) { | 458 bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls)) { |
459 assert(isClosed); | |
444 ClassSet classSet = _classSets[cls.declaration]; | 460 ClassSet classSet = _classSets[cls.declaration]; |
445 if (classSet == null) return false; | 461 if (classSet == null) return false; |
446 return classSet.anySubtype( | 462 return classSet.anySubtype( |
447 predicate, ClassHierarchyNode.DIRECTLY_INSTANTIATED, | 463 predicate, ClassHierarchyNode.DIRECTLY_INSTANTIATED, |
448 strict: true); | 464 strict: true); |
449 } | 465 } |
450 | 466 |
451 /// Returns `true` if [a] and [b] have any known common subtypes. | 467 /// Returns `true` if [a] and [b] have any known common subtypes. |
452 bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) { | 468 bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) { |
469 assert(isClosed); | |
453 ClassSet classSetA = _classSets[a.declaration]; | 470 ClassSet classSetA = _classSets[a.declaration]; |
454 ClassSet classSetB = _classSets[b.declaration]; | 471 ClassSet classSetB = _classSets[b.declaration]; |
455 if (classSetA == null || classSetB == null) return false; | 472 if (classSetA == null || classSetB == null) return false; |
456 // TODO(johnniwinther): Implement an optimized query on [ClassSet]. | 473 // TODO(johnniwinther): Implement an optimized query on [ClassSet]. |
457 Set<ClassElement> subtypesOfB = classSetB.subtypes().toSet(); | 474 Set<ClassElement> subtypesOfB = classSetB.subtypes().toSet(); |
458 for (ClassElement subtypeOfA in classSetA.subtypes()) { | 475 for (ClassElement subtypeOfA in classSetA.subtypes()) { |
459 if (subtypesOfB.contains(subtypeOfA)) { | 476 if (subtypesOfB.contains(subtypeOfA)) { |
460 return true; | 477 return true; |
461 } | 478 } |
462 } | 479 } |
463 return false; | 480 return false; |
464 } | 481 } |
465 | 482 |
466 /// Returns `true` if any directly instantiated class other than [cls] extends | 483 /// Returns `true` if any directly instantiated class other than [cls] extends |
467 /// [cls]. | 484 /// [cls]. |
468 bool hasAnyStrictSubclass(ClassElement cls) { | 485 bool hasAnyStrictSubclass(ClassElement cls) { |
486 assert(isClosed); | |
469 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 487 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
470 if (subclasses == null) return false; | 488 if (subclasses == null) return false; |
471 return subclasses.isIndirectlyInstantiated; | 489 return subclasses.isIndirectlyInstantiated; |
472 } | 490 } |
473 | 491 |
474 /// Returns `true` if any directly instantiated class other than [cls] | 492 /// Returns `true` if any directly instantiated class other than [cls] |
475 /// implements [cls]. | 493 /// implements [cls]. |
476 bool hasAnyStrictSubtype(ClassElement cls) { | 494 bool hasAnyStrictSubtype(ClassElement cls) { |
477 return strictSubtypeCount(cls) > 0; | 495 return strictSubtypeCount(cls) > 0; |
478 } | 496 } |
479 | 497 |
480 /// Returns `true` if all directly instantiated classes that implement [cls] | 498 /// Returns `true` if all directly instantiated classes that implement [cls] |
481 /// extend it. | 499 /// extend it. |
482 bool hasOnlySubclasses(ClassElement cls) { | 500 bool hasOnlySubclasses(ClassElement cls) { |
501 assert(isClosed); | |
483 // TODO(johnniwinther): move this to ClassSet? | 502 // TODO(johnniwinther): move this to ClassSet? |
484 if (cls == coreClasses.objectClass) return true; | 503 if (cls == coreClasses.objectClass) return true; |
485 ClassSet classSet = _classSets[cls.declaration]; | 504 ClassSet classSet = _classSets[cls.declaration]; |
486 if (classSet == null) { | 505 if (classSet == null) { |
487 // Vacuously true. | 506 // Vacuously true. |
488 return true; | 507 return true; |
489 } | 508 } |
490 return classSet.hasOnlyInstantiatedSubclasses; | 509 return classSet.hasOnlyInstantiatedSubclasses; |
491 } | 510 } |
492 | 511 |
493 @override | 512 @override |
494 ClassElement getLubOfInstantiatedSubclasses(ClassElement cls) { | 513 ClassElement getLubOfInstantiatedSubclasses(ClassElement cls) { |
514 assert(isClosed); | |
495 if (backend.isJsInterop(cls)) { | 515 if (backend.isJsInterop(cls)) { |
496 return backend.helpers.jsJavaScriptObjectClass; | 516 return backend.helpers.jsJavaScriptObjectClass; |
497 } | 517 } |
498 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 518 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; |
499 return hierarchy != null | 519 return hierarchy != null |
500 ? hierarchy.getLubOfInstantiatedSubclasses() | 520 ? hierarchy.getLubOfInstantiatedSubclasses() |
501 : null; | 521 : null; |
502 } | 522 } |
503 | 523 |
504 @override | 524 @override |
505 ClassElement getLubOfInstantiatedSubtypes(ClassElement cls) { | 525 ClassElement getLubOfInstantiatedSubtypes(ClassElement cls) { |
526 assert(isClosed); | |
506 if (backend.isJsInterop(cls)) { | 527 if (backend.isJsInterop(cls)) { |
507 return backend.helpers.jsJavaScriptObjectClass; | 528 return backend.helpers.jsJavaScriptObjectClass; |
508 } | 529 } |
509 ClassSet classSet = _classSets[cls.declaration]; | 530 ClassSet classSet = _classSets[cls.declaration]; |
510 return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null; | 531 return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null; |
511 } | 532 } |
512 | 533 |
513 /// Returns an iterable over the common supertypes of the [classes]. | 534 /// Returns an iterable over the common supertypes of the [classes]. |
514 Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) { | 535 Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) { |
536 assert(isClosed); | |
515 Iterator<ClassElement> iterator = classes.iterator; | 537 Iterator<ClassElement> iterator = classes.iterator; |
516 if (!iterator.moveNext()) return const <ClassElement>[]; | 538 if (!iterator.moveNext()) return const <ClassElement>[]; |
517 | 539 |
518 ClassElement cls = iterator.current; | 540 ClassElement cls = iterator.current; |
519 assert(checkInvariants(cls)); | 541 assert(checkInvariants(cls)); |
520 OrderedTypeSet typeSet = cls.allSupertypesAndSelf; | 542 OrderedTypeSet typeSet = cls.allSupertypesAndSelf; |
521 if (!iterator.moveNext()) return typeSet.types.map((type) => type.element); | 543 if (!iterator.moveNext()) return typeSet.types.map((type) => type.element); |
522 | 544 |
523 int depth = typeSet.maxDepth; | 545 int depth = typeSet.maxDepth; |
524 Link<OrderedTypeSet> otherTypeSets = const Link<OrderedTypeSet>(); | 546 Link<OrderedTypeSet> otherTypeSets = const Link<OrderedTypeSet>(); |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
581 _liveMixinUses[mixin] = uses; | 603 _liveMixinUses[mixin] = uses; |
582 } | 604 } |
583 } | 605 } |
584 } | 606 } |
585 Iterable<MixinApplicationElement> uses = _liveMixinUses[cls]; | 607 Iterable<MixinApplicationElement> uses = _liveMixinUses[cls]; |
586 return uses != null ? uses : const <MixinApplicationElement>[]; | 608 return uses != null ? uses : const <MixinApplicationElement>[]; |
587 } | 609 } |
588 | 610 |
589 /// Returns `true` if [cls] is mixed into a live class. | 611 /// Returns `true` if [cls] is mixed into a live class. |
590 bool isUsedAsMixin(ClassElement cls) { | 612 bool isUsedAsMixin(ClassElement cls) { |
613 assert(isClosed); | |
591 return !mixinUsesOf(cls).isEmpty; | 614 return !mixinUsesOf(cls).isEmpty; |
592 } | 615 } |
593 | 616 |
594 /// Returns `true` if any live class that mixes in [cls] implements [type]. | 617 /// Returns `true` if any live class that mixes in [cls] implements [type]. |
595 bool hasAnySubclassOfMixinUseThatImplements( | 618 bool hasAnySubclassOfMixinUseThatImplements( |
596 ClassElement cls, ClassElement type) { | 619 ClassElement cls, ClassElement type) { |
620 assert(isClosed); | |
597 return mixinUsesOf(cls) | 621 return mixinUsesOf(cls) |
598 .any((use) => hasAnySubclassThatImplements(use, type)); | 622 .any((use) => hasAnySubclassThatImplements(use, type)); |
599 } | 623 } |
600 | 624 |
601 /// Returns `true` if any live class that mixes in [mixin] is also a subclass | 625 /// Returns `true` if any live class that mixes in [mixin] is also a subclass |
602 /// of [superclass]. | 626 /// of [superclass]. |
603 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin) { | 627 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin) { |
628 assert(isClosed); | |
604 return mixinUsesOf(mixin).any((each) => each.isSubclassOf(superclass)); | 629 return mixinUsesOf(mixin).any((each) => each.isSubclassOf(superclass)); |
605 } | 630 } |
606 | 631 |
607 /// Returns `true` if [cls] or any superclass mixes in [mixin]. | 632 /// Returns `true` if [cls] or any superclass mixes in [mixin]. |
608 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin) { | 633 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin) { |
634 assert(isClosed); | |
609 if (isUsedAsMixin(mixin)) { | 635 if (isUsedAsMixin(mixin)) { |
610 ClassElement current = cls.declaration; | 636 ClassElement current = cls.declaration; |
611 mixin = mixin.declaration; | 637 mixin = mixin.declaration; |
612 while (current != null) { | 638 while (current != null) { |
613 current = current.declaration; | 639 current = current.declaration; |
614 if (current.isMixinApplication) { | 640 if (current.isMixinApplication) { |
615 MixinApplicationElement application = current; | 641 MixinApplicationElement application = current; |
616 if (application.mixin.declaration == mixin) return true; | 642 if (application.mixin.declaration == mixin) return true; |
617 } | 643 } |
618 current = current.superclass; | 644 current = current.superclass; |
619 } | 645 } |
620 } | 646 } |
621 return false; | 647 return false; |
622 } | 648 } |
623 | 649 |
624 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass | 650 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass |
625 /// of a mixin application of [y]. | 651 /// of a mixin application of [y]. |
626 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y) { | 652 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y) { |
653 assert(isClosed); | |
627 x = x.declaration; | 654 x = x.declaration; |
628 y = y.declaration; | 655 y = y.declaration; |
629 Map<ClassElement, bool> secondMap = | 656 Map<ClassElement, bool> secondMap = |
630 _subtypeCoveredByCache[x] ??= <ClassElement, bool>{}; | 657 _subtypeCoveredByCache[x] ??= <ClassElement, bool>{}; |
631 return secondMap[y] ??= subtypesOf(x).every((ClassElement cls) => | 658 return secondMap[y] ??= subtypesOf(x).every((ClassElement cls) => |
632 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y)); | 659 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y)); |
633 } | 660 } |
634 | 661 |
635 /// Returns `true` if any subclass of [superclass] implements [type]. | 662 /// Returns `true` if any subclass of [superclass] implements [type]. |
636 bool hasAnySubclassThatImplements( | 663 bool hasAnySubclassThatImplements( |
637 ClassElement superclass, ClassElement type) { | 664 ClassElement superclass, ClassElement type) { |
665 assert(isClosed); | |
638 Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass); | 666 Set<ClassElement> subclasses = typesImplementedBySubclassesOf(superclass); |
639 if (subclasses == null) return false; | 667 if (subclasses == null) return false; |
640 return subclasses.contains(type); | 668 return subclasses.contains(type); |
641 } | 669 } |
642 | 670 |
643 final Compiler _compiler; | 671 final Compiler _compiler; |
644 JavaScriptBackend get backend => _compiler.backend; | 672 JavaScriptBackend get backend => _compiler.backend; |
645 CommonMasks get commonMasks => _compiler.commonMasks; | 673 CommonMasks get commonMasks => _compiler.commonMasks; |
646 final FunctionSet allFunctions; | 674 final FunctionSet allFunctions; |
647 final Set<Element> functionsCalledInLoop = new Set<Element>(); | 675 final Set<Element> functionsCalledInLoop = new Set<Element>(); |
(...skipping 344 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
992 return functionsThatMightBePassedToApply.contains(element); | 1020 return functionsThatMightBePassedToApply.contains(element); |
993 } | 1021 } |
994 | 1022 |
995 @override | 1023 @override |
996 bool getCurrentlyKnownMightBePassedToApply(Element element) { | 1024 bool getCurrentlyKnownMightBePassedToApply(Element element) { |
997 return getMightBePassedToApply(element); | 1025 return getMightBePassedToApply(element); |
998 } | 1026 } |
999 | 1027 |
1000 bool get hasClosedWorldAssumption => !_compiler.options.hasIncrementalSupport; | 1028 bool get hasClosedWorldAssumption => !_compiler.options.hasIncrementalSupport; |
1001 } | 1029 } |
OLD | NEW |