| Index: pkg/compiler/lib/src/world.dart
|
| diff --git a/pkg/compiler/lib/src/world.dart b/pkg/compiler/lib/src/world.dart
|
| index c6a20e07be0c3dee272dbb1560d2cbd0a9eaf229..8c69baeb5c8c2653543e8988748a292d6d46405e 100644
|
| --- a/pkg/compiler/lib/src/world.dart
|
| +++ b/pkg/compiler/lib/src/world.dart
|
| @@ -728,19 +728,16 @@ class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
|
| : result.implementation == element.implementation;
|
| }
|
|
|
| - Element findMatchIn(ClassElement cls, Selector selector,
|
| - {ClassElement stopAtSuperclass}) {
|
| + Element findMatchIn(ClassElement cls, Selector selector) {
|
| // Use the [:implementation] of [cls] in case the found [element]
|
| // is in the patch class.
|
| - var result = cls.implementation
|
| - .lookupByName(selector.memberName, stopAt: stopAtSuperclass);
|
| + var result = cls.implementation.lookupByName(selector.memberName);
|
| return result;
|
| }
|
|
|
| /// Returns whether a [selector] call on an instance of [cls]
|
| /// will hit a method at runtime, and not go through [noSuchMethod].
|
| - bool hasConcreteMatch(ClassElement cls, Selector selector,
|
| - {ClassElement stopAtSuperclass}) {
|
| + bool hasConcreteMatch(ClassElement cls, Selector selector) {
|
| assert(invariant(cls, isInstantiated(cls),
|
| message: '$cls has not been instantiated.'));
|
| Element element = findMatchIn(cls, selector);
|
| @@ -756,49 +753,35 @@ class WorldImpl implements ClosedWorld, ClosedWorldRefiner, OpenWorld {
|
| @override
|
| bool needsNoSuchMethod(
|
| ClassElement base, Selector selector, ClassQuery query) {
|
| - /// Returns `true` if subclasses in the [rootNode] tree needs noSuchMethod
|
| - /// handling.
|
| - bool subclassesNeedNoSuchMethod(ClassHierarchyNode rootNode) {
|
| - if (!rootNode.isInstantiated) {
|
| - // No subclass needs noSuchMethod handling since they are all
|
| - // uninstantiated.
|
| + /// Returns `true` if [cls] is an instantiated class that does not have
|
| + /// a concrete method matching [selector].
|
| + bool needsNoSuchMethod(ClassElement cls) {
|
| + // We can skip uninstantiated subclasses.
|
| + if (!isInstantiated(cls)) {
|
| return false;
|
| }
|
| - ClassElement rootClass = rootNode.cls;
|
| - if (hasConcreteMatch(rootClass, selector)) {
|
| - // The root subclass has a concrete implementation so no subclass needs
|
| - // noSuchMethod handling.
|
| - return false;
|
| - } else if (rootNode.isDirectlyInstantiated) {
|
| - // The root class need noSuchMethod handling.
|
| - return true;
|
| - }
|
| - IterationStep result = rootNode.forEachSubclass((ClassElement subclass) {
|
| - if (hasConcreteMatch(subclass, selector, stopAtSuperclass: rootClass)) {
|
| - // Found a match - skip all subclasses.
|
| - return IterationStep.SKIP_SUBCLASSES;
|
| - } else {
|
| - // Stop fast - we found a need for noSuchMethod handling.
|
| - return IterationStep.STOP;
|
| - }
|
| - }, ClassHierarchyNode.DIRECTLY_INSTANTIATED, strict: true);
|
| - // We stopped fast so we need noSuchMethod handling.
|
| - return result == IterationStep.STOP;
|
| + // We can just skip abstract classes because we know no
|
| + // instance of them will be created at runtime, and
|
| + // therefore there is no instance that will require
|
| + // [noSuchMethod] handling.
|
| + return !cls.isAbstract && !hasConcreteMatch(cls, selector);
|
| }
|
|
|
| - ClassSet classSet = getClassSet(base);
|
| - ClassHierarchyNode node = classSet.node;
|
| - if (query == ClassQuery.EXACT) {
|
| - return node.isDirectlyInstantiated && !hasConcreteMatch(base, selector);
|
| - } else if (query == ClassQuery.SUBCLASS) {
|
| - return subclassesNeedNoSuchMethod(node);
|
| + bool baseNeedsNoSuchMethod = needsNoSuchMethod(base);
|
| + if (query == ClassQuery.EXACT || baseNeedsNoSuchMethod) {
|
| + return baseNeedsNoSuchMethod;
|
| + }
|
| +
|
| + Iterable<ClassElement> subclassesToCheck;
|
| + if (query == ClassQuery.SUBTYPE) {
|
| + subclassesToCheck = strictSubtypesOf(base);
|
| } else {
|
| - if (subclassesNeedNoSuchMethod(node)) return true;
|
| - for (ClassHierarchyNode subtypeNode in classSet.subtypeNodes) {
|
| - if (subclassesNeedNoSuchMethod(subtypeNode)) return true;
|
| - }
|
| - return false;
|
| + assert(query == ClassQuery.SUBCLASS);
|
| + subclassesToCheck = strictSubclassesOf(base);
|
| }
|
| +
|
| + return subclassesToCheck != null &&
|
| + subclassesToCheck.any(needsNoSuchMethod);
|
| }
|
|
|
| final Compiler _compiler;
|
|
|