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

Unified Diff: sdk/lib/_internal/compiler/implementation/types/type_mask.dart

Issue 12509005: Add intersection of disjoint masks to the TypeMask implementation. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Allow base == null. Ugh. Created 7 years, 9 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 | « sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/compiler/implementation/types/type_mask.dart
diff --git a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
index 9099ba1f6801660392e37ba9f26076de9f7cebeb..b94c4798f7dfc50e984e9363dc70640131b6ae78 100644
--- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
@@ -5,11 +5,9 @@
part of types;
/**
- * A type mask represents a set of concrete types, but the operations
- * on it are not guaranteed to be precise. When computing the union of
- * two masks you may get a mask that is too wide (like a common
- * superclass instead of a proper union type) and when computing the
- * intersection of two masks you may get a mask that is too narrow.
+ * A type mask represents a set of contained classes, but the
+ * operations on it are not guaranteed to be precise and they may
+ * yield conservative answers that contain too many classes.
*/
class TypeMask {
@@ -84,7 +82,7 @@ class TypeMask {
}
TypeMask union(TypeMask other, Compiler compiler) {
- if (base == other.base) {
+ if (base.asRaw() == other.base.asRaw()) {
return unionSame(other, compiler);
} else if (isSubclassOf(other.base, base, compiler)) {
return unionSubclass(other, compiler);
@@ -100,7 +98,7 @@ class TypeMask {
}
TypeMask unionSame(TypeMask other, Compiler compiler) {
- assert(base == other.base);
+ assert(base.asRaw() == other.base.asRaw());
// The two masks share the base type, so we must chose the least
// constraining kind (the highest) of the two. If either one of
// the masks are nullable the result should be nullable too.
@@ -149,7 +147,7 @@ class TypeMask {
}
TypeMask unionDisjoint(TypeMask other, Compiler compiler) {
- assert(base != other.base);
+ assert(base.asRaw() != other.base.asRaw());
assert(!isSubtypeOf(base, other.base, compiler));
assert(!isSubtypeOf(other.base, base, compiler));
// TODO(kasperl): Do this error handling earlier.
@@ -204,7 +202,7 @@ class TypeMask {
}
TypeMask intersection(TypeMask other, Compiler compiler) {
- if (base == other.base) {
+ if (base.asRaw() == other.base.asRaw()) {
return intersectionSame(other, compiler);
} else if (isSubclassOf(other.base, base, compiler)) {
return intersectionSubclass(other, compiler);
@@ -214,12 +212,13 @@ class TypeMask {
return intersectionSubtype(other, compiler);
} else if (isSubtypeOf(base, other.base, compiler)) {
return other.intersectionSubtype(this, compiler);
+ } else {
+ return intersectionDisjoint(other, compiler);
}
- return null;
}
TypeMask intersectionSame(TypeMask other, Compiler compiler) {
- assert(base == other.base);
+ assert(base.asRaw() == other.base.asRaw());
// The two masks share the base type, so we must chose the most
// constraining kind (the lowest) of the two. Only if both masks
// are nullable, will the result be nullable too.
@@ -267,10 +266,72 @@ class TypeMask {
}
}
+ TypeMask intersectionDisjoint(TypeMask other, Compiler compiler) {
+ assert(base.asRaw() != other.base.asRaw());
+ assert(!isSubtypeOf(base, other.base, compiler));
+ assert(!isSubtypeOf(other.base, base, compiler));
+ // TODO(kasperl): Do this error handling earlier.
+ if (base.kind != TypeKind.INTERFACE) return null;
+ if (other.base.kind != TypeKind.INTERFACE) return null;
+ // 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 null;
+ if (isSubclass && other.isSubclass) return null;
+ assert(isSubtype || other.isSubtype);
+ int kind = (isSubclass || other.isSubclass) ? SUBCLASS : SUBTYPE;
+ // Compute the set of classes that are contained in both type masks.
+ Set<ClassElement> common = commonContainedClasses(this, other, compiler);
+ if (common == null || common.isEmpty) return null;
+ // Narrow down the candidates by only looking at common classes
+ // that do not have a superclass or supertype that will be a
+ // better candidate.
+ Iterable<ClassElement> candidates = common.where((ClassElement each) {
+ bool containsSuperclass = common.contains(each.supertype.element);
+ // 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 || kind == 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 (Link link = each.interfaces; !link.isEmpty; link = link.tail) {
+ if (common.contains(link.head.element)) return false;
+ }
+ return true;
+ });
+ // Run through the list of candidates and compute the union. The
+ // result will only be nullable if both masks are nullable.
+ int combined = (kind << 1) | (flags & other.flags & 1);
+ TypeMask result;
+ for (ClassElement each in candidates) {
+ TypeMask mask = new TypeMask.internal(each.rawType, combined);
+ result = (result == null) ? mask : result.union(mask, compiler);
+ }
+ return result;
+ }
+
+ Set<ClassElement> containedClasses(Compiler compiler) {
+ ClassElement element = base.element;
+ if (isExact) {
+ return new Set<ClassElement>()..add(element);
+ } else if (isSubclass) {
+ return compiler.world.subclasses[element];
+ } else {
+ assert(isSubtype);
+ return compiler.world.subtypes[element];
+ }
+ }
+
bool operator ==(var other) {
if (other is !TypeMask) return false;
TypeMask otherMask = other;
- return (base == otherMask.base) && (flags == otherMask.flags);
+ if (flags != otherMask.flags) return false;
+ if (base == null || otherMask.base == null) {
+ return base == otherMask.base;
+ } else {
+ return base.asRaw() == otherMask.base.asRaw();
+ }
}
String toString() {
@@ -302,4 +363,22 @@ class TypeMask {
Set<ClassElement> subtypes = compiler.world.subtypes[yElement];
return (subtypes != null) ? subtypes.contains(xElement) : false;
}
+
+ static Set<ClassElement> commonContainedClasses(TypeMask x, TypeMask y,
+ Compiler compiler) {
+ Set<ClassElement> xSubset = x.containedClasses(compiler);
+ if (xSubset == null) return null;
+ Set<ClassElement> ySubset = y.containedClasses(compiler);
+ if (ySubset == null) return null;
+ Set<ClassElement> smallSet, largeSet;
+ if (xSubset.length <= ySubset.length) {
+ smallSet = xSubset;
+ largeSet = ySubset;
+ } else {
+ smallSet = ySubset;
+ largeSet = xSubset;
+ }
+ var result = smallSet.where((ClassElement each) => largeSet.contains(each));
+ return result.toSet();
+ }
}
« no previous file with comments | « sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698