Revert "Add ClassHierarchy to share code between J/KClosedWorld"
This reverts commit a8e930caf3ab089c867b5421d3941228733e2af1.
Compile time regression on some large apps.
TBR=johnniwinther@google.com
Change-Id: Ic1b736a5d50814ed8b8d24a9dc4a2d910e5f70df
Reviewed-on: https://dart-review.googlesource.com/62446
Reviewed-by: Stephen Adams <sra@google.com>
Commit-Queue: Stephen Adams <sra@google.com>
diff --git a/pkg/compiler/lib/src/frontend_strategy.dart b/pkg/compiler/lib/src/frontend_strategy.dart
index 45f1261..f6b8293 100644
--- a/pkg/compiler/lib/src/frontend_strategy.dart
+++ b/pkg/compiler/lib/src/frontend_strategy.dart
@@ -23,7 +23,7 @@
import 'library_loader.dart';
import 'native/enqueue.dart' show NativeResolutionEnqueuer;
import 'native/resolver.dart';
-import 'universe/class_hierarchy.dart';
+import 'universe/class_hierarchy_builder.dart';
import 'universe/world_builder.dart';
import 'universe/world_impact.dart';
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
index 7311eb2..644cfd2 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/flat_type_mask.dart
@@ -334,50 +334,23 @@
assert(TypeMask.assertIsNormalized(this, closedWorld));
assert(TypeMask.assertIsNormalized(other, closedWorld));
FlatTypeMask flatOther = other;
-
- ClassEntity otherBase = flatOther.base;
-
- bool includeNull = isNullable && flatOther.isNullable;
-
- TypeMask emptyOrNull() {
- return includeNull
- ? closedWorld.abstractValueDomain.nullType
- : closedWorld.abstractValueDomain.emptyType;
+ if (isEmptyOrNull) {
+ return flatOther.isNullable ? this : nonNullable();
+ } else if (flatOther.isEmptyOrNull) {
+ return isNullable ? flatOther : other.nonNullable();
+ } else if (base == flatOther.base) {
+ return intersectionSame(flatOther, closedWorld);
+ } else if (closedWorld.isSubclassOf(flatOther.base, base)) {
+ return intersectionStrictSubclass(flatOther, closedWorld);
+ } else if (closedWorld.isSubclassOf(base, flatOther.base)) {
+ return flatOther.intersectionStrictSubclass(this, closedWorld);
+ } else if (closedWorld.isSubtypeOf(flatOther.base, base)) {
+ return intersectionStrictSubtype(flatOther, closedWorld);
+ } else if (closedWorld.isSubtypeOf(base, flatOther.base)) {
+ return flatOther.intersectionStrictSubtype(this, closedWorld);
+ } else {
+ return intersectionDisjoint(flatOther, closedWorld);
}
-
- if (isEmptyOrNull || flatOther.isEmptyOrNull) {
- return emptyOrNull();
- }
-
- SubclassResult result = closedWorld.classHierarchy
- .commonSubclasses(base, _classQuery, otherBase, flatOther._classQuery);
-
- FlatTypeMask createSingle(ClassEntity cls) {
- switch (result.query) {
- case ClassQuery.EXACT:
- return includeNull
- ? new TypeMask.exact(cls, closedWorld)
- : new TypeMask.nonNullExact(cls, closedWorld);
- case ClassQuery.SUBCLASS:
- return includeNull
- ? new TypeMask.subclass(cls, closedWorld)
- : new TypeMask.nonNullSubclass(cls, closedWorld);
- case ClassQuery.SUBTYPE:
- return includeNull
- ? new TypeMask.subtype(cls, closedWorld)
- : new TypeMask.nonNullSubtype(cls, closedWorld);
- }
- throw new UnsupportedError("Unexpected ClassQuery: ${result.query}.");
- }
-
- List<FlatTypeMask> masks =
- result.classes.map<FlatTypeMask>(createSingle).toList();
- if (masks.isEmpty) return emptyOrNull();
- if (masks.length == 1) return masks.single;
- if (masks.length > UnionTypeMask.MAX_UNION_LENGTH) {
- return UnionTypeMask.flatten(masks, closedWorld);
- }
- return new UnionTypeMask._internal(masks);
}
bool isDisjoint(TypeMask other, JClosedWorld closedWorld) {
@@ -459,6 +432,54 @@
}
}
+ TypeMask intersectionStrictSubtype(
+ FlatTypeMask other, JClosedWorld closedWorld) {
+ assert(base != other.base);
+ assert(closedWorld.isSubtypeOf(other.base, base));
+ if (!isSubtype) return intersectionHelper(other, closedWorld);
+ // Only the other mask puts constraints on the intersection mask,
+ // so base the combined flags on the other mask. Only if both
+ // masks are nullable, will the result be nullable too.
+ // The result is guaranteed to be normalized, as the other type
+ // was normalized.
+ int combined = other.flags & ((flags & 1) | ~1);
+ if (other.flags == combined) {
+ return other;
+ } else {
+ return new FlatTypeMask.normalized(other.base, combined, closedWorld);
+ }
+ }
+
+ TypeMask intersectionDisjoint(FlatTypeMask other, JClosedWorld closedWorld) {
+ assert(base != other.base);
+ assert(!closedWorld.isSubtypeOf(base, other.base));
+ assert(!closedWorld.isSubtypeOf(other.base, base));
+ return intersectionHelper(other, closedWorld);
+ }
+
+ TypeMask intersectionHelper(FlatTypeMask other, JClosedWorld closedWorld) {
+ assert(base != other.base);
+ assert(!closedWorld.isSubclassOf(base, other.base));
+ assert(!closedWorld.isSubclassOf(other.base, base));
+ // If one of the masks are exact or if both of them are subclass
+ // masks, then the intersection is empty.
+ if (isExact || other.isExact) return intersectionEmpty(other);
+ if (isSubclass && other.isSubclass) return intersectionEmpty(other);
+ assert(isSubtype || other.isSubtype);
+ int kind = (isSubclass || other.isSubclass) ? SUBCLASS : SUBTYPE;
+ Iterable<ClassEntity> candidates = closedWorld.commonSubclasses(
+ base, _classQuery, other.base, other._classQuery);
+ if (candidates.isEmpty) return intersectionEmpty(other);
+ // Run through the list of candidates and compute the union. The
+ // result will only be nullable if both masks are nullable. We have
+ // to normalize here, as we generate types based on new base classes.
+ int combined = (kind << 1) | (flags & other.flags & 1);
+ Iterable<TypeMask> masks = candidates.map((ClassEntity cls) {
+ return new FlatTypeMask.normalized(cls, combined, closedWorld);
+ });
+ return UnionTypeMask.unionOf(masks, closedWorld);
+ }
+
TypeMask intersectionEmpty(FlatTypeMask other) {
return isNullable && other.isNullable
? new TypeMask.empty()
diff --git a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
index 23752a0..2b6ae66 100644
--- a/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
+++ b/pkg/compiler/lib/src/inferrer/typemasks/masks.dart
@@ -9,13 +9,12 @@
import '../../constants/values.dart' show ConstantValue, PrimitiveConstantValue;
import '../../elements/entities.dart';
import '../../types/abstract_value_domain.dart';
-import '../../universe/class_hierarchy.dart';
import '../../universe/selector.dart' show Selector;
import '../../universe/use.dart' show DynamicUse;
import '../../universe/world_builder.dart'
show UniverseSelectorConstraints, SelectorConstraintsStrategy;
import '../../util/util.dart';
-import '../../world.dart' show JClosedWorld;
+import '../../world.dart' show ClassQuery, JClosedWorld;
import '../type_graph_inferrer.dart' show TypeGraphInferrer;
import 'constants.dart';
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index 3b6fc65..8b424b6 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -38,7 +38,7 @@
import '../ssa/ssa.dart' show SsaFunctionCompiler;
import '../tracer.dart';
import '../universe/call_structure.dart' show CallStructure;
-import '../universe/class_hierarchy.dart'
+import '../universe/class_hierarchy_builder.dart'
show ClassHierarchyBuilder, ClassQueries;
import '../universe/selector.dart' show Selector;
import '../universe/use.dart' show StaticUse;
diff --git a/pkg/compiler/lib/src/js_backend/impact_transformer.dart b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
index b7a388a..a438262 100644
--- a/pkg/compiler/lib/src/js_backend/impact_transformer.dart
+++ b/pkg/compiler/lib/src/js_backend/impact_transformer.dart
@@ -4,7 +4,7 @@
library js_backend.backend.impact_transformer;
-import '../universe/class_hierarchy.dart' show ClassHierarchyBuilder;
+import '../universe/class_hierarchy_builder.dart' show ClassHierarchyBuilder;
import '../common.dart';
import '../common_elements.dart';
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 54863e5..a449b52 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -13,11 +13,10 @@
import '../js/js.dart' show js;
import '../js_emitter/js_emitter.dart' show Emitter;
import '../options.dart';
-import '../universe/class_hierarchy.dart';
import '../universe/feature.dart';
import '../universe/selector.dart';
import '../universe/world_builder.dart';
-import '../world.dart' show JClosedWorld, KClosedWorld;
+import '../world.dart' show ClassQuery, JClosedWorld, KClosedWorld;
import 'backend_usage.dart';
import 'namer.dart';
import 'native_data.dart';
@@ -1470,8 +1469,7 @@
classesNeedingTypeArguments.add(cls);
// TODO(ngeoffray): This should use subclasses, not subtypes.
- closedWorld.classHierarchy.forEachStrictSubtypeOf(cls,
- (ClassEntity sub) {
+ closedWorld.forEachStrictSubtypeOf(cls, (ClassEntity sub) {
potentiallyNeedTypeArguments(sub);
});
} else if (entity is FunctionEntity) {
@@ -1696,16 +1694,19 @@
impliedClass(runtimeTypeUse.argumentType);
// TODO(johnniwinther): Special case use of `this.runtimeType`.
- SubclassResult result = closedWorld.classHierarchy.commonSubclasses(
- receiverClass,
- ClassQuery.SUBTYPE,
- argumentClass,
- ClassQuery.SUBTYPE);
-
- for (ClassEntity cls in result.classes) {
- addClass(cls);
- if (neededOnAll) break;
+ if (closedWorld.isSubtypeOf(receiverClass, argumentClass)) {
+ addClass(receiverClass);
+ } else if (closedWorld.isSubtypeOf(argumentClass, receiverClass)) {
+ addClass(argumentClass);
}
+ if (neededOnAll) break;
+ // TODO(johnniwinther): Special case use of `this.runtimeType`.
+ // TODO(johnniwinther): Rename [commonSubclasses] to something like
+ // [strictCommonClasses] and support the non-strict case directly.
+ // Since we do a subclassesOf
+ classesDirectlyNeedingRuntimeType.addAll(
+ closedWorld.commonSubclasses(receiverClass, ClassQuery.SUBTYPE,
+ argumentClass, ClassQuery.SUBTYPE));
break;
case RuntimeTypeUseKind.unknown:
addClass(impliedClass(runtimeTypeUse.receiverType));
@@ -1716,17 +1717,15 @@
Set<ClassEntity> allClassesNeedingRuntimeType;
if (neededOnAll) {
neededOnFunctions = true;
- allClassesNeedingRuntimeType = closedWorld.classHierarchy
- .subclassesOf(commonElements.objectClass)
- .toSet();
+ allClassesNeedingRuntimeType =
+ closedWorld.subclassesOf(commonElements.objectClass).toSet();
} else {
allClassesNeedingRuntimeType = new Set<ClassEntity>();
// TODO(johnniwinther): Support this operation directly in
// [ClosedWorld] using the [ClassSet]s.
for (ClassEntity cls in classesDirectlyNeedingRuntimeType) {
if (!allClassesNeedingRuntimeType.contains(cls)) {
- allClassesNeedingRuntimeType
- .addAll(closedWorld.classHierarchy.subtypesOf(cls));
+ allClassesNeedingRuntimeType.addAll(closedWorld.subtypesOf(cls));
}
}
}
diff --git a/pkg/compiler/lib/src/js_model/js_strategy.dart b/pkg/compiler/lib/src/js_model/js_strategy.dart
index 1f4923a..6b68731 100644
--- a/pkg/compiler/lib/src/js_model/js_strategy.dart
+++ b/pkg/compiler/lib/src/js_model/js_strategy.dart
@@ -289,10 +289,10 @@
});
}
- closedWorld.classHierarchy
+ closedWorld
.getClassHierarchyNode(closedWorld.commonElements.objectClass)
.forEachSubclass((ClassEntity cls) {
- convertClassSet(closedWorld.classHierarchy.getClassSet(cls));
+ convertClassSet(closedWorld.getClassSet(cls));
}, ClassHierarchyNode.ALL);
Set<MemberEntity> liveInstanceMembers =
diff --git a/pkg/compiler/lib/src/kernel/element_map_impl.dart b/pkg/compiler/lib/src/kernel/element_map_impl.dart
index b3e5f49..2136ceb 100644
--- a/pkg/compiler/lib/src/kernel/element_map_impl.dart
+++ b/pkg/compiler/lib/src/kernel/element_map_impl.dart
@@ -43,7 +43,7 @@
import '../ordered_typeset.dart';
import '../ssa/kernel_impact.dart';
import '../ssa/type_builder.dart';
-import '../universe/class_hierarchy.dart';
+import '../universe/class_hierarchy_builder.dart';
import '../universe/class_set.dart';
import '../universe/selector.dart';
import '../universe/world_builder.dart';
@@ -2073,6 +2073,9 @@
final Map<ClassEntity, Set<ClassEntity>> typesImplementedBySubclasses;
+ final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes;
+ final Map<ClassEntity, ClassSet> _classSets;
+
// TODO(johnniwinther): Can this be derived from [ClassSet]s?
final Set<ClassEntity> _implementedClasses;
@@ -2086,8 +2089,6 @@
final Iterable<MemberEntity> processedMembers;
- final ClassHierarchy classHierarchy;
-
KClosedWorldImpl(this.elementMap,
{CompilerOptions options,
this.elementEnvironment,
@@ -2110,8 +2111,8 @@
Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes,
Map<ClassEntity, ClassSet> classSets})
: _implementedClasses = implementedClasses,
- classHierarchy = new ClassHierarchyImpl(
- commonElements, classHierarchyNodes, classSets) {
+ _classHierarchyNodes = classHierarchyNodes,
+ _classSets = classSets {
computeRtiNeed(resolutionWorldBuilder, rtiNeedBuilder, options);
}
@@ -2119,6 +2120,152 @@
bool isImplemented(ClassEntity cls) {
return _implementedClasses.contains(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 [JClosedWorld].
+ ClassHierarchyNode getClassHierarchyNode(ClassEntity cls) {
+ return _classHierarchyNodes[cls];
+ }
+
+ /// 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 [JClosedWorld].
+ ClassSet getClassSet(ClassEntity cls) {
+ return _classSets[cls];
+ }
+
+ // TODO(johnniwinther): Share the methods based on [ClassSet] and
+ // [ClassHierarchyNode] between KClosedWorld and JClosedWorld.
+ /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
+ /// instance of [y].
+ bool isSubtypeOf(ClassEntity x, ClassEntity y) {
+ ClassSet classSet = _classSets[y];
+ assert(classSet != null,
+ failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${_classSets}"));
+ ClassHierarchyNode classHierarchyNode = _classHierarchyNodes[x];
+ assert(classHierarchyNode != null,
+ failedAt(x, "No ClassHierarchyNode for $x"));
+ return classSet.hasSubtype(classHierarchyNode);
+ }
+
+ /// Returns an iterable over the directly instantiated that implement [cls]
+ /// possibly including [cls] itself, if it is live.
+ Iterable<ClassEntity> subtypesOf(ClassEntity cls) {
+ ClassSet classSet = _classSets[cls];
+ if (classSet == null) {
+ return const <ClassEntity>[];
+ } else {
+ return classSet
+ .subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
+ }
+ }
+
+ /// Returns an iterable over the directly instantiated classes that extend
+ /// [cls] possibly including [cls] itself, if it is live.
+ Iterable<ClassEntity> subclassesOf(ClassEntity cls) {
+ ClassHierarchyNode hierarchy = _classHierarchyNodes[cls];
+ if (hierarchy == null) return const <ClassEntity>[];
+ return hierarchy
+ .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
+ }
+
+ /// Returns an iterable over the directly instantiated that implement [cls]
+ /// _not_ including [cls].
+ Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls) {
+ ClassSet classSet = _classSets[cls];
+ if (classSet == null) {
+ return const <ClassEntity>[];
+ } else {
+ return classSet.subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+ strict: true);
+ }
+ }
+
+ Iterable<ClassEntity> getInterfaces(ClassEntity cls) {
+ return elementMap._getInterfaces(cls).map((t) => t.element);
+ }
+
+ ClassEntity getSuperClass(ClassEntity cls) {
+ return elementMap._getSuperType(cls)?.element;
+ }
+
+ /// Returns an iterable over the directly instantiated classes that extend
+ /// [cls] _not_ including [cls] itself.
+ Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) {
+ ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
+ if (subclasses == null) return const <ClassEntity>[];
+ return subclasses.subclassesByMask(
+ ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+ strict: true);
+ }
+
+ Set<ClassEntity> _commonContainedClasses(ClassEntity cls1, ClassQuery query1,
+ ClassEntity cls2, ClassQuery query2) {
+ Iterable<ClassEntity> xSubset = _containedSubset(cls1, query1);
+ if (xSubset == null) return null;
+ Iterable<ClassEntity> ySubset = _containedSubset(cls2, query2);
+ if (ySubset == null) return null;
+ return xSubset.toSet().intersection(ySubset.toSet());
+ }
+
+ Iterable<ClassEntity> _containedSubset(ClassEntity cls, ClassQuery query) {
+ switch (query) {
+ case ClassQuery.EXACT:
+ return null;
+ case ClassQuery.SUBCLASS:
+ return strictSubclassesOf(cls);
+ case ClassQuery.SUBTYPE:
+ return strictSubtypesOf(cls);
+ }
+ throw new ArgumentError('Unexpected query: $query.');
+ }
+
+ Iterable<ClassEntity> commonSubclasses(ClassEntity cls1, ClassQuery query1,
+ ClassEntity cls2, ClassQuery query2) {
+ // TODO(johnniwinther): Use [ClassSet] to compute this.
+ // Compute the set of classes that are contained in both class subsets.
+ Set<ClassEntity> common =
+ _commonContainedClasses(cls1, query1, cls2, query2);
+ if (common == null || common.isEmpty) return const <ClassEntity>[];
+ // Narrow down the candidates by only looking at common classes
+ // that do not have a superclass or supertype that will be a
+ // better candidate.
+ return common.where((ClassEntity each) {
+ bool containsSuperclass = common.contains(getSuperClass(each));
+ // If the superclass is also a candidate, then we don't want to
+ // deal with this class. If we're only looking for a subclass we
+ // know we don't have to look at the list of interfaces because
+ // they can never be in the common set.
+ if (containsSuperclass ||
+ query1 == ClassQuery.SUBCLASS ||
+ query2 == ClassQuery.SUBCLASS) {
+ return !containsSuperclass;
+ }
+ // Run through the direct supertypes of the class. If the common
+ // set contains the direct supertype of the class, we ignore the
+ // the class because the supertype is a better candidate.
+
+ for (ClassEntity interface in getInterfaces(each)) {
+ if (common.contains(interface)) return false;
+ }
+ return true;
+ });
+ }
+
+ /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubtypeOf(
+ ClassEntity cls, IterationStep f(ClassEntity cls)) {
+ ClassSet classSet = _classSets[cls];
+ if (classSet == null) return;
+ classSet.forEachSubtype(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
+ strict: true);
+ }
}
// Interface for testing equivalence of Kernel-based entities.
diff --git a/pkg/compiler/lib/src/kernel/kernel_strategy.dart b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
index 9e91d03..19e2aa3 100644
--- a/pkg/compiler/lib/src/kernel/kernel_strategy.dart
+++ b/pkg/compiler/lib/src/kernel/kernel_strategy.dart
@@ -31,7 +31,7 @@
import '../native/enqueue.dart' show NativeResolutionEnqueuer;
import '../native/resolver.dart';
import '../options.dart';
-import '../universe/class_hierarchy.dart';
+import '../universe/class_hierarchy_builder.dart';
import '../universe/world_builder.dart';
import '../universe/world_impact.dart';
import 'deferred_load.dart';
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy.dart b/pkg/compiler/lib/src/universe/class_hierarchy.dart
deleted file mode 100644
index f19320a..0000000
--- a/pkg/compiler/lib/src/universe/class_hierarchy.dart
+++ /dev/null
@@ -1,543 +0,0 @@
-// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import '../common.dart';
-import '../common_elements.dart';
-import '../elements/entities.dart';
-import '../elements/types.dart' show InterfaceType;
-import 'class_set.dart';
-
-// TODO(johnniwinther): Move more methods from `JClosedWorld` to
-// `ClassHierarchy`.
-abstract class ClassHierarchy {
- /// 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 [JClosedWorld].
- ClassHierarchyNode getClassHierarchyNode(ClassEntity cls);
-
- /// 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 [JClosedWorld].
- ClassSet getClassSet(ClassEntity cls);
-
- /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
- /// instance of [y].
- bool isSubtypeOf(ClassEntity x, ClassEntity y);
-
- /// Returns a [SubclassResult] for the subclasses that are contained in
- /// the subclass/subtype sets of both [cls1] and [cls2].
- ///
- /// Classes that are implied by included superclasses/supertypes are not
- /// returned.
- ///
- /// For instance for this hierarchy
- ///
- /// class A {}
- /// class B {}
- /// class C implements A, B {}
- /// class D extends C {}
- ///
- /// the query
- ///
- /// commonSubclasses(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE)
- ///
- /// return the set {C} because [D] is implied by [C].
- SubclassResult commonSubclasses(
- ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2);
-
- /// Returns an iterable over the directly instantiated that implement [cls]
- /// possibly including [cls] itself, if it is live.
- Iterable<ClassEntity> subtypesOf(ClassEntity cls);
-
- /// Returns an iterable over the live classes that extend [cls] including
- /// [cls] itself.
- Iterable<ClassEntity> subclassesOf(ClassEntity cls);
-
- /// Applies [f] to each live class that implements [cls] _not_ including [cls]
- /// itself.
- void forEachStrictSubtypeOf(
- ClassEntity cls, IterationStep f(ClassEntity cls));
-}
-
-class ClassHierarchyImpl implements ClassHierarchy {
- final CommonElements _commonElements;
- final Map<ClassEntity, ClassHierarchyNode> _classHierarchyNodes;
- final Map<ClassEntity, ClassSet> _classSets;
-
- ClassHierarchyImpl(
- this._commonElements, this._classHierarchyNodes, this._classSets);
-
- /// 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 [JClosedWorld].
- ClassHierarchyNode getClassHierarchyNode(ClassEntity cls) {
- return _classHierarchyNodes[cls];
- }
-
- /// 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 [JClosedWorld].
- ClassSet getClassSet(ClassEntity cls) {
- return _classSets[cls];
- }
-
- /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
- /// instance of [y].
- bool isSubtypeOf(ClassEntity x, ClassEntity y) {
- ClassSet classSet = _classSets[y];
- assert(classSet != null,
- failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${_classSets}"));
- ClassHierarchyNode classHierarchyNode = _classHierarchyNodes[x];
- assert(classHierarchyNode != null,
- failedAt(x, "No ClassHierarchyNode for $x"));
- return classSet.hasSubtype(classHierarchyNode);
- }
-
- /// Return `true` if [x] is a (non-strict) subclass of [y].
- bool isSubclassOf(ClassEntity x, ClassEntity y) {
- return _classHierarchyNodes[y].hasSubclass(_classHierarchyNodes[x]);
- }
-
- /// Returns an iterable over the directly instantiated that implement [cls]
- /// possibly including [cls] itself, if it is live.
- Iterable<ClassEntity> subtypesOf(ClassEntity cls) {
- ClassSet classSet = _classSets[cls];
- if (classSet == null) {
- return const <ClassEntity>[];
- } else {
- return classSet
- .subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
- }
- }
-
- /// Returns an iterable over the directly instantiated classes that extend
- /// [cls] possibly including [cls] itself, if it is live.
- Iterable<ClassEntity> subclassesOf(ClassEntity cls) {
- ClassHierarchyNode hierarchy = _classHierarchyNodes[cls];
- if (hierarchy == null) return const <ClassEntity>[];
- return hierarchy
- .subclassesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED);
- }
-
- /// Returns an iterable over the directly instantiated that implement [cls]
- /// _not_ including [cls].
- Iterable<ClassEntity> strictSubtypesOf(ClassEntity cls) {
- ClassSet classSet = _classSets[cls];
- if (classSet == null) {
- return const <ClassEntity>[];
- } else {
- return classSet.subtypesByMask(ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
- strict: true);
- }
- }
-
- /// Returns an iterable over the directly instantiated classes that extend
- /// [cls] _not_ including [cls] itself.
- Iterable<ClassEntity> strictSubclassesOf(ClassEntity cls) {
- ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
- if (subclasses == null) return const <ClassEntity>[];
- return subclasses.subclassesByMask(
- ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
- strict: true);
- }
-
- /// Applies [f] to each live class that extend [cls] _not_ including [cls]
- /// itself.
- void forEachStrictSubclassOf(
- ClassEntity cls, IterationStep f(ClassEntity cls)) {
- ClassHierarchyNode subclasses = _classHierarchyNodes[cls];
- if (subclasses == null) return;
- subclasses.forEachSubclass(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
- strict: true);
- }
-
- /// Applies [f] to each live class that implements [cls] _not_ including [cls]
- /// itself.
- void forEachStrictSubtypeOf(
- ClassEntity cls, IterationStep f(ClassEntity cls)) {
- ClassSet classSet = _classSets[cls];
- if (classSet == null) return;
- classSet.forEachSubtype(f, ClassHierarchyNode.EXPLICITLY_INSTANTIATED,
- strict: true);
- }
-
- SubclassResult commonSubclasses(ClassEntity cls1, ClassQuery query1,
- ClassEntity cls2, ClassQuery query2) {
- if (query1 == ClassQuery.EXACT && query2 == ClassQuery.EXACT) {
- // Exact classes [cls1] and [cls2] must be identical to have any classes
- // in common.
- if (cls1 != cls2) {
- return const SubclassResult.empty();
- }
- return new SubclassResult.exact(cls1);
- } else if (query1 == ClassQuery.EXACT) {
- if (query2 == ClassQuery.SUBCLASS) {
- // Exact [cls1] must be a subclass of [cls2] to have any classes in
- // common.
- if (isSubclassOf(cls1, cls2)) {
- return new SubclassResult.exact(cls1);
- }
- } else if (query2 == ClassQuery.SUBTYPE) {
- // Exact [cls1] must be a subtype of [cls2] to have any classes in
- // common.
- if (isSubtypeOf(cls1, cls2)) {
- return new SubclassResult.exact(cls1);
- }
- }
- return const SubclassResult.empty();
- } else if (query2 == ClassQuery.EXACT) {
- if (query1 == ClassQuery.SUBCLASS) {
- // Exact [cls2] must be a subclass of [cls1] to have any classes in
- // common.
- if (isSubclassOf(cls2, cls1)) {
- return new SubclassResult.exact(cls2);
- }
- } else if (query1 == ClassQuery.SUBTYPE) {
- // Exact [cls2] must be a subtype of [cls1] to have any classes in
- // common.
- if (isSubtypeOf(cls2, cls1)) {
- return new SubclassResult.exact(cls2);
- }
- }
- return const SubclassResult.empty();
- } else if (query1 == ClassQuery.SUBCLASS && query2 == ClassQuery.SUBCLASS) {
- // [cls1] must be a subclass of [cls2] or vice versa to have any classes
- // in common.
- if (cls1 == cls2 || isSubclassOf(cls1, cls2)) {
- // The subclasses of [cls1] are contained within the subclasses of
- // [cls2].
- return new SubclassResult.subclass(cls1);
- } else if (isSubclassOf(cls2, cls1)) {
- // The subclasses of [cls2] are contained within the subclasses of
- // [cls1].
- return new SubclassResult.subclass(cls2);
- }
- return const SubclassResult.empty();
- } else if (query1 == ClassQuery.SUBCLASS) {
- if (isSubtypeOf(cls1, cls2)) {
- // The subclasses of [cls1] are all subtypes of [cls2].
- return new SubclassResult.subclass(cls1);
- }
- if (cls1 == _commonElements.objectClass) {
- // Since [cls1] is `Object` all subtypes of [cls2] are contained within
- // the subclasses of [cls1].
- return new SubclassResult.subtype(cls2);
- }
- // Find all the root subclasses of [cls1] of that implement [cls2].
- //
- // For this hierarchy:
- //
- // class I {}
- // class A {}
- // class B extends A implements I {}
- // class C extends B {}
- // class D extends A implements I {}
- //
- // the common subclasses of "subclass of A" and "subtype of I" returns
- // "subclasses of {B, D}". The inclusion of class `C` is implied because
- // it is a subclass of `B`.
- List<ClassEntity> classes = <ClassEntity>[];
- forEachStrictSubclassOf(cls1, (ClassEntity subclass) {
- if (isSubtypeOf(subclass, cls2)) {
- classes.add(subclass);
- // Skip subclasses of [subclass]; they all implement [cls2] by
- // inheritance and are included in the subclasses of [subclass].
- return IterationStep.SKIP_SUBCLASSES;
- }
- return IterationStep.CONTINUE;
- });
- return new SubclassResult.subclasses(classes);
- } else if (query2 == ClassQuery.SUBCLASS) {
- if (isSubtypeOf(cls2, cls1)) {
- // The subclasses of [cls2] are all subtypes of [cls1].
- return new SubclassResult.subclass(cls2);
- }
- if (cls2 == _commonElements.objectClass) {
- // Since [cls2] is `Object` all subtypes of [cls1] are contained within
- // the subclasses of [cls2].
- return new SubclassResult.subtype(cls1);
- }
- // Find all the root subclasses of [cls2] of that implement [cls1].
- List<ClassEntity> classes = <ClassEntity>[];
- forEachStrictSubclassOf(cls2, (ClassEntity subclass) {
- if (isSubtypeOf(subclass, cls1)) {
- classes.add(subclass);
- // Skip subclasses of [subclass]; they all implement [cls1] by
- // inheritance and are included in the subclasses of [subclass].
- return IterationStep.SKIP_SUBCLASSES;
- }
- return IterationStep.CONTINUE;
- });
- return new SubclassResult.subclasses(classes);
- } else {
- if (cls1 == cls2 || isSubtypeOf(cls1, cls2)) {
- // The subtypes of [cls1] are contained within the subtypes of [cls2].
- return new SubclassResult.subtype(cls1);
- } else if (isSubtypeOf(cls2, cls1)) {
- // The subtypes of [cls2] are contained within the subtypes of [cls1].
- return new SubclassResult.subtype(cls2);
- }
- // Find all the root subclasses of [cls1] of that implement [cls2].
- //
- // For this hierarchy:
- //
- // class I {}
- // class A {}
- // class B extends A implements I {}
- // class C extends B {}
- // class D extends A implements I {}
- // class E implements B {}
- // class F extends E {}
- //
- // the common subclasses of "subtype of A" and "subtype of I" returns
- // "subclasses of {B, D, E}". The inclusion of classes `C` and `F` is
- // implied because they are subclasses of `B` and `E`, respectively.
- List<ClassEntity> classes = <ClassEntity>[];
- forEachStrictSubtypeOf(cls1, (ClassEntity subclass) {
- if (isSubtypeOf(subclass, cls2)) {
- classes.add(subclass);
- // Skip subclasses of [subclass]; they all implement [cls2] by
- // inheritance and are included in the subclasses of [subclass].
- return IterationStep.SKIP_SUBCLASSES;
- }
- return IterationStep.CONTINUE;
- });
- return new SubclassResult.subclasses(classes);
- }
- }
-}
-
-class ClassHierarchyBuilder {
- // We keep track of subtype and subclass relationships in four
- // distinct sets to make class hierarchy analysis faster.
- final Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes =
- <ClassEntity, ClassHierarchyNode>{};
- final Map<ClassEntity, ClassSet> classSets = <ClassEntity, ClassSet>{};
- final Map<ClassEntity, Set<ClassEntity>> mixinUses =
- new Map<ClassEntity, Set<ClassEntity>>();
-
- final CommonElements _commonElements;
- final ClassQueries _classQueries;
-
- ClassHierarchyBuilder(this._commonElements, this._classQueries);
-
- void registerClass(ClassEntity cls) {
- _ensureClassSet(_classQueries.getDeclaration(cls));
- }
-
- ClassHierarchyNode _ensureClassHierarchyNode(ClassEntity cls) {
- assert(_classQueries.checkClass(cls));
- return classHierarchyNodes.putIfAbsent(cls, () {
- ClassHierarchyNode parentNode;
- ClassEntity superclass = _classQueries.getSuperClass(cls);
- if (superclass != null) {
- parentNode = _ensureClassHierarchyNode(superclass);
- }
- return new ClassHierarchyNode(
- parentNode, cls, _classQueries.getHierarchyDepth(cls));
- });
- }
-
- ClassSet _ensureClassSet(ClassEntity cls) {
- assert(_classQueries.checkClass(cls));
- return classSets.putIfAbsent(cls, () {
- ClassHierarchyNode node = _ensureClassHierarchyNode(cls);
- ClassSet classSet = new ClassSet(node);
-
- for (InterfaceType type in _classQueries.getSupertypes(cls)) {
- // TODO(johnniwinther): Optimization: Avoid adding [cls] to
- // superclasses.
- ClassSet subtypeSet = _ensureClassSet(type.element);
- subtypeSet.addSubtype(node);
- }
-
- ClassEntity appliedMixin = _classQueries.getAppliedMixin(cls);
- while (appliedMixin != null) {
- // TODO(johnniwinther): Use the data stored in [ClassSet].
- registerMixinUse(cls, appliedMixin);
- ClassSet mixinSet = _ensureClassSet(appliedMixin);
- mixinSet.addMixinApplication(node);
-
- // In case of
- //
- // class A {}
- // class B = Object with A;
- // class C = Object with B;
- //
- // we need to register that C not only mixes in B but also A.
- appliedMixin = _classQueries.getAppliedMixin(appliedMixin);
- }
- return classSet;
- });
- }
-
- void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) {
- // Ensure that classes implicitly implementing `Function` are in its
- // subtype set.
- ClassEntity cls = node.cls;
- if (cls != _commonElements.functionClass &&
- _classQueries.implementsFunction(cls)) {
- ClassSet subtypeSet = _ensureClassSet(_commonElements.functionClass);
- subtypeSet.addSubtype(node);
- }
- if (!node.isInstantiated && node.parentNode != null) {
- _updateSuperClassHierarchyNodeForClass(node.parentNode);
- }
- }
-
- void updateClassHierarchyNodeForClass(ClassEntity cls,
- {bool directlyInstantiated: false, bool abstractlyInstantiated: false}) {
- ClassHierarchyNode node = _ensureClassSet(cls).node;
- _updateSuperClassHierarchyNodeForClass(node);
- if (directlyInstantiated) {
- node.isDirectlyInstantiated = true;
- }
- if (abstractlyInstantiated) {
- node.isAbstractlyInstantiated = true;
- }
- }
-
- void registerMixinUse(ClassEntity mixinApplication, ClassEntity mixin) {
- // TODO(johnniwinther): Add map restricted to live classes.
- // We don't support patch classes as mixin.
- Set<ClassEntity> users =
- mixinUses.putIfAbsent(mixin, () => new Set<ClassEntity>());
- users.add(mixinApplication);
- }
-
- bool _isSubtypeOf(ClassEntity x, ClassEntity y) {
- assert(
- classSets.containsKey(x), "ClassSet for $x has not been computed yet.");
- ClassSet classSet = classSets[y];
- assert(classSet != null,
- failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${classSets}"));
- ClassHierarchyNode classHierarchyNode = classHierarchyNodes[x];
- assert(classHierarchyNode != null,
- failedAt(x, "No ClassHierarchyNode for $x"));
- return classSet.hasSubtype(classHierarchyNode);
- }
-
- bool isInheritedInSubtypeOf(ClassEntity x, ClassEntity y) {
- ClassSet classSet = classSets[x];
- assert(classSet != null,
- failedAt(x, "No ClassSet for $x (${x.runtimeType}): ${classSets}"));
-
- if (_isSubtypeOf(x, y)) {
- // [x] implements [y] itself, possible through supertypes.
- return true;
- }
-
- /// Returns `true` if any live subclass of [node] implements [y].
- bool subclassImplements(ClassHierarchyNode node, {bool strict}) {
- return node.anySubclass((ClassEntity z) => _isSubtypeOf(z, y),
- ClassHierarchyNode.INSTANTIATED,
- strict: strict);
- }
-
- if (subclassImplements(classSet.node, strict: true)) {
- // A subclass of [x] implements [y].
- return true;
- }
-
- for (ClassHierarchyNode mixinApplication
- in classSet.mixinApplicationNodes) {
- if (subclassImplements(mixinApplication, strict: false)) {
- // A subclass of [mixinApplication] implements [y].
- return true;
- }
- }
- return false;
- }
-}
-
-abstract class ClassQueries {
- bool checkClass(covariant ClassEntity cls);
- bool validateClass(covariant ClassEntity cls);
-
- /// Returns the declaration of [cls].
- ClassEntity getDeclaration(covariant ClassEntity cls);
-
- /// Returns the class mixed into [cls] if any.
- // TODO(johnniwinther): Replace this by a `getAppliedMixins` function that
- // return transitively mixed in classes like in:
- // class A {}
- // class B = Object with A;
- // class C = Object with B;
- ClassEntity getAppliedMixin(covariant ClassEntity cls);
-
- /// Returns the hierarchy depth of [cls].
- int getHierarchyDepth(covariant ClassEntity cls);
-
- /// Returns `true` if [cls] implements `Function` either explicitly or through
- /// a `call` method.
- bool implementsFunction(covariant ClassEntity cls);
-
- /// Returns the superclass of [cls] if any.
- ClassEntity getSuperClass(covariant ClassEntity cls);
-
- /// Returns all supertypes of [cls].
- Iterable<InterfaceType> getSupertypes(covariant ClassEntity cls);
-}
-
-/// Enum values defining subset of classes included in queries.
-enum ClassQuery {
- /// Only the class itself is included.
- EXACT,
-
- /// The class and all subclasses (transitively) are included.
- SUBCLASS,
-
- /// The class and all classes that implement or subclass it (transitively)
- /// are included.
- SUBTYPE,
-}
-
-/// Result computed in [ClassHierarchy.commonSubclasses].
-class SubclassResult {
- /// The classes in the result set. The classes are always disjoint wrt. the
- /// interpretation of [query].
- final List<ClassEntity> classes;
-
- /// How [classes] should be interpreted: If `ClassQuery.EXACT`, only the
- /// classes in [classes] are on the result set. If `ClassQuery.SUBCLASS`,
- /// non-strict subclasses of the classes in [classes] are in the result set.
- /// If `ClassQuery.SUBTYPE`, non-strict subtypes of the classes in [classes]
- /// are in the result set.
- final ClassQuery query;
-
- /// Creates the empty result set.
- const SubclassResult.empty()
- : query = ClassQuery.EXACT,
- classes = const <ClassEntity>[];
-
- /// Creates the single set of [cls].
- SubclassResult.exact(ClassEntity cls)
- : query = ClassQuery.EXACT,
- classes = <ClassEntity>[cls];
-
- /// Creates the set of subclasses of [cls].
- SubclassResult.subclass(ClassEntity cls)
- : query = ClassQuery.SUBCLASS,
- classes = <ClassEntity>[cls];
-
- /// Creates the set of subtypes of [cls].
- SubclassResult.subtype(ClassEntity cls)
- : query = ClassQuery.SUBTYPE,
- classes = <ClassEntity>[cls];
-
- /// Creates the set of classes that are subclasses of a class in [classes].
- SubclassResult.subclasses(this.classes) : query = ClassQuery.SUBCLASS;
-
- SubclassResult.internal(this.query, this.classes);
-
- String toString() => 'SubclassResult($query,$classes)';
-}
diff --git a/pkg/compiler/lib/src/universe/class_hierarchy_builder.dart b/pkg/compiler/lib/src/universe/class_hierarchy_builder.dart
new file mode 100644
index 0000000..337975f
--- /dev/null
+++ b/pkg/compiler/lib/src/universe/class_hierarchy_builder.dart
@@ -0,0 +1,181 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../common.dart';
+import '../common_elements.dart';
+import '../elements/entities.dart';
+import '../elements/types.dart' show InterfaceType;
+import 'class_set.dart';
+
+class ClassHierarchyBuilder {
+ // We keep track of subtype and subclass relationships in four
+ // distinct sets to make class hierarchy analysis faster.
+ final Map<ClassEntity, ClassHierarchyNode> classHierarchyNodes =
+ <ClassEntity, ClassHierarchyNode>{};
+ final Map<ClassEntity, ClassSet> classSets = <ClassEntity, ClassSet>{};
+ final Map<ClassEntity, Set<ClassEntity>> mixinUses =
+ new Map<ClassEntity, Set<ClassEntity>>();
+
+ final CommonElements _commonElements;
+ final ClassQueries _classQueries;
+
+ ClassHierarchyBuilder(this._commonElements, this._classQueries);
+
+ void registerClass(ClassEntity cls) {
+ _ensureClassSet(_classQueries.getDeclaration(cls));
+ }
+
+ ClassHierarchyNode _ensureClassHierarchyNode(ClassEntity cls) {
+ assert(_classQueries.checkClass(cls));
+ return classHierarchyNodes.putIfAbsent(cls, () {
+ ClassHierarchyNode parentNode;
+ ClassEntity superclass = _classQueries.getSuperClass(cls);
+ if (superclass != null) {
+ parentNode = _ensureClassHierarchyNode(superclass);
+ }
+ return new ClassHierarchyNode(
+ parentNode, cls, _classQueries.getHierarchyDepth(cls));
+ });
+ }
+
+ ClassSet _ensureClassSet(ClassEntity cls) {
+ assert(_classQueries.checkClass(cls));
+ return classSets.putIfAbsent(cls, () {
+ ClassHierarchyNode node = _ensureClassHierarchyNode(cls);
+ ClassSet classSet = new ClassSet(node);
+
+ for (InterfaceType type in _classQueries.getSupertypes(cls)) {
+ // TODO(johnniwinther): Optimization: Avoid adding [cls] to
+ // superclasses.
+ ClassSet subtypeSet = _ensureClassSet(type.element);
+ subtypeSet.addSubtype(node);
+ }
+
+ ClassEntity appliedMixin = _classQueries.getAppliedMixin(cls);
+ while (appliedMixin != null) {
+ // TODO(johnniwinther): Use the data stored in [ClassSet].
+ registerMixinUse(cls, appliedMixin);
+ ClassSet mixinSet = _ensureClassSet(appliedMixin);
+ mixinSet.addMixinApplication(node);
+
+ // In case of
+ //
+ // class A {}
+ // class B = Object with A;
+ // class C = Object with B;
+ //
+ // we need to register that C not only mixes in B but also A.
+ appliedMixin = _classQueries.getAppliedMixin(appliedMixin);
+ }
+ return classSet;
+ });
+ }
+
+ void _updateSuperClassHierarchyNodeForClass(ClassHierarchyNode node) {
+ // Ensure that classes implicitly implementing `Function` are in its
+ // subtype set.
+ ClassEntity cls = node.cls;
+ if (cls != _commonElements.functionClass &&
+ _classQueries.implementsFunction(cls)) {
+ ClassSet subtypeSet = _ensureClassSet(_commonElements.functionClass);
+ subtypeSet.addSubtype(node);
+ }
+ if (!node.isInstantiated && node.parentNode != null) {
+ _updateSuperClassHierarchyNodeForClass(node.parentNode);
+ }
+ }
+
+ void updateClassHierarchyNodeForClass(ClassEntity cls,
+ {bool directlyInstantiated: false, bool abstractlyInstantiated: false}) {
+ ClassHierarchyNode node = _ensureClassSet(cls).node;
+ _updateSuperClassHierarchyNodeForClass(node);
+ if (directlyInstantiated) {
+ node.isDirectlyInstantiated = true;
+ }
+ if (abstractlyInstantiated) {
+ node.isAbstractlyInstantiated = true;
+ }
+ }
+
+ void registerMixinUse(ClassEntity mixinApplication, ClassEntity mixin) {
+ // TODO(johnniwinther): Add map restricted to live classes.
+ // We don't support patch classes as mixin.
+ Set<ClassEntity> users =
+ mixinUses.putIfAbsent(mixin, () => new Set<ClassEntity>());
+ users.add(mixinApplication);
+ }
+
+ bool _isSubtypeOf(ClassEntity x, ClassEntity y) {
+ assert(
+ classSets.containsKey(x), "ClassSet for $x has not been computed yet.");
+ ClassSet classSet = classSets[y];
+ assert(classSet != null,
+ failedAt(y, "No ClassSet for $y (${y.runtimeType}): ${classSets}"));
+ ClassHierarchyNode classHierarchyNode = classHierarchyNodes[x];
+ assert(classHierarchyNode != null,
+ failedAt(x, "No ClassHierarchyNode for $x"));
+ return classSet.hasSubtype(classHierarchyNode);
+ }
+
+ bool isInheritedInSubtypeOf(ClassEntity x, ClassEntity y) {
+ ClassSet classSet = classSets[x];
+ assert(classSet != null,
+ failedAt(x, "No ClassSet for $x (${x.runtimeType}): ${classSets}"));
+
+ if (_isSubtypeOf(x, y)) {
+ // [x] implements [y] itself, possible through supertypes.
+ return true;
+ }
+
+ /// Returns `true` if any live subclass of [node] implements [y].
+ bool subclassImplements(ClassHierarchyNode node, {bool strict}) {
+ return node.anySubclass((ClassEntity z) => _isSubtypeOf(z, y),
+ ClassHierarchyNode.INSTANTIATED,
+ strict: strict);
+ }
+
+ if (subclassImplements(classSet.node, strict: true)) {
+ // A subclass of [x] implements [y].
+ return true;
+ }
+
+ for (ClassHierarchyNode mixinApplication
+ in classSet.mixinApplicationNodes) {
+ if (subclassImplements(mixinApplication, strict: false)) {
+ // A subclass of [mixinApplication] implements [y].
+ return true;
+ }
+ }
+ return false;
+ }
+}
+
+abstract class ClassQueries {
+ bool checkClass(covariant ClassEntity cls);
+ bool validateClass(covariant ClassEntity cls);
+
+ /// Returns the declaration of [cls].
+ ClassEntity getDeclaration(covariant ClassEntity cls);
+
+ /// Returns the class mixed into [cls] if any.
+ // TODO(johnniwinther): Replace this by a `getAppliedMixins` function that
+ // return transitively mixed in classes like in:
+ // class A {}
+ // class B = Object with A;
+ // class C = Object with B;
+ ClassEntity getAppliedMixin(covariant ClassEntity cls);
+
+ /// Returns the hierarchy depth of [cls].
+ int getHierarchyDepth(covariant ClassEntity cls);
+
+ /// Returns `true` if [cls] implements `Function` either explicitly or through
+ /// a `call` method.
+ bool implementsFunction(covariant ClassEntity cls);
+
+ /// Returns the superclass of [cls] if any.
+ ClassEntity getSuperClass(covariant ClassEntity cls);
+
+ /// Returns all supertypes of [cls].
+ Iterable<InterfaceType> getSupertypes(covariant ClassEntity cls);
+}
diff --git a/pkg/compiler/lib/src/universe/world_builder.dart b/pkg/compiler/lib/src/universe/world_builder.dart
index 2417fd3..c1bf88d 100644
--- a/pkg/compiler/lib/src/universe/world_builder.dart
+++ b/pkg/compiler/lib/src/universe/world_builder.dart
@@ -28,7 +28,7 @@
import '../util/enumset.dart';
import '../util/util.dart';
import '../world.dart' show World, JClosedWorld, KClosedWorld, OpenWorld;
-import 'class_hierarchy.dart' show ClassHierarchyBuilder, ClassQueries;
+import 'class_hierarchy_builder.dart' show ClassHierarchyBuilder, ClassQueries;
import 'selector.dart' show Selector;
import 'use.dart'
show
diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
index d440deb..2a33f49 100644
--- a/pkg/compiler/lib/src/world.dart
+++ b/pkg/compiler/lib/src/world.dart
@@ -23,7 +23,6 @@
import 'ordered_typeset.dart';
import 'options.dart';
import 'types/abstract_value_domain.dart';
-import 'universe/class_hierarchy.dart';
import 'universe/class_set.dart';
import 'universe/function_set.dart' show FunctionSet;
import 'universe/selector.dart' show Selector;
@@ -69,8 +68,6 @@
Iterable<MemberEntity> get processedMembers;
- ClassHierarchy get classHierarchy;
-
/// Returns `true` if [cls] is either directly or indirectly instantiated.
bool isInstantiated(ClassEntity cls);
@@ -175,6 +172,27 @@
/// Returns an iterable over the common supertypes of the [classes].
Iterable<ClassEntity> commonSupertypesOf(Iterable<ClassEntity> classes);
+ /// Returns an iterable of the classes that are contained in the
+ /// strict subclass/subtype sets of both [cls1] and [cls2].
+ ///
+ /// Classes that are implied by included superclasses/supertypes are not
+ /// returned.
+ ///
+ /// For instance for this hierarchy
+ ///
+ /// class A {}
+ /// class B {}
+ /// class C implements A, B {}
+ /// class D extends C {}
+ ///
+ /// the query
+ ///
+ /// commonSubclasses(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE)
+ ///
+ /// return the set {C} because [D] is implied by [C].
+ Iterable<ClassEntity> commonSubclasses(
+ ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2);
+
/// Returns an iterable over the live mixin applications that mixin [cls].
Iterable<ClassEntity> mixinUsesOf(ClassEntity cls);
@@ -337,6 +355,19 @@
bool isInheritedInSubtypeOf(MemberEntity member, ClassEntity type);
}
+/// Enum values defining subset of classes included in queries.
+enum ClassQuery {
+ /// Only the class itself is included.
+ EXACT,
+
+ /// The class and all subclasses (transitively) are included.
+ SUBCLASS,
+
+ /// The class and all classes that implement or subclass it (transitively)
+ /// are included.
+ SUBTYPE,
+}
+
abstract class ClosedWorldBase implements JClosedWorld {
final ConstantSystem constantSystem;
final NativeData nativeData;
@@ -373,8 +404,6 @@
final Iterable<MemberEntity> processedMembers;
- final ClassHierarchy classHierarchy;
-
ClosedWorldBase(
this.elementEnvironment,
this.dartTypes,
@@ -396,9 +425,7 @@
AbstractValueStrategy abstractValueStrategy)
: this._implementedClasses = implementedClasses,
this._classHierarchyNodes = classHierarchyNodes,
- this._classSets = classSets,
- classHierarchy = new ClassHierarchyImpl(
- commonElements, classHierarchyNodes, classSets) {}
+ this._classSets = classSets {}
bool checkEntity(covariant Entity element);
@@ -638,6 +665,27 @@
return classSet != null ? classSet.getLubOfInstantiatedSubtypes() : null;
}
+ Set<ClassEntity> _commonContainedClasses(ClassEntity cls1, ClassQuery query1,
+ ClassEntity cls2, ClassQuery query2) {
+ Iterable<ClassEntity> xSubset = _containedSubset(cls1, query1);
+ if (xSubset == null) return null;
+ Iterable<ClassEntity> ySubset = _containedSubset(cls2, query2);
+ if (ySubset == null) return null;
+ return xSubset.toSet().intersection(ySubset.toSet());
+ }
+
+ Iterable<ClassEntity> _containedSubset(ClassEntity cls, ClassQuery query) {
+ switch (query) {
+ case ClassQuery.EXACT:
+ return null;
+ case ClassQuery.SUBCLASS:
+ return strictSubclassesOf(cls);
+ case ClassQuery.SUBTYPE:
+ return strictSubtypesOf(cls);
+ }
+ throw new ArgumentError('Unexpected query: $query.');
+ }
+
/// Returns `true` if [cls] is mixed into a live class.
bool isUsedAsMixin(ClassEntity cls) {
return !mixinUsesOf(cls).isEmpty;
@@ -761,6 +809,38 @@
return commonSupertypes;
}
+ Iterable<ClassEntity> commonSubclasses(ClassEntity cls1, ClassQuery query1,
+ ClassEntity cls2, ClassQuery query2) {
+ // TODO(johnniwinther): Use [ClassSet] to compute this.
+ // Compute the set of classes that are contained in both class subsets.
+ Set<ClassEntity> common =
+ _commonContainedClasses(cls1, query1, cls2, query2);
+ if (common == null || common.isEmpty) return const <ClassEntity>[];
+ // Narrow down the candidates by only looking at common classes
+ // that do not have a superclass or supertype that will be a
+ // better candidate.
+ return common.where((ClassEntity each) {
+ bool containsSuperclass = common.contains(getSuperClass(each));
+ // If the superclass is also a candidate, then we don't want to
+ // deal with this class. If we're only looking for a subclass we
+ // know we don't have to look at the list of interfaces because
+ // they can never be in the common set.
+ if (containsSuperclass ||
+ query1 == ClassQuery.SUBCLASS ||
+ query2 == ClassQuery.SUBCLASS) {
+ return !containsSuperclass;
+ }
+ // Run through the direct supertypes of the class. If the common
+ // set contains the direct supertype of the class, we ignore the
+ // the class because the supertype is a better candidate.
+
+ for (ClassEntity interface in getInterfaces(each)) {
+ if (common.contains(interface)) return false;
+ }
+ return true;
+ });
+ }
+
/// Returns an iterable over the live mixin applications that mixin [cls].
Iterable<ClassEntity> mixinUsesOf(ClassEntity cls) {
if (_liveMixinUses == null) {
@@ -957,11 +1037,23 @@
InterceptorData get interceptorData;
ElementEnvironment get elementEnvironment;
CommonElements get commonElements;
- ClassHierarchy get classHierarchy;
/// Returns `true` if [cls] is implemented by an instantiated class.
bool isImplemented(ClassEntity 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 [JClosedWorld].
+ ClassHierarchyNode getClassHierarchyNode(ClassEntity cls);
+
+ /// 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 [JClosedWorld].
+ ClassSet getClassSet(ClassEntity cls);
Iterable<MemberEntity> get liveInstanceMembers;
Map<ClassEntity, Set<ClassEntity>> get mixinUses;
Map<ClassEntity, Set<ClassEntity>> get typesImplementedBySubclasses;
@@ -973,4 +1065,42 @@
Iterable<MemberEntity> get processedMembers;
RuntimeTypesNeed get rtiNeed;
NoSuchMethodData get noSuchMethodData;
+
+ /// Returns `true` if [x] is a subtype of [y], that is, if [x] implements an
+ /// instance of [y].
+ bool isSubtypeOf(ClassEntity x, ClassEntity y);
+
+ /// Returns an iterable of the classes that are contained in the
+ /// strict subclass/subtype sets of both [cls1] and [cls2].
+ ///
+ /// Classes that are implied by included superclasses/supertypes are not
+ /// returned.
+ ///
+ /// For instance for this hierarchy
+ ///
+ /// class A {}
+ /// class B {}
+ /// class C implements A, B {}
+ /// class D extends C {}
+ ///
+ /// the query
+ ///
+ /// commonSubclasses(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE)
+ ///
+ /// return the set {C} because [D] is implied by [C].
+ Iterable<ClassEntity> commonSubclasses(
+ ClassEntity cls1, ClassQuery query1, ClassEntity cls2, ClassQuery query2);
+
+ /// Returns an iterable over the directly instantiated that implement [cls]
+ /// possibly including [cls] itself, if it is live.
+ Iterable<ClassEntity> subtypesOf(ClassEntity cls);
+
+ /// Returns an iterable over the live classes that extend [cls] including
+ /// [cls] itself.
+ Iterable<ClassEntity> subclassesOf(ClassEntity cls);
+
+ /// Applies [f] to each live class that implements [cls] _not_ including [cls]
+ /// itself.
+ void forEachStrictSubtypeOf(
+ ClassEntity cls, IterationStep f(ClassEntity cls));
}
diff --git a/tests/compiler/dart2js/jsinterop/world_test.dart b/tests/compiler/dart2js/jsinterop/world_test.dart
index 25377d5..cb9cf2c 100644
--- a/tests/compiler/dart2js/jsinterop/world_test.dart
+++ b/tests/compiler/dart2js/jsinterop/world_test.dart
@@ -11,7 +11,6 @@
import 'package:compiler/src/compiler.dart';
import 'package:compiler/src/elements/entities.dart' show ClassEntity;
import 'package:compiler/src/elements/names.dart';
-import 'package:compiler/src/universe/class_hierarchy.dart';
import 'package:compiler/src/universe/selector.dart';
import 'package:compiler/src/world.dart';
import '../helpers/element_lookup.dart';
diff --git a/tests/compiler/dart2js/model/class_set_test.dart b/tests/compiler/dart2js/model/class_set_test.dart
index 833334f..f91acf6 100644
--- a/tests/compiler/dart2js/model/class_set_test.dart
+++ b/tests/compiler/dart2js/model/class_set_test.dart
@@ -68,7 +68,7 @@
void checkClass(ClassEntity cls,
{bool directlyInstantiated: false, bool indirectlyInstantiated: false}) {
- ClassHierarchyNode node = world.classHierarchy.getClassHierarchyNode(cls);
+ ClassHierarchyNode node = world.getClassHierarchyNode(cls);
Expect.isNotNull(node, "Expected ClassHierarchyNode for $cls.");
Expect.equals(
directlyInstantiated || indirectlyInstantiated,
@@ -139,7 +139,7 @@
}
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(G), ClassHierarchyNode.ALL)
+ world.getClassHierarchyNode(G), ClassHierarchyNode.ALL)
.iterator;
checkState(G, currentNode: null, stack: null);
Expect.isNull(iterator.current);
@@ -151,7 +151,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(G), ClassHierarchyNode.ALL,
+ world.getClassHierarchyNode(G), ClassHierarchyNode.ALL,
includeRoot: false)
.iterator;
checkState(G, currentNode: null, stack: null);
@@ -161,7 +161,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(C), ClassHierarchyNode.ALL)
+ world.getClassHierarchyNode(C), ClassHierarchyNode.ALL)
.iterator;
checkState(C, currentNode: null, stack: null);
Expect.isNull(iterator.current);
@@ -182,7 +182,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(D), ClassHierarchyNode.ALL)
+ world.getClassHierarchyNode(D), ClassHierarchyNode.ALL)
.iterator;
checkState(D, currentNode: null, stack: null);
Expect.isNull(iterator.current);
@@ -194,7 +194,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(B), ClassHierarchyNode.ALL)
+ world.getClassHierarchyNode(B), ClassHierarchyNode.ALL)
.iterator;
checkState(B, currentNode: null, stack: null);
Expect.isNull(iterator.current);
@@ -209,7 +209,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(B), ClassHierarchyNode.ALL,
+ world.getClassHierarchyNode(B), ClassHierarchyNode.ALL,
includeRoot: false)
.iterator;
checkState(B, currentNode: null, stack: null);
@@ -222,7 +222,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(B),
+ world.getClassHierarchyNode(B),
new EnumSet<Instantiation>.fromValues(<Instantiation>[
Instantiation.DIRECTLY_INSTANTIATED,
Instantiation.UNINSTANTIATED
@@ -237,7 +237,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(A), ClassHierarchyNode.ALL)
+ world.getClassHierarchyNode(A), ClassHierarchyNode.ALL)
.iterator;
checkState(A, currentNode: null, stack: null);
Expect.isNull(iterator.current);
@@ -267,7 +267,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(A), ClassHierarchyNode.ALL,
+ world.getClassHierarchyNode(A), ClassHierarchyNode.ALL,
includeRoot: false)
.iterator;
checkState(A, currentNode: null, stack: null);
@@ -295,7 +295,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(A),
+ world.getClassHierarchyNode(A),
new EnumSet<Instantiation>.fromValues(<Instantiation>[
Instantiation.DIRECTLY_INSTANTIATED,
Instantiation.UNINSTANTIATED
@@ -325,7 +325,7 @@
Expect.isNull(iterator.current);
iterator = new ClassHierarchyNodeIterable(
- world.classHierarchy.getClassHierarchyNode(A),
+ world.getClassHierarchyNode(A),
new EnumSet<Instantiation>.fromValues(<Instantiation>[
Instantiation.DIRECTLY_INSTANTIATED,
Instantiation.UNINSTANTIATED
@@ -400,7 +400,7 @@
ClassEntity X = env.getClass("X");
void checkForEachSubclass(ClassEntity cls, List<ClassEntity> expected) {
- ClassSet classSet = world.classHierarchy.getClassSet(cls);
+ ClassSet classSet = world.getClassSet(cls);
List<ClassEntity> visited = <ClassEntity>[];
classSet.forEachSubclass((cls) {
visited.add(cls);
@@ -437,7 +437,7 @@
checkForEachSubclass(X, [X]);
void checkForEachSubtype(ClassEntity cls, List<ClassEntity> expected) {
- ClassSet classSet = world.classHierarchy.getClassSet(cls);
+ ClassSet classSet = world.getClassSet(cls);
List<ClassEntity> visited = <ClassEntity>[];
classSet.forEachSubtype((cls) {
visited.add(cls);
@@ -482,7 +482,7 @@
mask = ClassHierarchyNode.ALL;
}
- ClassSet classSet = world.classHierarchy.getClassSet(cls);
+ ClassSet classSet = world.getClassSet(cls);
List<ClassEntity> visited = <ClassEntity>[];
IterationStep visit(_cls) {
@@ -539,7 +539,7 @@
void checkAny(ClassEntity cls, List<ClassEntity> expected,
{ClassEntity find, bool expectedResult, bool anySubtype: false}) {
- ClassSet classSet = world.classHierarchy.getClassSet(cls);
+ ClassSet classSet = world.getClassSet(cls);
List<ClassEntity> visited = <ClassEntity>[];
bool visit(cls) {
diff --git a/tests/compiler/dart2js/model/subtypeset_test.dart b/tests/compiler/dart2js/model/subtypeset_test.dart
index fac2f27..fd5e963 100644
--- a/tests/compiler/dart2js/model/subtypeset_test.dart
+++ b/tests/compiler/dart2js/model/subtypeset_test.dart
@@ -67,7 +67,7 @@
void checkClass(ClassEntity cls, List<ClassEntity> expectedSubtypes,
{bool checkSubset: false}) {
- ClassSet node = world.classHierarchy.getClassSet(cls);
+ ClassSet node = world.getClassSet(cls);
Set<ClassEntity> actualSubtypes = node.subtypes().toSet();
if (checkSubset) {
for (ClassEntity subtype in expectedSubtypes) {
diff --git a/tests/compiler/dart2js/model/world_test.dart b/tests/compiler/dart2js/model/world_test.dart
index 78e93f1..3abdd5d 100644
--- a/tests/compiler/dart2js/model/world_test.dart
+++ b/tests/compiler/dart2js/model/world_test.dart
@@ -9,9 +9,8 @@
import 'package:compiler/src/common/names.dart';
import 'package:compiler/src/common_elements.dart';
import 'package:compiler/src/elements/entities.dart';
-import 'package:compiler/src/universe/class_hierarchy.dart';
import 'package:compiler/src/universe/class_set.dart';
-import 'package:compiler/src/world.dart' show JClosedWorld;
+import 'package:compiler/src/world.dart' show ClassQuery, JClosedWorld;
import '../type_test_helper.dart';
void main() {
@@ -551,106 +550,65 @@
ClassEntity A = env.getElement("A");
ClassEntity B = env.getElement("B");
ClassEntity C = env.getElement("C");
+ ClassEntity D = env.getElement("D");
ClassEntity F = env.getElement("F");
ClassEntity G = env.getElement("G");
+ ClassEntity H = env.getElement("H");
ClassEntity I = env.getElement("I");
ClassEntity J = env.getElement("J");
void check(ClassEntity cls1, ClassQuery query1, ClassEntity cls2,
- ClassQuery query2, SubclassResult expectedResult) {
- SubclassResult result1 =
- closedWorld.classHierarchy.commonSubclasses(cls1, query1, cls2, query2);
- SubclassResult result2 =
- closedWorld.classHierarchy.commonSubclasses(cls2, query2, cls1, query1);
- Expect.equals(
- result1.query,
- result2.query,
+ ClassQuery query2, List<ClassEntity> expectedResult) {
+ Iterable<ClassEntity> result1 =
+ closedWorld.commonSubclasses(cls1, query1, cls2, query2);
+ Iterable<ClassEntity> result2 =
+ closedWorld.commonSubclasses(cls2, query2, cls1, query1);
+ Expect.setEquals(
+ result1,
+ result2,
"Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):"
"\n a vs b: $result1\n b vs a: $result2");
Expect.setEquals(
- result1.classes,
- result2.classes,
- "Asymmetric results for ($cls1,$query1) vs ($cls2,$query2):"
- "\n a vs b: $result1\n b vs a: $result2");
- Expect.equals(
- expectedResult.query,
- result1.query,
- "Unexpected results for ($cls1,$query1) vs ($cls2,$query2):"
- "\n expected: $expectedResult\n actual: $result1");
- Expect.setEquals(
- expectedResult.classes,
- result1.classes,
+ expectedResult,
+ result1,
"Unexpected results for ($cls1,$query1) vs ($cls2,$query2):"
"\n expected: $expectedResult\n actual: $result1");
}
- check(A, ClassQuery.EXACT, A, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, [A]));
- check(A, ClassQuery.EXACT, A, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, [A]));
- check(A, ClassQuery.EXACT, A, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.EXACT, [A]));
- check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [A]));
- check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [A]));
- check(A, ClassQuery.SUBTYPE, A, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBTYPE, [A]));
+ check(A, ClassQuery.EXACT, A, ClassQuery.EXACT, []);
+ check(A, ClassQuery.EXACT, A, ClassQuery.SUBCLASS, []);
+ check(A, ClassQuery.EXACT, A, ClassQuery.SUBTYPE, []);
+ check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBCLASS, [C]);
+ check(A, ClassQuery.SUBCLASS, A, ClassQuery.SUBTYPE, [C]);
+ check(A, ClassQuery.SUBTYPE, A, ClassQuery.SUBTYPE, [C, D]);
- check(A, ClassQuery.EXACT, B, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.EXACT, B, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBCLASS, B, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.EXACT, B, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBTYPE, B, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [G]));
- check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [J]));
- check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [F, G, I, J]));
+ check(A, ClassQuery.EXACT, B, ClassQuery.EXACT, []);
+ check(A, ClassQuery.EXACT, B, ClassQuery.SUBCLASS, []);
+ check(A, ClassQuery.SUBCLASS, B, ClassQuery.EXACT, []);
+ check(A, ClassQuery.EXACT, B, ClassQuery.SUBTYPE, []);
+ check(A, ClassQuery.SUBTYPE, B, ClassQuery.EXACT, []);
+ check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBCLASS, []);
+ check(A, ClassQuery.SUBCLASS, B, ClassQuery.SUBTYPE, [G]);
+ check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBCLASS, [J]);
+ check(A, ClassQuery.SUBTYPE, B, ClassQuery.SUBTYPE, [F, G, I, J]);
- check(A, ClassQuery.EXACT, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.EXACT, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBCLASS, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, [C]));
- check(A, ClassQuery.EXACT, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(A, ClassQuery.SUBTYPE, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, [C]));
- check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [C]));
- check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [C]));
- check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [C]));
- check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBTYPE, [C]));
+ check(A, ClassQuery.EXACT, C, ClassQuery.EXACT, []);
+ check(A, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, []);
+ check(A, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, []);
+ check(A, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, []);
+ check(A, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, []);
+ check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, [G]);
+ check(A, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, [G]);
+ check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, [G]);
+ check(A, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, [F, G, H]);
- check(B, ClassQuery.EXACT, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.EXACT, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.SUBCLASS, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.EXACT, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.SUBTYPE, C, ClassQuery.EXACT,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.EXACT, []));
- check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, []));
- check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [G]));
- check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE,
- new SubclassResult.internal(ClassQuery.SUBCLASS, [F, G]));
+ check(B, ClassQuery.EXACT, C, ClassQuery.EXACT, []);
+ check(B, ClassQuery.EXACT, C, ClassQuery.SUBCLASS, []);
+ check(B, ClassQuery.SUBCLASS, C, ClassQuery.EXACT, []);
+ check(B, ClassQuery.EXACT, C, ClassQuery.SUBTYPE, []);
+ check(B, ClassQuery.SUBTYPE, C, ClassQuery.EXACT, []);
+ check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBCLASS, []);
+ check(B, ClassQuery.SUBCLASS, C, ClassQuery.SUBTYPE, []);
+ check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBCLASS, [G]);
+ check(B, ClassQuery.SUBTYPE, C, ClassQuery.SUBTYPE, [F, G]);
}
diff --git a/tests/compiler/dart2js/needs_no_such_method_test.dart b/tests/compiler/dart2js/needs_no_such_method_test.dart
index 735e390..5cd35d2 100644
--- a/tests/compiler/dart2js/needs_no_such_method_test.dart
+++ b/tests/compiler/dart2js/needs_no_such_method_test.dart
@@ -9,9 +9,8 @@
import 'package:compiler/src/elements/entities.dart';
import 'package:compiler/src/elements/names.dart';
import 'package:compiler/src/universe/call_structure.dart';
-import 'package:compiler/src/universe/class_hierarchy.dart';
import 'package:compiler/src/universe/selector.dart';
-import 'package:compiler/src/world.dart' show JClosedWorld;
+import 'package:compiler/src/world.dart' show JClosedWorld, ClassQuery;
import 'type_test_helper.dart';
void main() {