Index: pkg/kernel/lib/src/incremental_class_hierarchy.dart |
diff --git a/pkg/kernel/lib/src/incremental_class_hierarchy.dart b/pkg/kernel/lib/src/incremental_class_hierarchy.dart |
index cb1696e9b5eadd298634bcc39c17f2382a17de94..bdca807d4ca06740978362fe52f538992cc66f02 100644 |
--- a/pkg/kernel/lib/src/incremental_class_hierarchy.dart |
+++ b/pkg/kernel/lib/src/incremental_class_hierarchy.dart |
@@ -7,9 +7,13 @@ import 'dart:math'; |
import 'package:kernel/ast.dart'; |
import 'package:kernel/class_hierarchy.dart'; |
+import 'package:kernel/src/heap.dart'; |
/// Lazy and incremental implementation of [ClassHierarchy]. |
class IncrementalClassHierarchy implements ClassHierarchy { |
+ /// The next unique identifier for [_ClassInfo]s. |
+ int _nextId = 0; |
+ |
/// The mapping from [Class]es to the corresponding [_ClassInfo]s. |
/// It is filled lazily as the client requests information about classes. |
final Map<Class, _ClassInfo> _info = {}; |
@@ -35,22 +39,7 @@ class IncrementalClassHierarchy implements ClassHierarchy { |
@override |
int getClassDepth(Class node) { |
- var info = _getInfo(node); |
- if (info.depth < 0) { |
- int superDepth = -1; |
- if (node.supertype != null) { |
- superDepth = max(superDepth, getClassDepth(node.supertype.classNode)); |
- } |
- if (node.mixedInType != null) { |
- superDepth = max(superDepth, getClassDepth(node.mixedInType.classNode)); |
- } |
- for (var supertype in node.implementedTypes) { |
- superDepth = max(superDepth, getClassDepth(supertype.classNode)); |
- } |
- info.depth = superDepth + 1; |
- } |
- |
- return info.depth; |
+ return _getInfo(node).depth; |
} |
@override |
@@ -61,9 +50,8 @@ class IncrementalClassHierarchy implements ClassHierarchy { |
} |
@override |
- int getClassIndex(Class class_) { |
- // TODO(scheglov): implement getClassIndex |
- throw new UnimplementedError(); |
+ int getClassIndex(Class node) { |
+ return _getInfo(node).id; |
} |
@override |
@@ -79,9 +67,9 @@ class IncrementalClassHierarchy implements ClassHierarchy { |
} |
@override |
- List<Class> getRankedSuperclasses(Class class_) { |
- // TODO(scheglov): implement getRankedSuperclasses |
- throw new UnimplementedError(); |
+ List<Class> getRankedSuperclasses(Class node) { |
+ var info = _getInfo(node); |
+ return _getRankedSuperclassList(info).map((info) => info.node).toList(); |
} |
@override |
@@ -98,17 +86,95 @@ class IncrementalClassHierarchy implements ClassHierarchy { |
/// Return the [_ClassInfo] for the [node]. |
_ClassInfo _getInfo(Class node) { |
- return _info.putIfAbsent(node, () => new _ClassInfo(node)); |
+ var info = _info[node]; |
+ if (info == null) { |
+ info = new _ClassInfo(_nextId++, node); |
+ _info[node] = info; |
+ |
+ int superDepth = -1; |
+ if (node.supertype != null) { |
+ var superInfo = _getInfo(node.supertype.classNode); |
+ superDepth = max(superDepth, superInfo.depth); |
+ } |
+ if (node.mixedInType != null) { |
+ var mixedInfo = _getInfo(node.mixedInType.classNode); |
+ superDepth = max(superDepth, mixedInfo.depth); |
+ } |
+ for (var supertype in node.implementedTypes) { |
+ var implementedInfo = _getInfo(supertype.classNode); |
+ superDepth = max(superDepth, implementedInfo.depth); |
+ } |
+ info.depth = superDepth + 1; |
+ } |
+ return info; |
+ } |
+ |
+ List<_ClassInfo> _getRankedSuperclassList(_ClassInfo info) { |
+ if (info.rankedSuperclassList != null) { |
+ return info.rankedSuperclassList; |
+ } |
+ |
+ var heap = new _LubHeap()..add(info); |
+ var chain = <_ClassInfo>[]; |
+ info.rankedSuperclassList = chain; |
+ |
+ _ClassInfo lastInfo = null; |
+ while (heap.isNotEmpty) { |
+ var nextInfo = heap.remove(); |
+ if (identical(nextInfo, lastInfo)) continue; |
+ lastInfo = nextInfo; |
+ |
+ chain.add(nextInfo); |
+ |
+ void addToHeap(Supertype supertype) { |
+ var superInfo = _getInfo(supertype.classNode); |
+ heap.add(superInfo); |
+ } |
+ |
+ var classNode = nextInfo.node; |
+ if (classNode.supertype != null) addToHeap(classNode.supertype); |
+ if (classNode.mixedInType != null) addToHeap(classNode.mixedInType); |
+ classNode.implementedTypes.forEach(addToHeap); |
+ } |
+ return chain; |
} |
} |
/// Information about a [Class]. |
class _ClassInfo { |
+ /// The unique identifier of the [_ClassInfo]. |
+ final int id; |
+ |
+ /// The [Class] node described by this [_ClassInfo]. |
final Class node; |
/// The number of steps in the longest inheritance path from the class |
- /// to [Object], or -1 if the depth has not been computed yet. |
+ /// to [Object], or `-1` if the depth has not been computed yet. |
int depth = -1; |
- _ClassInfo(this.node); |
+ /// The list of superclasses sorted by depth (descending order) and |
+ /// unique identifiers (ascending order), or `null` if the lit has not |
+ /// been computed yet. |
+ List<_ClassInfo> rankedSuperclassList; |
+ |
+ _ClassInfo(this.id, this.node); |
+ |
+ @override |
+ String toString() => node.toString(); |
+} |
+ |
+/// Heap for use in computing least upper bounds. |
+/// |
+/// The heap is sorted such that classes that are deepest in the hierarchy |
+/// are removed first; in the case of ties, classes with lower unique |
+/// identifiers removed first. |
+class _LubHeap extends Heap<_ClassInfo> { |
+ @override |
+ bool sortsBefore(_ClassInfo a, _ClassInfo b) => sortsBeforeStatic(a, b); |
+ |
+ static bool sortsBeforeStatic(_ClassInfo a, _ClassInfo b) { |
+ if (a.depth > b.depth) return true; |
+ if (a.depth < b.depth) return false; |
+ return a.id < b.id; |
+ } |
} |