| 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
|
|
|