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

Unified Diff: pkg/kernel/lib/src/incremental_class_hierarchy.dart

Issue 2921083002: Implement getClassicLeastUpperBound() in IncrementalClassHierarchy. (Closed)
Patch Set: Created 3 years, 7 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 | « no previous file | pkg/kernel/test/class_hierarchy_test.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 2f29efc1d0114f4f96663b8d0d85af4dc2cecb8c..6655ac901bf844f132b0d7710c48c23ac69928e4 100644
--- a/pkg/kernel/lib/src/incremental_class_hierarchy.dart
+++ b/pkg/kernel/lib/src/incremental_class_hierarchy.dart
@@ -51,8 +51,97 @@ class IncrementalClassHierarchy implements ClassHierarchy {
@override
InterfaceType getClassicLeastUpperBound(
InterfaceType type1, InterfaceType type2) {
- // TODO(scheglov): implement getClassicLeastUpperBound
- throw new UnimplementedError();
+ // The algorithm is: first we compute a list of superclasses for both types,
+ // ordered from greatest to least depth, and ordered by topological sort
+ // index within each depth. Due to the sort order, we can find the
+ // intersection of these lists by a simple walk.
+ //
+ // Then, for each class in the intersection, determine the exact type that
+ // is implemented by type1 and type2. If the types match, that type is a
+ // candidate (it's a member of S_n). As soon as we find a candidate which
+ // is unique for its depth, we return it.
+ //
+ // As an optimization, if the class for I is a subtype of the class for J,
+ // then we know that the list of superclasses of J is a subset of the list
+ // of superclasses for I; therefore it is sufficient to compute just the
+ // list of superclasses for J. To avoid complicating the code below (which
+ // intersects the two lists), we set both lists equal to the list of
+ // superclasses for J. And vice versa with the role of I and J swapped.
+
+ // Compute the list of superclasses for both types, with the above
+ // optimization.
+ _ClassInfo info1 = _getInfo(type1.classNode);
+ _ClassInfo info2 = _getInfo(type2.classNode);
+ List<_ClassInfo> classes1;
+ List<_ClassInfo> classes2;
+ if (identical(info1, info2) || info1.isSubtypeOf(info2)) {
+ classes1 = classes2 = _getRankedSuperclassList(info2);
+ } else if (info2.isSubtypeOf(info1)) {
+ classes1 = classes2 = _getRankedSuperclassList(info1);
+ } else {
+ classes1 = _getRankedSuperclassList(info1);
+ classes2 = _getRankedSuperclassList(info2);
+ }
+
+ // Walk the lists finding their intersection, looking for a depth that has a
+ // single candidate.
+ int i1 = 0;
+ int i2 = 0;
+ InterfaceType candidate = null;
+ int currentDepth = -1;
+ int numCandidatesAtThisDepth = 0;
+ while (true) {
+ _ClassInfo next = classes1[i1];
+ _ClassInfo next2 = classes2[i2];
+ if (!identical(next, next2)) {
+ if (_LubHeap.sortsBeforeStatic(next, next2)) {
+ ++i1;
+ } else {
+ ++i2;
+ }
+ continue;
+ }
+ ++i2;
+ ++i1;
+ if (next.depth != currentDepth) {
+ if (numCandidatesAtThisDepth == 1) return candidate;
+ currentDepth = next.depth;
+ numCandidatesAtThisDepth = 0;
+ candidate = null;
+ } else if (numCandidatesAtThisDepth > 1) {
+ continue;
+ }
+
+ // For each class in the intersection, find the exact type that is
+ // implemented by type1 and type2. If they match, it's a candidate.
+ //
+ // Two additional optimizations:
+ //
+ // - If this class lacks type parameters, we know there is a match without
+ // needing to substitute.
+ //
+ // - If the depth is 0, we have reached Object, so we can return it
+ // immediately. Since all interface types are subtypes of Object, this
+ // ensures the loop terminates.
+ if (next.node.typeParameters.isEmpty) {
+ candidate = next.node.rawType;
+ if (currentDepth == 0) return candidate;
+ ++numCandidatesAtThisDepth;
+ } else {
+ var superType1 = identical(info1, next)
+ ? type1
+ : Substitution.fromInterfaceType(type1).substituteType(
+ info1.genericSuperTypes[next.node].asInterfaceType);
+ var superType2 = identical(info2, next)
+ ? type2
+ : Substitution.fromInterfaceType(type2).substituteType(
+ info2.genericSuperTypes[next.node].asInterfaceType);
+ if (superType1 == superType2) {
+ candidate = superType1;
+ ++numCandidatesAtThisDepth;
+ }
+ }
+ }
}
@override
« no previous file with comments | « no previous file | pkg/kernel/test/class_hierarchy_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698