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

Unified Diff: pkg/compiler/lib/src/types/flat_type_mask.dart

Issue 2420073002: Decouple TypeMask from ClassElement (Closed)
Patch Set: Updated cf. comments. Created 4 years, 2 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/compiler/lib/src/types/forwarding_type_mask.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: pkg/compiler/lib/src/types/flat_type_mask.dart
diff --git a/pkg/compiler/lib/src/types/flat_type_mask.dart b/pkg/compiler/lib/src/types/flat_type_mask.dart
index 5a3ef8e1ef0e8dda14c446b7847706e3523fe931..ce6cd550f90280b9eee6c68bd7eb73c24070fda4 100644
--- a/pkg/compiler/lib/src/types/flat_type_mask.dart
+++ b/pkg/compiler/lib/src/types/flat_type_mask.dart
@@ -14,17 +14,15 @@ class FlatTypeMask implements TypeMask {
static const int SUBCLASS = 2;
static const int SUBTYPE = 3;
- final ClassElement base;
+ final Entity base;
final int flags;
- FlatTypeMask(ClassElement base, int kind, bool isNullable)
+ FlatTypeMask(Entity base, int kind, bool isNullable)
: this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
- FlatTypeMask.exact(ClassElement base) : this.internal(base, (EXACT << 1) | 1);
- FlatTypeMask.subclass(ClassElement base)
- : this.internal(base, (SUBCLASS << 1) | 1);
- FlatTypeMask.subtype(ClassElement base)
- : this.internal(base, (SUBTYPE << 1) | 1);
+ FlatTypeMask.exact(Entity base) : this.internal(base, (EXACT << 1) | 1);
+ FlatTypeMask.subclass(Entity base) : this.internal(base, (SUBCLASS << 1) | 1);
+ FlatTypeMask.subtype(Entity base) : this.internal(base, (SUBTYPE << 1) | 1);
const FlatTypeMask.nonNullEmpty()
: base = null,
@@ -33,23 +31,22 @@ class FlatTypeMask implements TypeMask {
: base = null,
flags = 1;
- FlatTypeMask.nonNullExact(ClassElement base)
- : this.internal(base, EXACT << 1);
- FlatTypeMask.nonNullSubclass(ClassElement base)
+ FlatTypeMask.nonNullExact(Entity base) : this.internal(base, EXACT << 1);
+ FlatTypeMask.nonNullSubclass(Entity base)
: this.internal(base, SUBCLASS << 1);
- FlatTypeMask.nonNullSubtype(ClassElement base)
- : this.internal(base, SUBTYPE << 1);
+ FlatTypeMask.nonNullSubtype(Entity base) : this.internal(base, SUBTYPE << 1);
+
+ bool _validateBase(ClassElement element) => element.isDeclaration;
FlatTypeMask.internal(this.base, this.flags) {
- assert(base == null || base.isDeclaration);
+ assert(base == null || _validateBase(base));
}
/**
* Ensures that the generated mask is normalized, i.e., a call to
* [TypeMask.assertIsNormalized] with the factory's result returns `true`.
*/
- factory FlatTypeMask.normalized(
- ClassElement base, int flags, ClosedWorld world) {
+ factory FlatTypeMask.normalized(Entity base, int flags, ClosedWorld world) {
if ((flags >> 1) == EMPTY || ((flags >> 1) == EXACT)) {
return new FlatTypeMask.internal(base, flags);
}
@@ -61,14 +58,8 @@ class FlatTypeMask implements TypeMask {
if (((flags >> 1) == SUBCLASS) && !world.hasAnyStrictSubclass(base)) {
flags = (flags & 0x1) | (EXACT << 1);
}
- Map<ClassElement, TypeMask> cachedMasks =
- world.canonicalizedTypeMasks[flags];
- if (cachedMasks == null) {
- world.canonicalizedTypeMasks[flags] =
- cachedMasks = <ClassElement, TypeMask>{};
- }
- return cachedMasks.putIfAbsent(
- base, () => new FlatTypeMask.internal(base, flags));
+ return world.getCachedMask(
+ base, flags, () => new FlatTypeMask.internal(base, flags));
}
bool get isEmpty => isEmptyOrNull && !isNullable;
@@ -98,23 +89,23 @@ class FlatTypeMask implements TypeMask {
return isNullable ? new FlatTypeMask.internal(base, flags & ~1) : this;
}
- bool contains(ClassElement type, ClosedWorld closedWorld) {
- assert(type.isDeclaration);
+ bool contains(Entity other, ClosedWorld closedWorld) {
+ assert(_validateBase(other));
if (isEmptyOrNull) {
return false;
- } else if (identical(base, type)) {
+ } else if (identical(base, other)) {
return true;
} else if (isExact) {
return false;
} else if (isSubclass) {
- return closedWorld.isSubclassOf(type, base);
+ return closedWorld.isSubclassOf(other, base);
} else {
assert(isSubtype);
- return closedWorld.isSubtypeOf(type, base);
+ return closedWorld.isSubtypeOf(other, base);
}
}
- bool isSingleImplementationOf(ClassElement cls, ClosedWorld closedWorld) {
+ bool isSingleImplementationOf(Entity cls, ClosedWorld closedWorld) {
// Special case basic types so that, for example, JSString is the
// single implementation of String.
// The general optimization is to realize there is only one class that
@@ -154,7 +145,7 @@ class FlatTypeMask implements TypeMask {
if (other is! FlatTypeMask) return other.containsMask(this, closedWorld);
// The other must be flat, so compare base and flags.
FlatTypeMask flatOther = other;
- ClassElement otherBase = flatOther.base;
+ Entity otherBase = flatOther.base;
// If other is exact, it only contains its base.
// TODO(herhut): Get rid of isSingleImplementationOf.
if (flatOther.isExact) {
@@ -214,23 +205,21 @@ class FlatTypeMask implements TypeMask {
base == backendClasses.stringImplementation;
}
- bool containsOnly(ClassElement cls) {
- assert(cls.isDeclaration);
+ bool containsOnly(Entity cls) {
+ assert(_validateBase(cls));
return base == cls;
}
- bool satisfies(ClassElement cls, ClosedWorld closedWorld) {
- assert(cls.isDeclaration);
+ bool satisfies(Entity cls, ClosedWorld closedWorld) {
+ assert(_validateBase(cls));
if (isEmptyOrNull) return false;
if (closedWorld.isSubtypeOf(base, cls)) return true;
return false;
}
- /**
- * Returns the [ClassElement] if this type represents a single class,
- * otherwise returns `null`. This method is conservative.
- */
- ClassElement singleClass(ClosedWorld closedWorld) {
+ /// Returns the [Entity] if this type represents a single class, otherwise
+ /// returns `null`. This method is conservative.
+ Entity singleClass(ClosedWorld closedWorld) {
if (isEmptyOrNull) return null;
if (isNullable) return null; // It is Null and some other class.
if (isExact) {
@@ -479,6 +468,7 @@ class FlatTypeMask implements TypeMask {
if (isSubclass && other.isSubclass) return intersectionEmpty(other);
assert(isSubtype || other.isSubtype);
int kind = (isSubclass || other.isSubclass) ? SUBCLASS : SUBTYPE;
+ // TODO(johnniwinther): Move this computation to [ClosedWorld].
// Compute the set of classes that are contained in both type masks.
Set<ClassElement> common = commonContainedClasses(this, other, closedWorld);
if (common == null || common.isEmpty) return intersectionEmpty(other);
@@ -504,7 +494,7 @@ class FlatTypeMask implements TypeMask {
// 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((ClassElement cls) {
+ Iterable<TypeMask> masks = candidates.map((Entity cls) {
return new FlatTypeMask.normalized(cls, combined, closedWorld);
});
return UnionTypeMask.unionOf(masks, closedWorld);
@@ -517,27 +507,6 @@ class FlatTypeMask implements TypeMask {
}
/**
- * Returns whether [element] will be the one used at runtime when being
- * invoked on an instance of [cls]. [selector] is used to ensure library
- * privacy is taken into account.
- */
- static bool hasElementIn(
- ClassElement cls, Selector selector, Element element) {
- // Use [:implementation:] of [element]
- // because our function set only stores declarations.
- Element result = findMatchIn(cls, selector);
- return result == null
- ? false
- : result.implementation == element.implementation;
- }
-
- static Element findMatchIn(ClassElement cls, Selector selector) {
- // Use the [:implementation] of [cls] in case the found [element]
- // is in the patch class.
- return cls.implementation.lookupByName(selector.memberName);
- }
-
- /**
* Returns whether [element] is a potential target when being
* invoked on this type mask. [selector] is used to ensure library
* privacy is taken into account.
@@ -547,7 +516,8 @@ class FlatTypeMask implements TypeMask {
assert(element.name == selector.name);
if (isEmpty) return false;
if (isNull) {
- return hasElementIn(backendClasses.nullImplementation, selector, element);
+ return closedWorld.hasElementIn(
+ backendClasses.nullImplementation, selector, element);
}
// TODO(kasperl): Can't we just avoid creating typed selectors
@@ -563,14 +533,14 @@ class FlatTypeMask implements TypeMask {
if (other == backendClasses.nullImplementation) {
return isNullable;
} else if (isExact) {
- return hasElementIn(self, selector, element);
+ return closedWorld.hasElementIn(self, selector, element);
} else if (isSubclass) {
- return hasElementIn(self, selector, element) ||
+ return closedWorld.hasElementIn(self, selector, element) ||
other.isSubclassOf(self) ||
closedWorld.hasAnySubclassThatMixes(self, other);
} else {
assert(isSubtype);
- bool result = hasElementIn(self, selector, element) ||
+ bool result = closedWorld.hasElementIn(self, selector, element) ||
other.implementsInterface(self) ||
closedWorld.hasAnySubclassThatImplements(other, base) ||
closedWorld.hasAnySubclassOfMixinUseThatImplements(other, base);
@@ -579,108 +549,28 @@ class FlatTypeMask implements TypeMask {
// can be hit from any of the mixin applications.
Iterable<ClassElement> mixinUses = closedWorld.mixinUsesOf(self);
return mixinUses.any((mixinApplication) =>
- hasElementIn(mixinApplication, selector, element) ||
+ closedWorld.hasElementIn(mixinApplication, selector, element) ||
other.isSubclassOf(mixinApplication) ||
closedWorld.hasAnySubclassThatMixes(mixinApplication, other));
}
}
- /**
- * Returns whether a [selector] call on an instance of [cls]
- * will hit a method at runtime, and not go through [noSuchMethod].
- */
- static bool hasConcreteMatch(
- ClassElement cls, Selector selector, ClosedWorld world) {
- assert(invariant(cls, world.isInstantiated(cls),
- message: '$cls has not been instantiated.'));
- Element element = findMatchIn(cls, selector);
- if (element == null) return false;
-
- if (element.isAbstract) {
- ClassElement enclosingClass = element.enclosingClass;
- return hasConcreteMatch(enclosingClass.superclass, selector, world);
- }
- return selector.appliesUntyped(element);
- }
-
bool needsNoSuchMethodHandling(Selector selector, ClosedWorld closedWorld) {
// A call on an empty type mask is either dead code, or a call on
// `null`.
if (isEmptyOrNull) return false;
// A call on an exact mask for an abstract class is dead code.
- if (isExact && base.isAbstract) return false;
- // If the receiver is guaranteed to have a member that
- // matches what we're looking for, there's no need to
- // introduce a noSuchMethod handler. It will never be called.
- //
- // As an example, consider this class hierarchy:
- //
- // A <-- noSuchMethod
- // / \
- // C B <-- foo
- //
- // If we know we're calling foo on an object of type B we
- // don't have to worry about the noSuchMethod method in A
- // because objects of type B implement foo. On the other hand,
- // if we end up calling foo on something of type C we have to
- // add a handler for it.
-
- // If the holders of all user-defined noSuchMethod
- // implementations that might be applicable to the receiver
- // type have a matching member for the current name and
- // selector, we avoid introducing a noSuchMethod handler.
- //
- // As an example, consider this class hierarchy:
- //
- // A <-- foo
- // / \
- // noSuchMethod --> B C <-- bar
- // | |
- // C D <-- noSuchMethod
- //
- // When calling foo on an object of type A, we know that the
- // implementations of noSuchMethod are in the classes B and D
- // that also (indirectly) implement foo, so we do not need a
- // handler for it.
- //
- // If we're calling bar on an object of type D, we don't need
- // the handler either because all objects of type D implement
- // bar through inheritance.
- //
- // If we're calling bar on an object of type A we do need the
- // handler because we may have to call B.noSuchMethod since B
- // does not implement bar.
-
- /// 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.
- // TODO(johnniwinther): Put filtering into the (Class)World.
- if (!closedWorld.isInstantiated(cls)) {
- return false;
- }
- // 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, closedWorld);
- }
-
- bool baseNeedsNoSuchMethod = needsNoSuchMethod(base);
- if (isExact || baseNeedsNoSuchMethod) {
- return baseNeedsNoSuchMethod;
- }
-
- Iterable<ClassElement> subclassesToCheck;
- if (isSubtype) {
- subclassesToCheck = closedWorld.strictSubtypesOf(base);
- } else {
- assert(isSubclass);
- subclassesToCheck = closedWorld.strictSubclassesOf(base);
- }
+ // TODO(johnniwinther): A type mask cannot be abstract. Remove the need
+ // for this noise (currently used for super-calls in inference and mirror
+ // usage).
+ if (isExact && closedWorld.isAbstract(base)) return false;
- return subclassesToCheck != null &&
- subclassesToCheck.any(needsNoSuchMethod);
+ return closedWorld.needsNoSuchMethod(
+ base,
+ selector,
+ isExact
+ ? ClassQuery.EXACT
+ : (isSubclass ? ClassQuery.SUBCLASS : ClassQuery.SUBTYPE));
}
Element locateSingleElement(Selector selector, Compiler compiler) {
@@ -689,7 +579,7 @@ class FlatTypeMask implements TypeMask {
compiler.closedWorld.allFunctions.filter(selector, this);
if (targets.length != 1) return null;
Element result = targets.first;
- ClassElement enclosing = result.enclosingClass;
+ ClassElement enclosing = result.enclosingClass.declaration;
// We only return the found element if it is guaranteed to be implemented on
// all classes in the receiver type [this]. It could be found only in a
// subclass or in an inheritance-wise unrelated class in case of subtype
@@ -703,7 +593,7 @@ class FlatTypeMask implements TypeMask {
//}
return null;
} else {
- if (base.isSubclassOf(enclosing)) return result;
+ if (closedWorld.isSubclassOf(base, enclosing)) return result;
if (closedWorld.isSubclassOfMixinUseOf(base, enclosing)) return result;
}
return null;
« no previous file with comments | « no previous file | pkg/compiler/lib/src/types/forwarding_type_mask.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698