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 |