Chromium Code Reviews| 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 |