Index: pkg/compiler/lib/src/world.dart |
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart |
index e8c9b13752317ee0917a6c77a074448056030764..481bd3888b1c38f689230551ba2f846e3ad4ce0d 100644 |
--- a/pkg/compiler/lib/src/world.dart |
+++ b/pkg/compiler/lib/src/world.dart |
@@ -185,9 +185,9 @@ class World implements ClassWorld { |
Iterable<ClassElement> subclassesOf(ClassElement cls) { |
ClassHierarchyNode hierarchy = _classHierarchyNodes[cls.declaration]; |
if (hierarchy == null) return const <ClassElement>[]; |
- assert(invariant(cls, isInstantiated(cls.declaration), |
- message: 'Class $cls has not been instantiated.')); |
- return hierarchy.subclasses(); |
+ return hierarchy.subclasses( |
+ includeIndirectlyInstantiated: false, |
+ includeUninstantiated: false); |
} |
/// Returns an iterable over the directly instantiated classes that extend |
@@ -195,16 +195,24 @@ class World implements ClassWorld { |
Iterable<ClassElement> strictSubclassesOf(ClassElement cls) { |
ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
if (subclasses == null) return const <ClassElement>[]; |
- assert(invariant(cls, isInstantiated(cls.declaration), |
- message: 'Class $cls has not been instantiated.')); |
- return subclasses.strictSubclasses(); |
+ return subclasses.subclasses( |
+ strict: true, |
+ includeIndirectlyInstantiated: false, |
+ includeUninstantiated: false); |
} |
/// Returns an iterable over the directly instantiated that implement [cls] |
/// _not_ including [cls]. |
Iterable<ClassElement> strictSubtypesOf(ClassElement cls) { |
- Set<ClassElement> subtypes = _subtypes[cls.declaration]; |
- return subtypes != null ? subtypes : const <ClassElement>[]; |
+ ClassSet classSet = _classSets[cls.declaration]; |
+ if (classSet == null) { |
+ return const <ClassElement>[]; |
+ } else { |
+ return classSet.subtypes( |
+ strict: true, |
+ includeIndirectlyInstantiated: false, |
+ includeUninstantiated: false); |
+ } |
} |
/// Returns `true` if any directly instantiated class other than [cls] extends |
@@ -212,8 +220,6 @@ class World implements ClassWorld { |
bool hasAnyStrictSubclass(ClassElement cls) { |
ClassHierarchyNode subclasses = _classHierarchyNodes[cls.declaration]; |
if (subclasses == null) return false; |
- assert(invariant(cls, isInstantiated(cls.declaration), |
- message: 'Class $cls has not been instantiated.')); |
return subclasses.isIndirectlyInstantiated; |
} |
@@ -338,8 +344,8 @@ class World implements ClassWorld { |
// distinct sets to make class hierarchy analysis faster. |
final Map<ClassElement, ClassHierarchyNode> _classHierarchyNodes = |
<ClassElement, ClassHierarchyNode>{}; |
- final Map<ClassElement, Set<ClassElement>> _subtypes = |
- new Map<ClassElement, Set<ClassElement>>(); |
+ final Map<ClassElement, ClassSet> _classSets = |
+ <ClassElement, ClassSet>{}; |
final Set<Element> sideEffectsFreeElements = new Set<Element>(); |
@@ -371,38 +377,81 @@ class World implements ClassWorld { |
this.compiler = compiler, |
alreadyPopulated = compiler.cacheStrategy.newSet(); |
- ClassHierarchyNode classHierarchyNode(ClassElement cls) { |
- return _classHierarchyNodes[cls]; |
+ /// Called to add [cls] to the set of known classes. |
+ /// |
+ /// This ensures that class hierarchy queries can be performed on [cls] and |
+ /// classes that extend or implement it. |
+ void registerClass(ClassElement cls) { |
+ _ensureClassSet(cls); |
+ } |
+ |
+ /// Returns [ClassHierarchyNode] for [cls] used to model the class hierarchies |
+ /// of known classes. |
+ /// |
+ /// This method is only provided for testing. For queries on classes, use the |
+ /// methods defined in [ClassWorld]. |
+ ClassHierarchyNode getClassHierarchyNode(ClassElement cls) { |
+ return _classHierarchyNodes[cls.declaration]; |
+ } |
+ |
+ ClassHierarchyNode _ensureClassHierarchyNode(ClassElement cls) { |
+ cls = cls.declaration; |
+ return _classHierarchyNodes.putIfAbsent(cls, () { |
+ ClassHierarchyNode node = new ClassHierarchyNode(cls); |
+ if (cls.superclass != null) { |
+ _ensureClassHierarchyNode(cls.superclass).addDirectSubclass(node); |
+ } |
+ return node; |
+ }); |
} |
- void populate() { |
+ /// Returns [ClassSet] for [cls] used to model the extends and implements |
+ /// relations of known classes. |
+ /// |
+ /// This method is only provided for testing. For queries on classes, use the |
+ /// methods defined in [ClassWorld]. |
+ ClassSet getClassSet(ClassElement cls) { |
+ return _classSets[cls.declaration]; |
+ } |
+ |
+ ClassSet _ensureClassSet(ClassElement cls) { |
+ cls = cls.declaration; |
+ return _classSets.putIfAbsent(cls, () { |
+ ClassHierarchyNode node = _ensureClassHierarchyNode(cls); |
+ ClassSet classSet = new ClassSet(node); |
+ |
+ for (InterfaceType type in cls.allSupertypes) { |
+ // TODO(johnniwinther): Optimization: Avoid adding [cls] to |
+ // superclasses. |
+ ClassSet subtypeSet = _ensureClassSet(type.element); |
+ subtypeSet.addSubtype(node); |
+ } |
+ return classSet; |
+ }); |
+ } |
- /// Ensure that a [ClassHierarchyNode] exists for [cls]. Updates the |
- /// `isDirectlyInstantiated` and `isIndirectlyInstantiated` property of the |
- /// node according the provided arguments and returns the node. |
- ClassHierarchyNode createClassHierarchyNodeForClass( |
+ void populate() { |
+ /// Updates the `isDirectlyInstantiated` and `isIndirectlyInstantiated` |
+ /// properties of the [ClassHierarchyNode] for [cls]. |
+ void updateClassHierarchyNodeForClass( |
ClassElement cls, |
{bool directlyInstantiated: false, |
bool indirectlyInstantiated: false}) { |
- assert(isInstantiated(cls)); |
- |
- ClassHierarchyNode node = _classHierarchyNodes.putIfAbsent(cls, () { |
- ClassHierarchyNode node = new ClassHierarchyNode(cls); |
- if (cls.superclass != null) { |
- createClassHierarchyNodeForClass(cls.superclass, |
- indirectlyInstantiated: |
- directlyInstantiated || indirectlyInstantiated) |
- .addDirectSubclass(node); |
- } |
- return node; |
- }); |
- if (directlyInstantiated) { |
+ assert(!directlyInstantiated || isInstantiated(cls)); |
+ ClassHierarchyNode node = getClassHierarchyNode(cls); |
+ bool changed = false; |
+ if (directlyInstantiated && !node.isDirectlyInstantiated) { |
node.isDirectlyInstantiated = true; |
+ changed = true; |
} |
- if (indirectlyInstantiated) { |
+ if (indirectlyInstantiated && !node.isIndirectlyInstantiated) { |
node.isIndirectlyInstantiated = true; |
+ changed = true; |
+ } |
+ if (changed && cls.superclass != null) { |
+ updateClassHierarchyNodeForClass( |
+ cls.superclass, indirectlyInstantiated: true); |
} |
- return node; |
} |
void addSubtypes(ClassElement cls) { |
@@ -414,13 +463,7 @@ class World implements ClassWorld { |
compiler.internalError(cls, 'Class "${cls.name}" is not resolved.'); |
} |
- createClassHierarchyNodeForClass(cls, directlyInstantiated: true); |
- |
- for (DartType type in cls.allSupertypes) { |
- Set<Element> subtypesOfSupertype = |
- _subtypes.putIfAbsent(type.element, () => new Set<ClassElement>()); |
- subtypesOfSupertype.add(cls); |
- } |
+ updateClassHierarchyNodeForClass(cls, directlyInstantiated: true); |
// Walk through the superclasses, and record the types |
// implemented by that type on the superclasses. |