Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(767)

Unified Diff: pkg/compiler/lib/src/universe/class_set.dart

Issue 1304083008: Add ClassSet to support ClassWorld.strictSubtypesOf (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Updated cf. comments. Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/use_unused_api.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/universe/class_set.dart
diff --git a/pkg/compiler/lib/src/universe/class_set.dart b/pkg/compiler/lib/src/universe/class_set.dart
index 11d9e090ac21eb237b2408f099a50cf162f7dfe4..d19b2c1ceff8cd1cc655b6d0d016c9761c89a1ac 100644
--- a/pkg/compiler/lib/src/universe/class_set.dart
+++ b/pkg/compiler/lib/src/universe/class_set.dart
@@ -12,7 +12,27 @@ import '../util/util.dart' show Link;
///
/// This is used by the [ClassWorld] to perform queries on subclass and subtype
/// relations.
-// TODO(johnniwinther): Use this for `ClassWorld.subtypesOf`.
+///
+/// For this class hierarchy:
+///
+/// class A {}
+/// class B extends A {}
+/// class C extends A {}
+/// class D extends B {}
+/// class E extends D {}
+///
+/// the [ClassHierarchyNode]s form this subclass tree:
+///
+/// Object
+/// |
+/// A
+/// / \
+/// B C
+/// |
+/// D
+/// |
+/// E
+///
class ClassHierarchyNode {
final ClassElement cls;
@@ -47,39 +67,240 @@ class ClassHierarchyNode {
_directSubclasses = _directSubclasses.prepend(subclass);
}
+ /// Returns `true` if [other] is contained in the subtree of this node.
+ ///
+ /// This means that [other] is a subclass of [cls].
+ bool contains(ClassElement other) {
+ while (other != null) {
+ if (cls == other) return true;
+ if (cls.hierarchyDepth >= other.hierarchyDepth) return false;
+ other = other.superclass;
+ }
+ return false;
+ }
+
/// `true` if [cls] has been directly or indirectly instantiated.
bool get isInstantiated => isDirectlyInstantiated || isIndirectlyInstantiated;
/// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
- /// If [directlyInstantiated] is `true`, the iterable only returns the
- /// directly instantiated subclasses of [cls].
- Iterable<ClassElement> subclasses({bool directlyInstantiated: true}) {
+ ///
+ /// The directly instantiated, indirectly instantiated and uninstantiated
+ /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
+ /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+ /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+ Iterable<ClassElement> subclasses(
+ {bool includeDirectlyInstantiated: true,
+ bool includeIndirectlyInstantiated: true,
+ bool includeUninstantiated: true,
+ bool strict: false}) {
return new ClassHierarchyNodeIterable(
- this, directlyInstantiatedOnly: directlyInstantiated);
+ this,
+ includeRoot: !strict,
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated);
}
- /// Returns an [Iterable] of the strict subclasses of [cls] _not_ including
- /// [cls] itself. If [directlyInstantiated] is `true`, the iterable only
- /// returns the directly instantiated subclasses of [cls].
- Iterable<ClassElement> strictSubclasses(
- {bool directlyInstantiated: true}) {
- return new ClassHierarchyNodeIterable(this,
- includeRoot: false, directlyInstantiatedOnly: directlyInstantiated);
+ void dump(StringBuffer sb, String indentation) {
+ sb.write('$indentation$cls:[');
+ if (_directSubclasses.isEmpty) {
+ sb.write(']');
+ } else {
+ sb.write('\n');
+ bool needsComma = false;
+ for (Link<ClassHierarchyNode> link = _directSubclasses;
+ !link.isEmpty;
+ link = link.tail) {
+ if (needsComma) {
+ sb.write(',\n');
+ }
+ link.head.dump(sb, '$indentation ');
+ needsComma = true;
+ }
+ sb.write('\n');
+ sb.write('$indentation]');
+ }
}
String toString() => cls.toString();
}
+/// Object holding the subclass and subtype relation for a single
+/// [ClassElement].
+///
+/// The subclass relation for a class `C` is modelled through a reference to
+/// the [ClassHierarchyNode] for `C` in the global [ClassHierarchyNode] tree
+/// computed in [World].
+///
+/// The subtype relation for a class `C` is modelled through a collection of
+/// disjoint [ClassHierarchyNode] subtrees. The subclasses of `C`, modelled
+/// through the aforementioned [ClassHierarchyNode] pointer, are extended with
+/// the subtypes that do not extend `C` through a list of additional
+/// [ClassHierarchyNode] nodes. This list is normalized to contain only the
+/// nodes for the topmost subtypes and is furthermore ordered in increasing
+/// hierarchy depth order.
+///
+/// For this class hierarchy:
+///
+/// class A {}
+/// class B extends A {}
+/// class C implements B {}
+/// class D implements A {}
+/// class E extends D {}
+/// class F implements D {}
+///
+/// the [ClassHierarchyNode] tree is
+///
+/// Object
+/// / | | \
+/// A C D F
+/// | |
+/// B E
+///
+/// and the [ClassSet] for `A` holds these [ClassHierarchyNode] nodes:
+///
+/// A -> [C, D, F]
+///
+/// The subtypes `B` and `E` are not directly modeled because they are implied
+/// by their subclass relation to `A` and `D`, repectively. This can be seen
+/// if we expand the subclass subtrees:
+///
+/// A -> [C, D, F]
+/// | |
+/// B E
+///
+class ClassSet {
+ final ClassHierarchyNode node;
+
+ List<ClassHierarchyNode> _directSubtypes;
+
+ ClassSet(this.node);
+
+ ClassElement get cls => node.cls;
+
+ /// Returns an [Iterable] of the subclasses of [cls] possibly including [cls].
+ ///
+ /// The directly instantiated, indirectly instantiated and uninstantiated
+ /// subclasses of [cls] are returned if [includeDirectlyInstantiated],
+ /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+ /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+ Iterable<ClassElement> subclasses(
+ {bool includeDirectlyInstantiated: true,
+ bool includeIndirectlyInstantiated: true,
+ bool includeUninstantiated: true,
+ bool strict: false}) {
+ return node.subclasses(
+ strict: strict,
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated);
+ }
+
+ /// Returns an [Iterable] of the subtypes of [cls] possibly including [cls].
+ ///
+ /// The directly instantiated, indirectly instantiated and uninstantiated
+ /// subtypes of [cls] are returned if [includeDirectlyInstantiated],
+ /// [includeIndirectlyInstantiated], and [includeUninstantiated] are `true`,
+ /// respectively. If [strict] is `true`, [cls] itself is _not_ returned.
+ Iterable<ClassElement> subtypes(
+ {bool includeDirectlyInstantiated: true,
+ bool includeIndirectlyInstantiated: true,
+ bool includeUninstantiated: true,
+ bool strict: false}) {
+ if (_directSubtypes == null) {
+ return node.subclasses(
+ strict: strict,
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated);
+ }
+ return new SubtypesIterable.SubtypesIterator(this,
+ includeRoot: !strict,
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated);
+ }
+
+ /// Adds [subtype] as a subtype of [cls].
+ void addSubtype(ClassHierarchyNode subtype) {
+ if (node.contains(subtype.cls)) {
+ return;
+ }
+ if (_directSubtypes == null) {
+ _directSubtypes = <ClassHierarchyNode>[subtype];
+ } else {
+ int hierarchyDepth = subtype.cls.hierarchyDepth;
+ List<ClassHierarchyNode> newSubtypes = <ClassHierarchyNode>[];
+ bool added = false;
+ for (ClassHierarchyNode otherSubtype in _directSubtypes) {
+ int otherHierarchyDepth = otherSubtype.cls.hierarchyDepth;
+ if (hierarchyDepth == otherHierarchyDepth) {
+ if (subtype == otherSubtype) {
+ return;
+ } else {
+ // [otherSubtype] is unrelated to [subtype].
+ newSubtypes.add(otherSubtype);
+ }
+ } else if (hierarchyDepth > otherSubtype.cls.hierarchyDepth) {
+ // [otherSubtype] could be a superclass of [subtype].
+ if (otherSubtype.contains(subtype.cls)) {
+ // [subtype] is already in this set.
+ return;
+ } else {
+ // [otherSubtype] is unrelated to [subtype].
+ newSubtypes.add(otherSubtype);
+ }
+ } else {
+ if (!added) {
+ // Insert [subtype] before other subtypes of higher hierarchy depth.
+ newSubtypes.add(subtype);
+ added = true;
+ }
+ // [subtype] could be a superclass of [otherSubtype].
+ if (subtype.contains(otherSubtype.cls)) {
+ // Replace [otherSubtype].
+ } else {
+ newSubtypes.add(otherSubtype);
+ }
+ }
+ }
+ if (!added) {
+ newSubtypes.add(subtype);
+ }
+ _directSubtypes = newSubtypes;
+ }
+ }
+
+ String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.write('[\n');
+ node.dump(sb, ' ');
+ sb.write('\n');
+ if (_directSubtypes != null) {
+ for (ClassHierarchyNode node in _directSubtypes) {
+ node.dump(sb, ' ');
+ sb.write('\n');
+ }
+ }
+ sb.write(']');
+ return sb.toString();
+ }
+}
+
/// Iterable for subclasses of a [ClassHierarchyNode].
class ClassHierarchyNodeIterable extends IterableBase<ClassElement> {
final ClassHierarchyNode root;
final bool includeRoot;
- final bool directlyInstantiatedOnly;
+ final bool includeDirectlyInstantiated;
+ final bool includeIndirectlyInstantiated;
+ final bool includeUninstantiated;
ClassHierarchyNodeIterable(
this.root,
{this.includeRoot: true,
- this.directlyInstantiatedOnly: false}) {
+ this.includeDirectlyInstantiated: true,
+ this.includeIndirectlyInstantiated: true,
+ this.includeUninstantiated: true}) {
if (root == null) throw new StateError("No root for iterable.");
}
@@ -112,7 +333,13 @@ class ClassHierarchyNodeIterator implements Iterator<ClassElement> {
bool get includeRoot => iterable.includeRoot;
- bool get directlyInstantiatedOnly => iterable.directlyInstantiatedOnly;
+ bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
+
+ bool get includeIndirectlyInstantiated {
+ return iterable.includeIndirectlyInstantiated;
+ }
+
+ bool get includeUninstantiated => iterable.includeUninstantiated;
@override
ClassElement get current {
@@ -143,6 +370,11 @@ class ClassHierarchyNodeIterator implements Iterator<ClassElement> {
}
currentNode = stack.head;
stack = stack.tail;
+ if (!includeUninstantiated && !currentNode.isInstantiated) {
+ // We're only iterating instantiated classes so there is no use in
+ // visiting the current node and its subtree.
+ continue;
+ }
for (Link<ClassHierarchyNode> link = currentNode._directSubclasses;
!link.isEmpty;
link = link.tail) {
@@ -157,9 +389,90 @@ class ClassHierarchyNodeIterator implements Iterator<ClassElement> {
/// Returns `true` if the class of [node] is a valid result for this iterator.
bool _isValid(ClassHierarchyNode node) {
if (!includeRoot && node == root) return false;
- if (directlyInstantiatedOnly && !node.isDirectlyInstantiated) return false;
- return true;
+ if (includeDirectlyInstantiated && node.isDirectlyInstantiated) {
+ return true;
+ }
+ if (includeIndirectlyInstantiated && node.isIndirectlyInstantiated) {
+ return true;
+ }
+ if (includeUninstantiated && !node.isInstantiated) {
+ return true;
+ }
+ return false;
}
}
+/// Iterable for the subtypes in a [ClassSet].
+class SubtypesIterable extends IterableBase<ClassElement> {
+ final ClassSet subtypeSet;
+ final bool includeRoot;
+ final bool includeDirectlyInstantiated;
+ final bool includeIndirectlyInstantiated;
+ final bool includeUninstantiated;
+
+ SubtypesIterable.SubtypesIterator(
+ this.subtypeSet,
+ {this.includeRoot: true,
+ this.includeDirectlyInstantiated: true,
+ this.includeIndirectlyInstantiated: true,
+ this.includeUninstantiated: true});
+
+ @override
+ Iterator<ClassElement> get iterator => new SubtypesIterator(this);
+}
+
+/// Iterator for the subtypes in a [ClassSet].
+class SubtypesIterator extends Iterator<ClassElement> {
+ final SubtypesIterable iterable;
+ Iterator<ClassElement> elements;
+ Iterator<ClassHierarchyNode> hierarchyNodes;
+
+ SubtypesIterator(this.iterable);
+ bool get includeRoot => iterable.includeRoot;
+
+ bool get includeDirectlyInstantiated => iterable.includeDirectlyInstantiated;
+
+ bool get includeIndirectlyInstantiated {
+ return iterable.includeIndirectlyInstantiated;
+ }
+
+ bool get includeUninstantiated => iterable.includeUninstantiated;
+
+ @override
+ ClassElement get current {
+ if (elements != null) {
+ return elements.current;
+ }
+ return null;
+ }
+
+ @override
+ bool moveNext() {
+ if (elements == null && hierarchyNodes == null) {
+ // Initial state. Iterate through subclasses.
+ elements = iterable.subtypeSet.node.subclasses(
+ strict: !includeRoot,
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated).iterator;
+ }
+ if (elements != null && elements.moveNext()) {
+ return true;
+ }
+ if (hierarchyNodes == null) {
+ // Start iterating through subtypes.
+ hierarchyNodes = iterable.subtypeSet._directSubtypes.iterator;
+ }
+ while (hierarchyNodes.moveNext()) {
+ elements = hierarchyNodes.current.subclasses(
+ includeDirectlyInstantiated: includeDirectlyInstantiated,
+ includeIndirectlyInstantiated: includeIndirectlyInstantiated,
+ includeUninstantiated: includeUninstantiated).iterator;
+ if (elements.moveNext()) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
« no previous file with comments | « pkg/compiler/lib/src/serialization/modelz.dart ('k') | pkg/compiler/lib/src/use_unused_api.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698