| 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 ClosureClassElement, SynthesizedCallMethodElementX; | 7 import 'closure.dart' show ClosureClassElement, SynthesizedCallMethodElementX; |
| 8 import 'common/backend_api.dart' show BackendClasses; | 8 import 'common/backend_api.dart' show BackendClasses; |
| 9 import 'common.dart'; | 9 import 'common.dart'; |
| 10 import 'constants/constant_system.dart'; | 10 import 'constants/constant_system.dart'; |
| (...skipping 379 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 390 | 390 |
| 391 class ClosedWorldImpl implements ClosedWorld, ClosedWorldRefiner { | 391 class ClosedWorldImpl implements ClosedWorld, ClosedWorldRefiner { |
| 392 final JavaScriptBackend _backend; | 392 final JavaScriptBackend _backend; |
| 393 BackendClasses get backendClasses => _backend.backendClasses; | 393 BackendClasses get backendClasses => _backend.backendClasses; |
| 394 InterceptorData get interceptorData => _backend.interceptorData; | 394 InterceptorData get interceptorData => _backend.interceptorData; |
| 395 FunctionSet _allFunctions; | 395 FunctionSet _allFunctions; |
| 396 | 396 |
| 397 final Iterable<TypedefElement> _allTypedefs; | 397 final Iterable<TypedefElement> _allTypedefs; |
| 398 | 398 |
| 399 final Map<ClassEntity, Set<ClassEntity>> _mixinUses; | 399 final Map<ClassEntity, Set<ClassEntity>> _mixinUses; |
| 400 Map<ClassElement, List<MixinApplicationElement>> _liveMixinUses; | 400 Map<ClassEntity, List<ClassEntity>> _liveMixinUses; |
| 401 | 401 |
| 402 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; | 402 final Map<ClassEntity, Set<ClassEntity>> _typesImplementedBySubclasses; |
| 403 | 403 |
| 404 // We keep track of subtype and subclass relationships in four | 404 // We keep track of subtype and subclass relationships in four |
| 405 // distinct sets to make class hierarchy analysis faster. | 405 // distinct sets to make class hierarchy analysis faster. |
| 406 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; | 406 final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes; |
| 407 final Map<ClassEntity, ClassSet> _classSets; | 407 final Map<ClassEntity, ClassSet> _classSets; |
| 408 | 408 |
| 409 final Map<ClassElement, Map<ClassElement, bool>> _subtypeCoveredByCache = | 409 final Map<ClassEntity, Map<ClassEntity, bool>> _subtypeCoveredByCache = |
| 410 <ClassElement, Map<ClassElement, bool>>{}; | 410 <ClassEntity, Map<ClassEntity, bool>>{}; |
| 411 | 411 |
| 412 final Set<Element> functionsCalledInLoop = new Set<Element>(); | 412 final Set<Element> functionsCalledInLoop = new Set<Element>(); |
| 413 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); | 413 final Map<Element, SideEffects> sideEffects = new Map<Element, SideEffects>(); |
| 414 | 414 |
| 415 final Set<Element> sideEffectsFreeElements = new Set<Element>(); | 415 final Set<Element> sideEffectsFreeElements = new Set<Element>(); |
| 416 | 416 |
| 417 final Set<Element> elementsThatCannotThrow = new Set<Element>(); | 417 final Set<Element> elementsThatCannotThrow = new Set<Element>(); |
| 418 | 418 |
| 419 final Set<Element> functionsThatMightBePassedToApply = | 419 final Set<Element> functionsThatMightBePassedToApply = |
| 420 new Set<FunctionElement>(); | 420 new Set<FunctionElement>(); |
| 421 | 421 |
| 422 CommonMasks _commonMasks; | 422 CommonMasks _commonMasks; |
| 423 | 423 |
| 424 final CommonElements commonElements; | 424 final CommonElements commonElements; |
| 425 | 425 |
| 426 final ResolutionWorldBuilder _resolverWorld; | 426 final ResolutionWorldBuilder _resolverWorld; |
| 427 | 427 |
| 428 bool get isClosed => true; | |
| 429 | |
| 430 ClosedWorldImpl( | 428 ClosedWorldImpl( |
| 431 {JavaScriptBackend backend, | 429 {JavaScriptBackend backend, |
| 432 this.commonElements, | 430 this.commonElements, |
| 433 ResolutionWorldBuilder resolutionWorldBuilder, | 431 ResolutionWorldBuilder resolutionWorldBuilder, |
| 434 FunctionSetBuilder functionSetBuilder, | 432 FunctionSetBuilder functionSetBuilder, |
| 435 Iterable<TypedefElement> allTypedefs, | 433 Iterable<TypedefElement> allTypedefs, |
| 436 Map<ClassEntity, Set<ClassEntity>> mixinUses, | 434 Map<ClassEntity, Set<ClassEntity>> mixinUses, |
| 437 Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses, | 435 Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses, |
| 438 Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes, | 436 Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes, |
| 439 Map<ClassEntity, ClassSet> classSets}) | 437 Map<ClassEntity, ClassSet> classSets}) |
| 440 : this._backend = backend, | 438 : this._backend = backend, |
| 441 this._resolverWorld = resolutionWorldBuilder, | 439 this._resolverWorld = resolutionWorldBuilder, |
| 442 this._allTypedefs = allTypedefs, | 440 this._allTypedefs = allTypedefs, |
| 443 this._mixinUses = mixinUses, | 441 this._mixinUses = mixinUses, |
| 444 this._typesImplementedBySubclasses = typesImplementedBySubclasses, | 442 this._typesImplementedBySubclasses = typesImplementedBySubclasses, |
| 445 this._classHierarchyNodes = classHierarchyNodes, | 443 this._classHierarchyNodes = classHierarchyNodes, |
| 446 this._classSets = classSets { | 444 this._classSets = classSets { |
| 447 _commonMasks = new CommonMasks(this); | 445 _commonMasks = new CommonMasks(this); |
| 448 _allFunctions = functionSetBuilder.close(this); | 446 _allFunctions = functionSetBuilder.close(this); |
| 449 } | 447 } |
| 450 | 448 |
| 451 NativeData get nativeData => _backend.nativeData; | 449 NativeData get nativeData => _backend.nativeData; |
| 452 | 450 |
| 453 @override | 451 @override |
| 454 ClosedWorld get closedWorld => this; | 452 ClosedWorld get closedWorld => this; |
| 455 | 453 |
| 456 /// Cache of [FlatTypeMask]s grouped by the 8 possible values of the | 454 /// Cache of [FlatTypeMask]s grouped by the 8 possible values of the |
| 457 /// `FlatTypeMask.flags` property. | 455 /// `FlatTypeMask.flags` property. |
| 458 final List<Map<ClassElement, TypeMask>> _canonicalizedTypeMasks = | 456 final List<Map<ClassEntity, TypeMask>> _canonicalizedTypeMasks = |
| 459 new List<Map<ClassElement, TypeMask>>.filled(8, null); | 457 new List<Map<ClassEntity, TypeMask>>.filled(8, null); |
| 460 | 458 |
| 461 FunctionSet get allFunctions => _allFunctions; | 459 FunctionSet get allFunctions => _allFunctions; |
| 462 | 460 |
| 463 CommonMasks get commonMasks { | 461 CommonMasks get commonMasks { |
| 464 assert(isClosed); | |
| 465 return _commonMasks; | 462 return _commonMasks; |
| 466 } | 463 } |
| 467 | 464 |
| 468 ConstantSystem get constantSystem => _backend.constantSystem; | 465 ConstantSystem get constantSystem => _backend.constantSystem; |
| 469 | 466 |
| 470 TypeMask getCachedMask(ClassElement base, int flags, TypeMask createMask()) { | 467 TypeMask getCachedMask(ClassEntity base, int flags, TypeMask createMask()) { |
| 471 Map<ClassElement, TypeMask> cachedMasks = | 468 Map<ClassEntity, TypeMask> cachedMasks = |
| 472 _canonicalizedTypeMasks[flags] ??= <ClassElement, TypeMask>{}; | 469 _canonicalizedTypeMasks[flags] ??= <ClassEntity, TypeMask>{}; |
| 473 return cachedMasks.putIfAbsent(base, createMask); | 470 return cachedMasks.putIfAbsent(base, createMask); |
| 474 } | 471 } |
| 475 | 472 |
| 473 bool _checkClass(ClassElement cls) => cls.isDeclaration; |
| 474 |
| 476 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { | 475 bool checkInvariants(ClassElement cls, {bool mustBeInstantiated: true}) { |
| 477 return invariant(cls, cls.isDeclaration, | 476 return invariant(cls, cls.isDeclaration, |
| 478 message: '$cls must be the declaration.') && | 477 message: '$cls must be the declaration.') && |
| 479 invariant(cls, cls.isResolved, | 478 invariant(cls, cls.isResolved, |
| 480 message: | 479 message: |
| 481 '$cls must be resolved.') /* && | 480 '$cls must be resolved.') /* && |
| 482 // TODO(johnniwinther): Reinsert this or similar invariant. | 481 // TODO(johnniwinther): Reinsert this or similar invariant. |
| 483 (!mustBeInstantiated || | 482 (!mustBeInstantiated || |
| 484 invariant(cls, isInstantiated(cls), | 483 invariant(cls, isInstantiated(cls), |
| 485 message: '$cls is not instantiated.'))*/ | 484 message: '$cls is not instantiated.'))*/ |
| 486 ; | 485 ; |
| 487 } | 486 } |
| 488 | 487 |
| 489 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an | 488 /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an |
| 490 /// instance of [y]. | 489 /// instance of [y]. |
| 491 bool isSubtypeOf(ClassElement x, ClassElement y) { | 490 bool isSubtypeOf(ClassElement x, ClassElement y) { |
| 492 assert(isClosed); | |
| 493 assert(checkInvariants(x)); | 491 assert(checkInvariants(x)); |
| 494 assert(checkInvariants(y, mustBeInstantiated: false)); | 492 assert(checkInvariants(y, mustBeInstantiated: false)); |
| 495 | 493 |
| 496 if (y == commonElements.objectClass) return true; | 494 if (y == commonElements.objectClass) return true; |
| 497 if (x == commonElements.objectClass) return false; | 495 if (x == commonElements.objectClass) return false; |
| 498 if (x.asInstanceOf(y) != null) return true; | 496 if (x.asInstanceOf(y) != null) return true; |
| 499 if (y != commonElements.functionClass) return false; | 497 if (y != commonElements.functionClass) return false; |
| 500 return x.callType != null; | 498 return x.callType != null; |
| 501 } | 499 } |
| 502 | 500 |
| 503 /// Return `true` if [x] is a (non-strict) subclass of [y]. | 501 /// Return `true` if [x] is a (non-strict) subclass of [y]. |
| 504 bool isSubclassOf(ClassElement x, ClassElement y) { | 502 bool isSubclassOf(ClassElement x, ClassElement y) { |
| 505 assert(isClosed); | |
| 506 assert(checkInvariants(x)); | 503 assert(checkInvariants(x)); |
| 507 assert(checkInvariants(y)); | 504 assert(checkInvariants(y)); |
| 508 | 505 |
| 509 if (y == commonElements.objectClass) return true; | 506 if (y == commonElements.objectClass) return true; |
| 510 if (x == commonElements.objectClass) return false; | 507 if (x == commonElements.objectClass) return false; |
| 511 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { | 508 while (x != null && x.hierarchyDepth >= y.hierarchyDepth) { |
| 512 if (x == y) return true; | 509 if (x == y) return true; |
| 513 x = x.superclass; | 510 x = x.superclass; |
| 514 } | 511 } |
| 515 return false; | 512 return false; |
| 516 } | 513 } |
| 517 | 514 |
| 518 @override | 515 @override |
| 519 bool isInstantiated(ClassElement cls) { | 516 bool isInstantiated(ClassEntity cls) { |
| 520 assert(isClosed); | 517 assert(_checkClass(cls)); |
| 521 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 518 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
| 522 return node != null && node.isInstantiated; | 519 return node != null && node.isInstantiated; |
| 523 } | 520 } |
| 524 | 521 |
| 525 @override | 522 @override |
| 526 bool isDirectlyInstantiated(ClassElement cls) { | 523 bool isDirectlyInstantiated(ClassEntity cls) { |
| 527 assert(isClosed); | 524 assert(_checkClass(cls)); |
| 528 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 525 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
| 529 return node != null && node.isDirectlyInstantiated; | 526 return node != null && node.isDirectlyInstantiated; |
| 530 } | 527 } |
| 531 | 528 |
| 532 @override | 529 @override |
| 533 bool isAbstractlyInstantiated(ClassElement cls) { | 530 bool isAbstractlyInstantiated(ClassEntity cls) { |
| 534 assert(isClosed); | 531 assert(_checkClass(cls)); |
| 535 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 532 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
| 536 return node != null && node.isAbstractlyInstantiated; | 533 return node != null && node.isAbstractlyInstantiated; |
| 537 } | 534 } |
| 538 | 535 |
| 539 @override | 536 @override |
| 540 bool isExplicitlyInstantiated(ClassElement cls) { | 537 bool isExplicitlyInstantiated(ClassEntity cls) { |
| 541 assert(isClosed); | 538 assert(_checkClass(cls)); |
| 542 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 539 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
| 543 return node != null && node.isExplicitlyInstantiated; | 540 return node != null && node.isExplicitlyInstantiated; |
| 544 } | 541 } |
| 545 | 542 |
| 546 @override | 543 @override |
| 547 bool isIndirectlyInstantiated(ClassElement cls) { | 544 bool isIndirectlyInstantiated(ClassEntity cls) { |
| 548 assert(isClosed); | 545 assert(_checkClass(cls)); |
| 549 ClassHierarchyNode node = _classHierarchyNodes[cls.declaration]; | 546 ClassHierarchyNode node = _classHierarchyNodes[cls]; |
| 550 return node != null && node.isIndirectlyInstantiated; | 547 return node != null && node.isIndirectlyInstantiated; |
| 551 } | 548 } |
| 552 | 549 |
| 553 @override | 550 @override |
| 554 bool isAbstract(ClassElement cls) => cls.isAbstract; | 551 bool isAbstract(ClassEntity cls) => cls.isAbstract; |
| 555 | 552 |
| 556 /// Returns `true` if [cls] is implemented by an instantiated class. | 553 /// Returns `true` if [cls] is implemented by an instantiated class. |
| 557 bool isImplemented(ClassElement cls) { | 554 bool isImplemented(ClassEntity cls) { |
| 558 assert(isClosed); | |
| 559 return _resolverWorld.isImplemented(cls); | 555 return _resolverWorld.isImplemented(cls); |
| 560 } | 556 } |
| 561 | 557 |
| 562 /// Returns an iterable over the directly instantiated classes that extend | 558 /// Returns an iterable over the directly instantiated classes that extend |
| 563 /// [cls] possibly including [cls] itself, if it is live. | 559 /// [cls] possibly including [cls] itself, if it is live. |
| 564 Iterable<ClassElement> subclassesOf(ClassElement cls) { | 560 Iterable<ClassEntity> subclassesOf(ClassEntity cls) { |
| 565 assert(isClosed); | 561 assert(_checkClass(cls)); |
| 566 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 562 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls]; |
| 567 if (hierarchy == null) return const <ClassElement>[]; | 563 if (hierarchy == null) return const <ClassEntity>[]; |
| 568 return hierarchy | 564 return hierarchy |
| 569 .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED); | 565 .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED); |
| 570 } | 566 } |
| 571 | 567 |
| 572 /// Returns an iterable over the directly instantiated classes that extend | 568 /// Returns an iterable over the directly instantiated classes that extend |
| 573 /// [cls] _not_ including [cls] itself. | 569 /// [cls] _not_ including [cls] itself. |
| 574 Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { | 570 Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) { |
| 575 assert(isClosed); | 571 assert(_checkClass(cls)); |
| 576 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 572 ClassHierarchyNode subclasses = _classHierarchyNodes[cls]; |
| 577 if (subclasses == null) return const <ClassElement>[]; | 573 if (subclasses == null) return const <ClassEntity>[]; |
| 578 return subclasses.subclassesByMask( | 574 return subclasses.subclassesByMask( |
| 579 ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 575 ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 580 strict: true); | 576 strict: true); |
| 581 } | 577 } |
| 582 | 578 |
| 583 /// Returns the number of live classes that extend [cls] _not_ | 579 /// Returns the number of live classes that extend [cls] _not_ |
| 584 /// including [cls] itself. | 580 /// including [cls] itself. |
| 585 int strictSubclassCount(ClassElement cls) { | 581 int strictSubclassCount(ClassEntity cls) { |
| 586 assert(isClosed); | 582 assert(_checkClass(cls)); |
| 587 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 583 ClassHierarchyNode subclasses = _classHierarchyNodes[cls]; |
| 588 if (subclasses == null) return 0; | 584 if (subclasses == null) return 0; |
| 589 return subclasses.instantiatedSubclassCount; | 585 return subclasses.instantiatedSubclassCount; |
| 590 } | 586 } |
| 591 | 587 |
| 592 /// Applies [f] to each live class that extend [cls] _not_ including [cls] | 588 /// Applies [f] to each live class that extend [cls] _not_ including [cls] |
| 593 /// itself. | 589 /// itself. |
| 594 void forEachStrictSubclassOf( | 590 void forEachStrictSubclassOf( |
| 595 ClassElement cls, IterationStep f(ClassElement cls)) { | 591 ClassEntity cls, IterationStep f(ClassEntity cls)) { |
| 596 assert(isClosed); | 592 assert(_checkClass(cls)); |
| 597 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 593 ClassHierarchyNode subclasses = _classHierarchyNodes[cls]; |
| 598 if (subclasses == null) return; | 594 if (subclasses == null) return; |
| 599 subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 595 subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 600 strict: true); | 596 strict: true); |
| 601 } | 597 } |
| 602 | 598 |
| 603 /// Returns `true` if [predicate] applies to any live class that extend [cls] | 599 /// Returns `true` if [predicate] applies to any live class that extend [cls] |
| 604 /// _not_ including [cls] itself. | 600 /// _not_ including [cls] itself. |
| 605 bool anyStrictSubclassOf(ClassElement cls, bool predicate(ClassElement cls)) { | 601 bool anyStrictSubclassOf(ClassEntity cls, bool predicate(ClassEntity cls)) { |
| 606 assert(isClosed); | 602 assert(_checkClass(cls)); |
| 607 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 603 ClassHierarchyNode subclasses = _classHierarchyNodes[cls]; |
| 608 if (subclasses == null) return false; | 604 if (subclasses == null) return false; |
| 609 return subclasses.anySubclass( | 605 return subclasses.anySubclass( |
| 610 predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 606 predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 611 strict: true); | 607 strict: true); |
| 612 } | 608 } |
| 613 | 609 |
| 614 /// Returns an iterable over the directly instantiated that implement [cls] | 610 /// Returns an iterable over the directly instantiated that implement [cls] |
| 615 /// possibly including [cls] itself, if it is live. | 611 /// possibly including [cls] itself, if it is live. |
| 616 Iterable<ClassElement> subtypesOf(ClassElement cls) { | 612 Iterable<ClassEntity> subtypesOf(ClassEntity cls) { |
| 617 assert(isClosed); | 613 assert(_checkClass(cls)); |
| 618 ClassSet classSet = _classSets[cls.declaration]; | 614 ClassSet classSet = _classSets[cls]; |
| 619 if (classSet == null) { | 615 if (classSet == null) { |
| 620 return const <ClassElement>[]; | 616 return const <ClassEntity>[]; |
| 621 } else { | 617 } else { |
| 622 return classSet | 618 return classSet |
| 623 .subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED); | 619 .subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED); |
| 624 } | 620 } |
| 625 } | 621 } |
| 626 | 622 |
| 627 /// Returns an iterable over the directly instantiated that implement [cls] | 623 /// Returns an iterable over the directly instantiated that implement [cls] |
| 628 /// _not_ including [cls]. | 624 /// _not_ including [cls]. |
| 629 Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { | 625 Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls) { |
| 630 assert(isClosed); | 626 assert(_checkClass(cls)); |
| 631 ClassSet classSet = _classSets[cls.declaration]; | 627 ClassSet classSet = _classSets[cls]; |
| 632 if (classSet == null) { | 628 if (classSet == null) { |
| 633 return const <ClassElement>[]; | 629 return const <ClassEntity>[]; |
| 634 } else { | 630 } else { |
| 635 return classSet.subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 631 return classSet.subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 636 strict: true); | 632 strict: true); |
| 637 } | 633 } |
| 638 } | 634 } |
| 639 | 635 |
| 640 /// Returns the number of live classes that implement [cls] _not_ | 636 /// Returns the number of live classes that implement [cls] _not_ |
| 641 /// including [cls] itself. | 637 /// including [cls] itself. |
| 642 int strictSubtypeCount(ClassElement cls) { | 638 int strictSubtypeCount(ClassEntity cls) { |
| 643 assert(isClosed); | 639 assert(_checkClass(cls)); |
| 644 ClassSet classSet = _classSets[cls.declaration]; | 640 ClassSet classSet = _classSets[cls]; |
| 645 if (classSet == null) return 0; | 641 if (classSet == null) return 0; |
| 646 return classSet.instantiatedSubtypeCount; | 642 return classSet.instantiatedSubtypeCount; |
| 647 } | 643 } |
| 648 | 644 |
| 649 /// Applies [f] to each live class that implements [cls] _not_ including [cls] | 645 /// Applies [f] to each live class that implements [cls] _not_ including [cls] |
| 650 /// itself. | 646 /// itself. |
| 651 void forEachStrictSubtypeOf( | 647 void forEachStrictSubtypeOf( |
| 652 ClassElement cls, IterationStep f(ClassElement cls)) { | 648 ClassEntity cls, IterationStep f(ClassEntity cls)) { |
| 653 assert(isClosed); | 649 assert(_checkClass(cls)); |
| 654 ClassSet classSet = _classSets[cls.declaration]; | 650 ClassSet classSet = _classSets[cls]; |
| 655 if (classSet == null) return; | 651 if (classSet == null) return; |
| 656 classSet.forEachSubtype(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 652 classSet.forEachSubtype(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 657 strict: true); | 653 strict: true); |
| 658 } | 654 } |
| 659 | 655 |
| 660 /// Returns `true` if [predicate] applies to any live class that extend [cls] | 656 /// Returns `true` if [predicate] applies to any live class that extend [cls] |
| 661 /// _not_ including [cls] itself. | 657 /// _not_ including [cls] itself. |
| 662 bool anyStrictSubtypeOf(ClassElement cls, bool predicate(ClassElement cls)) { | 658 bool anyStrictSubtypeOf(ClassEntity cls, bool predicate(ClassEntity cls)) { |
| 663 assert(isClosed); | 659 assert(_checkClass(cls)); |
| 664 ClassSet classSet = _classSets[cls.declaration]; | 660 ClassSet classSet = _classSets[cls]; |
| 665 if (classSet == null) return false; | 661 if (classSet == null) return false; |
| 666 return classSet.anySubtype( | 662 return classSet.anySubtype( |
| 667 predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, | 663 predicate, ClassHierarchyNode.EXPLICITLY_INSTANTIATED, |
| 668 strict: true); | 664 strict: true); |
| 669 } | 665 } |
| 670 | 666 |
| 671 /// Returns `true` if [a] and [b] have any known common subtypes. | 667 /// Returns `true` if [a] and [b] have any known common subtypes. |
| 672 bool haveAnyCommonSubtypes(ClassElement a, ClassElement b) { | 668 bool haveAnyCommonSubtypes(ClassEntity a, ClassEntity b) { |
| 673 assert(isClosed); | 669 assert(_checkClass(a)); |
| 674 ClassSet classSetA = _classSets[a.declaration]; | 670 assert(_checkClass(b)); |
| 675 ClassSet classSetB = _classSets[b.declaration]; | 671 ClassSet classSetA = _classSets[a]; |
| 672 ClassSet classSetB = _classSets[b]; |
| 676 if (classSetA == null || classSetB == null) return false; | 673 if (classSetA == null || classSetB == null) return false; |
| 677 // TODO(johnniwinther): Implement an optimized query on [ClassSet]. | 674 // TODO(johnniwinther): Implement an optimized query on [ClassSet]. |
| 678 Set<ClassElement> subtypesOfB = classSetB.subtypes().toSet(); | 675 Set<ClassEntity> subtypesOfB = classSetB.subtypes().toSet(); |
| 679 for (ClassElement subtypeOfA in classSetA.subtypes()) { | 676 for (ClassEntity subtypeOfA in classSetA.subtypes()) { |
| 680 if (subtypesOfB.contains(subtypeOfA)) { | 677 if (subtypesOfB.contains(subtypeOfA)) { |
| 681 return true; | 678 return true; |
| 682 } | 679 } |
| 683 } | 680 } |
| 684 return false; | 681 return false; |
| 685 } | 682 } |
| 686 | 683 |
| 687 /// Returns `true` if any directly instantiated class other than [cls] extends | 684 /// Returns `true` if any directly instantiated class other than [cls] extends |
| 688 /// [cls]. | 685 /// [cls]. |
| 689 bool hasAnyStrictSubclass(ClassElement cls) { | 686 bool hasAnyStrictSubclass(ClassEntity cls) { |
| 690 assert(isClosed); | 687 assert(_checkClass(cls)); |
| 691 ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; | 688 ClassHierarchyNode subclasses = _classHierarchyNodes[cls]; |
| 692 if (subclasses == null) return false; | 689 if (subclasses == null) return false; |
| 693 return subclasses.isIndirectlyInstantiated; | 690 return subclasses.isIndirectlyInstantiated; |
| 694 } | 691 } |
| 695 | 692 |
| 696 /// Returns `true` if any directly instantiated class other than [cls] | 693 /// Returns `true` if any directly instantiated class other than [cls] |
| 697 /// implements [cls]. | 694 /// implements [cls]. |
| 698 bool hasAnyStrictSubtype(ClassElement cls) { | 695 bool hasAnyStrictSubtype(ClassEntity cls) { |
| 699 return strictSubtypeCount(cls) > 0; | 696 return strictSubtypeCount(cls) > 0; |
| 700 } | 697 } |
| 701 | 698 |
| 702 /// Returns `true` if all directly instantiated classes that implement [cls] | 699 /// Returns `true` if all directly instantiated classes that implement [cls] |
| 703 /// extend it. | 700 /// extend it. |
| 704 bool hasOnlySubclasses(ClassElement cls) { | 701 bool hasOnlySubclasses(ClassEntity cls) { |
| 705 assert(isClosed); | 702 assert(_checkClass(cls)); |
| 706 // TODO(johnniwinther): move this to ClassSet? | 703 // TODO(johnniwinther): move this to ClassSet? |
| 707 if (cls == commonElements.objectClass) return true; | 704 if (cls == commonElements.objectClass) return true; |
| 708 ClassSet classSet = _classSets[cls.declaration]; | 705 ClassSet classSet = _classSets[cls]; |
| 709 if (classSet == null) { | 706 if (classSet == null) { |
| 710 // Vacuously true. | 707 // Vacuously true. |
| 711 return true; | 708 return true; |
| 712 } | 709 } |
| 713 return classSet.hasOnlyInstantiatedSubclasses; | 710 return classSet.hasOnlyInstantiatedSubclasses; |
| 714 } | 711 } |
| 715 | 712 |
| 716 @override | 713 @override |
| 717 ClassElement getLubOfInstantiatedSubclasses(ClassElement cls) { | 714 ClassEntity getLubOfInstantiatedSubclasses(ClassEntity cls) { |
| 718 assert(isClosed); | 715 assert(_checkClass(cls)); |
| 719 if (nativeData.isJsInteropClass(cls)) { | 716 if (nativeData.isJsInteropClass(cls)) { |
| 720 return _backend.helpers.jsJavaScriptObjectClass; | 717 return _backend.helpers.jsJavaScriptObjectClass; |
| 721 } | 718 } |
| 722 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; | 719 ClassHierarchyNode hierarchy = _classHierarchyNodes[cls]; |
| 723 return hierarchy != null | 720 return hierarchy != null |
| 724 ? hierarchy.getLubOfInstantiatedSubclasses() | 721 ? hierarchy.getLubOfInstantiatedSubclasses() |
| 725 : null; | 722 : null; |
| 726 } | 723 } |
| 727 | 724 |
| 728 @override | 725 @override |
| 729 ClassElement getLubOfInstantiatedSubtypes(ClassElement cls) { | 726 ClassEntity getLubOfInstantiatedSubtypes(ClassEntity cls) { |
| 730 assert(isClosed); | 727 assert(_checkClass(cls)); |
| 731 if (nativeData.isJsInteropClass(cls)) { | 728 if (nativeData.isJsInteropClass(cls)) { |
| 732 return _backend.helpers.jsJavaScriptObjectClass; | 729 return _backend.helpers.jsJavaScriptObjectClass; |
| 733 } | 730 } |
| 734 ClassSet classSet = _classSets[cls.declaration]; | 731 ClassSet classSet = _classSets[cls]; |
| 735 return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null; | 732 return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null; |
| 736 } | 733 } |
| 737 | 734 |
| 738 /// Returns an iterable over the common supertypes of the [classes]. | 735 /// Returns an iterable over the common supertypes of the [classes]. |
| 739 Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) { | 736 Iterable<ClassElement> commonSupertypesOf(Iterable<ClassElement> classes) { |
| 740 assert(isClosed); | |
| 741 Iterator<ClassElement> iterator = classes.iterator; | 737 Iterator<ClassElement> iterator = classes.iterator; |
| 742 if (!iterator.moveNext()) return const <ClassElement>[]; | 738 if (!iterator.moveNext()) return const <ClassElement>[]; |
| 743 | 739 |
| 744 ClassElement cls = iterator.current; | 740 ClassElement cls = iterator.current; |
| 745 assert(checkInvariants(cls)); | 741 assert(checkInvariants(cls)); |
| 746 OrderedTypeSet typeSet = cls.allSupertypesAndSelf; | 742 OrderedTypeSet typeSet = cls.allSupertypesAndSelf; |
| 747 if (!iterator.moveNext()) return typeSet.types.map((type) => type.element); | 743 if (!iterator.moveNext()) return typeSet.types.map((type) => type.element); |
| 748 | 744 |
| 749 int depth = typeSet.maxDepth; | 745 int depth = typeSet.maxDepth; |
| 750 Link<OrderedTypeSet> otherTypeSets = const Link<OrderedTypeSet>(); | 746 Link<OrderedTypeSet> otherTypeSets = const Link<OrderedTypeSet>(); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 770 if (link.head.asInstanceOf(cls) == null) { | 766 if (link.head.asInstanceOf(cls) == null) { |
| 771 continue OUTER; | 767 continue OUTER; |
| 772 } | 768 } |
| 773 } | 769 } |
| 774 commonSupertypes.add(cls); | 770 commonSupertypes.add(cls); |
| 775 } | 771 } |
| 776 commonSupertypes.add(commonElements.objectClass); | 772 commonSupertypes.add(commonElements.objectClass); |
| 777 return commonSupertypes; | 773 return commonSupertypes; |
| 778 } | 774 } |
| 779 | 775 |
| 780 Iterable<ClassElement> commonSubclasses(ClassElement cls1, ClassQuery query1, | 776 Iterable<ClassEntity> commonSubclasses(ClassEntity cls1, ClassQuery query1, |
| 781 ClassElement cls2, ClassQuery query2) { | 777 ClassEntity cls2, ClassQuery query2) { |
| 782 // TODO(johnniwinther): Use [ClassSet] to compute this. | 778 // TODO(johnniwinther): Use [ClassSet] to compute this. |
| 783 // Compute the set of classes that are contained in both class subsets. | 779 // Compute the set of classes that are contained in both class subsets. |
| 784 Set<ClassEntity> common = | 780 Set<ClassEntity> common = |
| 785 _commonContainedClasses(cls1, query1, cls2, query2); | 781 _commonContainedClasses(cls1, query1, cls2, query2); |
| 786 if (common == null || common.isEmpty) return const <ClassElement>[]; | 782 if (common == null || common.isEmpty) return const <ClassEntity>[]; |
| 787 // Narrow down the candidates by only looking at common classes | 783 // Narrow down the candidates by only looking at common classes |
| 788 // that do not have a superclass or supertype that will be a | 784 // that do not have a superclass or supertype that will be a |
| 789 // better candidate. | 785 // better candidate. |
| 790 return common.where((ClassElement each) { | 786 return common.where((ClassElement each) { |
| 791 bool containsSuperclass = common.contains(each.supertype.element); | 787 bool containsSuperclass = common.contains(each.supertype.element); |
| 792 // If the superclass is also a candidate, then we don't want to | 788 // If the superclass is also a candidate, then we don't want to |
| 793 // deal with this class. If we're only looking for a subclass we | 789 // deal with this class. If we're only looking for a subclass we |
| 794 // know we don't have to look at the list of interfaces because | 790 // know we don't have to look at the list of interfaces because |
| 795 // they can never be in the common set. | 791 // they can never be in the common set. |
| 796 if (containsSuperclass || | 792 if (containsSuperclass || |
| 797 query1 == ClassQuery.SUBCLASS || | 793 query1 == ClassQuery.SUBCLASS || |
| 798 query2 == ClassQuery.SUBCLASS) { | 794 query2 == ClassQuery.SUBCLASS) { |
| 799 return !containsSuperclass; | 795 return !containsSuperclass; |
| 800 } | 796 } |
| 801 // Run through the direct supertypes of the class. If the common | 797 // Run through the direct supertypes of the class. If the common |
| 802 // set contains the direct supertype of the class, we ignore the | 798 // set contains the direct supertype of the class, we ignore the |
| 803 // the class because the supertype is a better candidate. | 799 // the class because the supertype is a better candidate. |
| 804 for (Link link = each.interfaces; !link.isEmpty; link = link.tail) { | 800 for (Link link = each.interfaces; !link.isEmpty; link = link.tail) { |
| 805 if (common.contains(link.head.element)) return false; | 801 if (common.contains(link.head.element)) return false; |
| 806 } | 802 } |
| 807 return true; | 803 return true; |
| 808 }); | 804 }); |
| 809 } | 805 } |
| 810 | 806 |
| 811 Set<ClassElement> _commonContainedClasses(ClassElement cls1, | 807 Set<ClassEntity> _commonContainedClasses(ClassEntity cls1, ClassQuery query1, |
| 812 ClassQuery query1, ClassElement cls2, ClassQuery query2) { | 808 ClassEntity cls2, ClassQuery query2) { |
| 813 Iterable<ClassElement> xSubset = _containedSubset(cls1, query1); | 809 Iterable<ClassEntity> xSubset = _containedSubset(cls1, query1); |
| 814 if (xSubset == null) return null; | 810 if (xSubset == null) return null; |
| 815 Iterable<ClassElement> ySubset = _containedSubset(cls2, query2); | 811 Iterable<ClassEntity> ySubset = _containedSubset(cls2, query2); |
| 816 if (ySubset == null) return null; | 812 if (ySubset == null) return null; |
| 817 return xSubset.toSet().intersection(ySubset.toSet()); | 813 return xSubset.toSet().intersection(ySubset.toSet()); |
| 818 } | 814 } |
| 819 | 815 |
| 820 Iterable<ClassElement> _containedSubset(ClassElement cls, ClassQuery query) { | 816 Iterable<ClassEntity> _containedSubset(ClassEntity cls, ClassQuery query) { |
| 821 switch (query) { | 817 switch (query) { |
| 822 case ClassQuery.EXACT: | 818 case ClassQuery.EXACT: |
| 823 return null; | 819 return null; |
| 824 case ClassQuery.SUBCLASS: | 820 case ClassQuery.SUBCLASS: |
| 825 return strictSubclassesOf(cls); | 821 return strictSubclassesOf(cls); |
| 826 case ClassQuery.SUBTYPE: | 822 case ClassQuery.SUBTYPE: |
| 827 return strictSubtypesOf(cls); | 823 return strictSubtypesOf(cls); |
| 828 } | 824 } |
| 829 throw new ArgumentError('Unexpected query: $query.'); | 825 throw new ArgumentError('Unexpected query: $query.'); |
| 830 } | 826 } |
| 831 | 827 |
| 832 /// Returns an iterable over the live mixin applications that mixin [cls]. | 828 /// Returns an iterable over the live mixin applications that mixin [cls]. |
| 833 Iterable<MixinApplicationElement> mixinUsesOf(ClassElement cls) { | 829 Iterable<ClassEntity> mixinUsesOf(ClassEntity cls) { |
| 834 assert(isClosed); | |
| 835 if (_liveMixinUses == null) { | 830 if (_liveMixinUses == null) { |
| 836 _liveMixinUses = new Map<ClassElement, List<MixinApplicationElement>>(); | 831 _liveMixinUses = new Map<ClassEntity, List<ClassEntity>>(); |
| 837 for (ClassElement mixin in _mixinUses.keys) { | 832 for (ClassElement mixin in _mixinUses.keys) { |
| 838 List<MixinApplicationElement> uses = <MixinApplicationElement>[]; | 833 List<ClassEntity> uses = <ClassEntity>[]; |
| 839 | 834 |
| 840 void addLiveUse(MixinApplicationElement mixinApplication) { | 835 void addLiveUse(MixinApplicationElement mixinApplication) { |
| 841 if (isInstantiated(mixinApplication)) { | 836 if (isInstantiated(mixinApplication)) { |
| 842 uses.add(mixinApplication); | 837 uses.add(mixinApplication); |
| 843 } else if (mixinApplication.isNamedMixinApplication) { | 838 } else if (mixinApplication.isNamedMixinApplication) { |
| 844 Set<ClassEntity> next = _mixinUses[mixinApplication]; | 839 Set<ClassEntity> next = _mixinUses[mixinApplication]; |
| 845 if (next != null) { | 840 if (next != null) { |
| 846 next.forEach(addLiveUse); | 841 next.forEach(addLiveUse); |
| 847 } | 842 } |
| 848 } | 843 } |
| 849 } | 844 } |
| 850 | 845 |
| 851 _mixinUses[mixin].forEach(addLiveUse); | 846 _mixinUses[mixin].forEach(addLiveUse); |
| 852 if (uses.isNotEmpty) { | 847 if (uses.isNotEmpty) { |
| 853 _liveMixinUses[mixin] = uses; | 848 _liveMixinUses[mixin] = uses; |
| 854 } | 849 } |
| 855 } | 850 } |
| 856 } | 851 } |
| 857 Iterable<MixinApplicationElement> uses = _liveMixinUses[cls]; | 852 Iterable<ClassEntity> uses = _liveMixinUses[cls]; |
| 858 return uses != null ? uses : const <MixinApplicationElement>[]; | 853 return uses != null ? uses : const <ClassEntity>[]; |
| 859 } | 854 } |
| 860 | 855 |
| 861 /// Returns `true` if [cls] is mixed into a live class. | 856 /// Returns `true` if [cls] is mixed into a live class. |
| 862 bool isUsedAsMixin(ClassElement cls) { | 857 bool isUsedAsMixin(ClassEntity cls) { |
| 863 assert(isClosed); | |
| 864 return !mixinUsesOf(cls).isEmpty; | 858 return !mixinUsesOf(cls).isEmpty; |
| 865 } | 859 } |
| 866 | 860 |
| 867 /// Returns `true` if any live class that mixes in [cls] implements [type]. | 861 /// Returns `true` if any live class that mixes in [cls] implements [type]. |
| 868 bool hasAnySubclassOfMixinUseThatImplements( | 862 bool hasAnySubclassOfMixinUseThatImplements( |
| 869 ClassElement cls, ClassElement type) { | 863 ClassEntity cls, ClassEntity type) { |
| 870 assert(isClosed); | |
| 871 return mixinUsesOf(cls) | 864 return mixinUsesOf(cls) |
| 872 .any((use) => hasAnySubclassThatImplements(use, type)); | 865 .any((use) => hasAnySubclassThatImplements(use, type)); |
| 873 } | 866 } |
| 874 | 867 |
| 875 /// Returns `true` if any live class that mixes in [mixin] is also a subclass | 868 /// Returns `true` if any live class that mixes in [mixin] is also a subclass |
| 876 /// of [superclass]. | 869 /// of [superclass]. |
| 877 bool hasAnySubclassThatMixes(ClassElement superclass, ClassElement mixin) { | 870 bool hasAnySubclassThatMixes(ClassEntity superclass, ClassEntity mixin) { |
| 878 assert(isClosed); | 871 return mixinUsesOf(mixin).any((ClassElement each) { |
| 879 return mixinUsesOf(mixin).any((each) => each.isSubclassOf(superclass)); | 872 return each.isSubclassOf(superclass); |
| 873 }); |
| 880 } | 874 } |
| 881 | 875 |
| 882 /// Returns `true` if [cls] or any superclass mixes in [mixin]. | 876 /// Returns `true` if [cls] or any superclass mixes in [mixin]. |
| 883 bool isSubclassOfMixinUseOf(ClassElement cls, ClassElement mixin) { | 877 bool isSubclassOfMixinUseOf(ClassEntity cls, ClassEntity mixin) { |
| 884 assert(isClosed); | 878 assert(_checkClass(cls)); |
| 885 assert(cls.isDeclaration); | 879 assert(_checkClass(mixin)); |
| 886 assert(mixin.isDeclaration); | |
| 887 if (isUsedAsMixin(mixin)) { | 880 if (isUsedAsMixin(mixin)) { |
| 888 ClassElement current = cls; | 881 ClassElement current = cls; |
| 889 while (current != null) { | 882 while (current != null) { |
| 890 if (current.isMixinApplication) { | 883 if (current.isMixinApplication) { |
| 891 MixinApplicationElement application = current; | 884 MixinApplicationElement application = current; |
| 892 if (application.mixin == mixin) return true; | 885 if (application.mixin == mixin) return true; |
| 893 } | 886 } |
| 894 current = current.superclass; | 887 current = current.superclass; |
| 895 } | 888 } |
| 896 } | 889 } |
| 897 return false; | 890 return false; |
| 898 } | 891 } |
| 899 | 892 |
| 900 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass | 893 /// Returns `true` if every subtype of [x] is a subclass of [y] or a subclass |
| 901 /// of a mixin application of [y]. | 894 /// of a mixin application of [y]. |
| 902 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassElement x, ClassElement y) { | 895 bool everySubtypeIsSubclassOfOrMixinUseOf(ClassEntity x, ClassEntity y) { |
| 903 assert(isClosed); | 896 assert(_checkClass(x)); |
| 904 assert(x.isDeclaration); | 897 assert(_checkClass(y)); |
| 905 assert(y.isDeclaration); | 898 Map<ClassEntity, bool> secondMap = |
| 906 Map<ClassElement, bool> secondMap = | 899 _subtypeCoveredByCache[x] ??= <ClassEntity, bool>{}; |
| 907 _subtypeCoveredByCache[x] ??= <ClassElement, bool>{}; | 900 return secondMap[y] ??= subtypesOf(x).every((ClassEntity cls) => |
| 908 return secondMap[y] ??= subtypesOf(x).every((ClassElement cls) => | |
| 909 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y)); | 901 isSubclassOf(cls, y) || isSubclassOfMixinUseOf(cls, y)); |
| 910 } | 902 } |
| 911 | 903 |
| 912 /// Returns `true` if any subclass of [superclass] implements [type]. | 904 /// Returns `true` if any subclass of [superclass] implements [type]. |
| 913 bool hasAnySubclassThatImplements( | 905 bool hasAnySubclassThatImplements(ClassEntity superclass, ClassEntity type) { |
| 914 ClassElement superclass, ClassElement type) { | 906 assert(_checkClass(superclass)); |
| 915 assert(isClosed); | 907 Set<ClassEntity> subclasses = _typesImplementedBySubclasses[superclass]; |
| 916 | |
| 917 Set<ClassEntity> subclasses = | |
| 918 _typesImplementedBySubclasses[superclass.declaration]; | |
| 919 if (subclasses == null) return false; | 908 if (subclasses == null) return false; |
| 920 return subclasses.contains(type); | 909 return subclasses.contains(type); |
| 921 } | 910 } |
| 922 | 911 |
| 923 @override | 912 @override |
| 924 bool hasElementIn(ClassElement cls, Selector selector, Element element) { | 913 bool hasElementIn(ClassEntity cls, Selector selector, Element element) { |
| 925 // Use [:implementation:] of [element] | 914 // Use [:implementation:] of [element] |
| 926 // because our function set only stores declarations. | 915 // because our function set only stores declarations. |
| 927 Element result = findMatchIn(cls, selector); | 916 Element result = findMatchIn(cls, selector); |
| 928 return result == null | 917 return result == null |
| 929 ? false | 918 ? false |
| 930 : result.implementation == element.implementation; | 919 : result.implementation == element.implementation; |
| 931 } | 920 } |
| 932 | 921 |
| 933 MemberElement findMatchIn(ClassElement cls, Selector selector, | 922 MemberElement findMatchIn(ClassElement cls, Selector selector, |
| 934 {ClassElement stopAtSuperclass}) { | 923 {ClassElement stopAtSuperclass}) { |
| (...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1000 } | 989 } |
| 1001 return false; | 990 return false; |
| 1002 } | 991 } |
| 1003 } | 992 } |
| 1004 | 993 |
| 1005 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies | 994 /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies |
| 1006 /// of known classes. | 995 /// of known classes. |
| 1007 /// | 996 /// |
| 1008 /// This method is only provided for testing. For queries on classes, use the | 997 /// This method is only provided for testing. For queries on classes, use the |
| 1009 /// methods defined in [ClosedWorld]. | 998 /// methods defined in [ClosedWorld]. |
| 1010 ClassHierarchyNode getClassHierarchyNode(ClassElement cls) { | 999 ClassHierarchyNode getClassHierarchyNode(ClassEntity cls) { |
| 1011 return _classHierarchyNodes[cls.declaration]; | 1000 assert(_checkClass(cls)); |
| 1001 return _classHierarchyNodes[cls]; |
| 1012 } | 1002 } |
| 1013 | 1003 |
| 1014 /// Returns [ClassSet] for [cls] used to model the extends and implements | 1004 /// Returns [ClassSet] for [cls] used to model the extends and implements |
| 1015 /// relations of known classes. | 1005 /// relations of known classes. |
| 1016 /// | 1006 /// |
| 1017 /// This method is only provided for testing. For queries on classes, use the | 1007 /// This method is only provided for testing. For queries on classes, use the |
| 1018 /// methods defined in [ClosedWorld]. | 1008 /// methods defined in [ClosedWorld]. |
| 1019 ClassSet getClassSet(ClassElement cls) { | 1009 ClassSet getClassSet(ClassEntity cls) { |
| 1020 return _classSets[cls.declaration]; | 1010 assert(_checkClass(cls)); |
| 1011 return _classSets[cls]; |
| 1021 } | 1012 } |
| 1022 | 1013 |
| 1023 void registerClosureClass(ClosureClassElement cls) { | 1014 void registerClosureClass(ClosureClassElement cls) { |
| 1024 ClassHierarchyNode parentNode = getClassHierarchyNode(cls.superclass); | 1015 ClassHierarchyNode parentNode = getClassHierarchyNode(cls.superclass); |
| 1025 ClassHierarchyNode node = _classHierarchyNodes[cls] = | 1016 ClassHierarchyNode node = _classHierarchyNodes[cls] = |
| 1026 new ClassHierarchyNode(parentNode, cls, cls.hierarchyDepth); | 1017 new ClassHierarchyNode(parentNode, cls, cls.hierarchyDepth); |
| 1027 for (ResolutionInterfaceType type in cls.allSupertypes) { | 1018 for (ResolutionInterfaceType type in cls.allSupertypes) { |
| 1028 ClassSet subtypeSet = getClassSet(type.element); | 1019 ClassSet subtypeSet = getClassSet(type.element); |
| 1029 subtypeSet.addSubtype(node); | 1020 subtypeSet.addSubtype(node); |
| 1030 } | 1021 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1065 bool hasAnyUserDefinedGetter(Selector selector, TypeMask mask) { | 1056 bool hasAnyUserDefinedGetter(Selector selector, TypeMask mask) { |
| 1066 return allFunctions.filter(selector, mask).any((each) => each.isGetter); | 1057 return allFunctions.filter(selector, mask).any((each) => each.isGetter); |
| 1067 } | 1058 } |
| 1068 | 1059 |
| 1069 FieldElement locateSingleField(Selector selector, TypeMask mask) { | 1060 FieldElement locateSingleField(Selector selector, TypeMask mask) { |
| 1070 Element result = locateSingleElement(selector, mask); | 1061 Element result = locateSingleElement(selector, mask); |
| 1071 return (result != null && result.isField) ? result : null; | 1062 return (result != null && result.isField) ? result : null; |
| 1072 } | 1063 } |
| 1073 | 1064 |
| 1074 MemberElement locateSingleElement(Selector selector, TypeMask mask) { | 1065 MemberElement locateSingleElement(Selector selector, TypeMask mask) { |
| 1075 assert(isClosed); | |
| 1076 mask ??= commonMasks.dynamicType; | 1066 mask ??= commonMasks.dynamicType; |
| 1077 return mask.locateSingleElement(selector, this); | 1067 return mask.locateSingleElement(selector, this); |
| 1078 } | 1068 } |
| 1079 | 1069 |
| 1080 TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) { | 1070 TypeMask extendMaskIfReachesAll(Selector selector, TypeMask mask) { |
| 1081 assert(isClosed); | |
| 1082 bool canReachAll = true; | 1071 bool canReachAll = true; |
| 1083 if (mask != null) { | 1072 if (mask != null) { |
| 1084 canReachAll = _backend.backendUsage.isInvokeOnUsed && | 1073 canReachAll = _backend.backendUsage.isInvokeOnUsed && |
| 1085 mask.needsNoSuchMethodHandling(selector, this); | 1074 mask.needsNoSuchMethodHandling(selector, this); |
| 1086 } | 1075 } |
| 1087 return canReachAll ? commonMasks.dynamicType : mask; | 1076 return canReachAll ? commonMasks.dynamicType : mask; |
| 1088 } | 1077 } |
| 1089 | 1078 |
| 1090 void addFunctionCalledInLoop(Element element) { | 1079 void addFunctionCalledInLoop(Element element) { |
| 1091 functionsCalledInLoop.add(element.declaration); | 1080 functionsCalledInLoop.add(element.declaration); |
| (...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1191 return getMightBePassedToApply(element.expression); | 1180 return getMightBePassedToApply(element.expression); |
| 1192 } | 1181 } |
| 1193 return functionsThatMightBePassedToApply.contains(element); | 1182 return functionsThatMightBePassedToApply.contains(element); |
| 1194 } | 1183 } |
| 1195 | 1184 |
| 1196 @override | 1185 @override |
| 1197 bool getCurrentlyKnownMightBePassedToApply(Element element) { | 1186 bool getCurrentlyKnownMightBePassedToApply(Element element) { |
| 1198 return getMightBePassedToApply(element); | 1187 return getMightBePassedToApply(element); |
| 1199 } | 1188 } |
| 1200 } | 1189 } |
| OLD | NEW |