Chromium Code Reviews| Index: sdk/lib/_internal/compiler/implementation/types/type_mask.dart |
| =================================================================== |
| --- sdk/lib/_internal/compiler/implementation/types/type_mask.dart (revision 22167) |
| +++ sdk/lib/_internal/compiler/implementation/types/type_mask.dart (working copy) |
| @@ -4,12 +4,85 @@ |
| part of types; |
| +abstract class TypeMask { |
| + factory TypeMask(DartType base, int kind, bool isNullable) |
| + => new FlatTypeMask(base, kind, isNullable); |
| + |
| + factory TypeMask.empty() => new FlatTypeMask.empty(); |
| + |
| + factory TypeMask.exact(DartType base) => new FlatTypeMask.exact(base); |
| + factory TypeMask.subclass(DartType base) => new FlatTypeMask.subclass(base); |
| + factory TypeMask.subtype(DartType base) => new FlatTypeMask.subtype(base); |
| + |
| + factory TypeMask.nonNullEmpty() |
| + => new FlatTypeMask.nonNullEmpty(); |
| + factory TypeMask.nonNullExact(DartType base) |
| + => new FlatTypeMask.nonNullExact(base); |
| + factory TypeMask.nonNullSubclass(DartType base) |
| + => new FlatTypeMask.nonNullSubclass(base); |
| + factory TypeMask.nonNullSubtype(DartType base) |
| + => new FlatTypeMask.nonNullSubtype(base); |
| + |
| + /** |
| + * Returns a nullable variant of [this] type mask. |
| + */ |
| + TypeMask nullable(); |
| + |
| + /** |
| + * Returns a non-nullable variant of [this] type mask. |
| + */ |
| + TypeMask nonNullable(); |
| + |
| + bool get isEmpty; |
| + bool get isNullable; |
| + bool get isExact; |
| + |
| + /** |
| + * Returns whether or not this type mask contains the given type. |
| + */ |
| + bool contains(DartType type, Compiler compiler); |
| + |
| + /** |
| + * Returns whether or not this type mask contains all types. |
| + */ |
| + bool containsAll(Compiler compiler); |
| + |
| + /** |
| + * Returns the [ClassElement] if this type represents a single class, |
| + * otherwise returns `null`. This method is conservative. |
| + */ |
| + ClassElement singleClass(Compiler compiler); |
| + |
| + /** |
| + * Returns the [ClassElement] that this type can always be. Returns |
| + * null if this type is empty. |
| + */ |
| + ClassElement topClass(); |
|
kasperl
2013/04/30 14:03:24
It would be nice if we could get rid of this in an
ngeoffray
2013/05/01 12:56:16
I just got rid of this. As well as exactType.
|
| + |
| + TypeMask union(TypeMask other, Compiler compiler); |
| + TypeMask intersection(TypeMask other, Compiler compiler); |
| + |
| + /** |
| + * Returns whether a [selector] call will hit a method at runtime, |
| + * and not go through [noSuchMethod]. |
| + */ |
| + bool willHit(Selector selector, Compiler compiler); |
| + |
| + |
| + /** |
| + * 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. |
| + */ |
| + bool canHit(Element element, Selector selector, Compiler compiler); |
| +} |
| + |
| /** |
|
kasperl
2013/04/30 14:03:24
I'd move this to another file in the next CL.
ngeoffray
2013/05/01 12:56:16
Will do.
|
| * 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 { |
| +class FlatTypeMask implements TypeMask { |
| static const int EMPTY = 0; |
| static const int EXACT = 1; |
| @@ -19,28 +92,28 @@ |
| final DartType base; |
| final int flags; |
| - TypeMask(DartType base, int kind, bool isNullable) |
| + FlatTypeMask(DartType base, int kind, bool isNullable) |
| : this.internal(base, (kind << 1) | (isNullable ? 1 : 0)); |
| - TypeMask.empty() |
| + FlatTypeMask.empty() |
| : this.internal(null, (EMPTY << 1) | 1); |
| - TypeMask.exact(DartType base) |
| + FlatTypeMask.exact(DartType base) |
| : this.internal(base, (EXACT << 1) | 1); |
| - TypeMask.subclass(DartType base) |
| + FlatTypeMask.subclass(DartType base) |
| : this.internal(base, (SUBCLASS << 1) | 1); |
| - TypeMask.subtype(DartType base) |
| + FlatTypeMask.subtype(DartType base) |
| : this.internal(base, (SUBTYPE << 1) | 1); |
| - TypeMask.nonNullEmpty() |
| + FlatTypeMask.nonNullEmpty() |
| : this.internal(null, EMPTY << 1); |
| - TypeMask.nonNullExact(DartType base) |
| + FlatTypeMask.nonNullExact(DartType base) |
| : this.internal(base, EXACT << 1); |
| - TypeMask.nonNullSubclass(DartType base) |
| + FlatTypeMask.nonNullSubclass(DartType base) |
| : this.internal(base, SUBCLASS << 1); |
| - TypeMask.nonNullSubtype(DartType base) |
| + FlatTypeMask.nonNullSubtype(DartType base) |
| : this.internal(base, SUBTYPE << 1); |
| - TypeMask.internal(DartType base, this.flags) |
| + FlatTypeMask.internal(DartType base, this.flags) |
| : this.base = transformBase(base); |
| // TODO(kasperl): We temporarily transform the base to be the raw |
| @@ -70,23 +143,14 @@ |
| DartType get exactType => isExact ? base : null; |
| - /** |
| - * Returns a nullable variant of [this] type mask. |
| - */ |
| TypeMask nullable() { |
| - return isNullable ? this : new TypeMask.internal(base, flags | 1); |
| + return isNullable ? this : new FlatTypeMask.internal(base, flags | 1); |
| } |
| - /** |
| - * Returns a non-nullable variant of [this] type mask. |
| - */ |
| TypeMask nonNullable() { |
| - return isNullable ? new TypeMask.internal(base, flags & ~1) : this; |
| + return isNullable ? new FlatTypeMask.internal(base, flags & ~1) : this; |
| } |
| - /** |
| - * Returns whether or not this type mask contains the given type. |
| - */ |
| bool contains(DartType type, Compiler compiler) { |
| if (isEmpty) { |
| return false; |
| @@ -101,6 +165,11 @@ |
| return isSubtypeOf(type, base, compiler); |
| } |
| } |
| + |
| + ClassElement topClass() { |
| + if (isEmpty) return null; |
| + return base.element; |
| + } |
| /** |
| * Returns the [ClassElement] if this type represents a single class, |
| @@ -129,7 +198,7 @@ |
| || identical(base.element, compiler.dynamicClass); |
| } |
| - TypeMask union(TypeMask other, Compiler compiler) { |
| + TypeMask union(FlatTypeMask other, Compiler compiler) { |
| if (isEmpty) { |
| return isNullable ? other.nullable() : other; |
| } else if (other.isEmpty) { |
| @@ -149,7 +218,7 @@ |
| } |
| } |
| - TypeMask unionSame(TypeMask other, Compiler compiler) { |
| + TypeMask unionSame(FlatTypeMask other, Compiler compiler) { |
| assert(base == other.base); |
| // The two masks share the base type, so we must chose the least |
| // constraining kind (the highest) of the two. If either one of |
| @@ -162,11 +231,11 @@ |
| } else if (other.flags == combined) { |
| return other; |
| } else { |
| - return new TypeMask.internal(base, combined); |
| + return new FlatTypeMask.internal(base, combined); |
| } |
| } |
| - TypeMask unionSubclass(TypeMask other, Compiler compiler) { |
| + TypeMask unionSubclass(FlatTypeMask other, Compiler compiler) { |
| assert(isSubclassOf(other.base, base, compiler)); |
| int combined; |
| if (isExact && other.isExact) { |
| @@ -183,22 +252,22 @@ |
| : other.flags | (flags & 1); |
| } |
| return (flags != combined) |
| - ? new TypeMask.internal(base, combined) |
| + ? new FlatTypeMask.internal(base, combined) |
| : this; |
| } |
| - TypeMask unionSubtype(TypeMask other, Compiler compiler) { |
| + TypeMask unionSubtype(FlatTypeMask other, Compiler compiler) { |
| assert(isSubtypeOf(other.base, base, compiler)); |
| // Since the other mask is a subtype of this mask, we need the |
| // resulting union to be a subtype too. If either one of the masks |
| // are nullable the result should be nullable too. |
| int combined = (SUBTYPE << 1) | ((flags | other.flags) & 1); |
| return (flags != combined) |
| - ? new TypeMask.internal(base, combined) |
| + ? new FlatTypeMask.internal(base, combined) |
| : this; |
| } |
| - TypeMask unionDisjoint(TypeMask other, Compiler compiler) { |
| + TypeMask unionDisjoint(FlatTypeMask other, Compiler compiler) { |
| assert(base != other.base); |
| assert(!isSubtypeOf(base, other.base, compiler)); |
| assert(!isSubtypeOf(other.base, base, compiler)); |
| @@ -253,7 +322,7 @@ |
| isNullable || other.isNullable); |
| } |
| - TypeMask intersection(TypeMask other, Compiler compiler) { |
| + TypeMask intersection(FlatTypeMask other, Compiler compiler) { |
| if (isEmpty) { |
| return other.isNullable ? this : nonNullable(); |
| } else if (other.isEmpty) { |
| @@ -273,7 +342,7 @@ |
| } |
| } |
| - TypeMask intersectionSame(TypeMask other, Compiler compiler) { |
| + TypeMask intersectionSame(FlatTypeMask other, Compiler compiler) { |
| assert(base == other.base); |
| // The two masks share the base type, so we must chose the most |
| // constraining kind (the lowest) of the two. Only if both masks |
| @@ -286,11 +355,11 @@ |
| } else if (other.flags == combined) { |
| return other; |
| } else { |
| - return new TypeMask.internal(base, combined); |
| + return new FlatTypeMask.internal(base, combined); |
| } |
| } |
| - TypeMask intersectionSubclass(TypeMask other, Compiler compiler) { |
| + TypeMask intersectionSubclass(FlatTypeMask other, Compiler compiler) { |
| assert(isSubclassOf(other.base, base, compiler)); |
| // If this mask isn't at least a subclass mask, then the |
| // intersection with the other mask is empty. |
| @@ -302,11 +371,11 @@ |
| if (other.flags == combined) { |
| return other; |
| } else { |
| - return new TypeMask.internal(other.base, combined); |
| + return new FlatTypeMask.internal(other.base, combined); |
| } |
| } |
| - TypeMask intersectionSubtype(TypeMask other, Compiler compiler) { |
| + TypeMask intersectionSubtype(FlatTypeMask other, Compiler compiler) { |
| assert(isSubtypeOf(other.base, base, compiler)); |
| // If this mask isn't a subtype mask, then the intersection with |
| // the other mask is empty. |
| @@ -318,11 +387,11 @@ |
| if (other.flags == combined) { |
| return other; |
| } else { |
| - return new TypeMask.internal(other.base, combined); |
| + return new FlatTypeMask.internal(other.base, combined); |
| } |
| } |
| - TypeMask intersectionDisjoint(TypeMask other, Compiler compiler) { |
| + TypeMask intersectionDisjoint(FlatTypeMask other, Compiler compiler) { |
| assert(base != other.base); |
| assert(!isSubtypeOf(base, other.base, compiler)); |
| assert(!isSubtypeOf(other.base, base, compiler)); |
| @@ -358,13 +427,13 @@ |
| int combined = (kind << 1) | (flags & other.flags & 1); |
| TypeMask result; |
| for (ClassElement each in candidates) { |
| - TypeMask mask = new TypeMask.internal(each.rawType, combined); |
| + TypeMask mask = new FlatTypeMask.internal(each.rawType, combined); |
| result = (result == null) ? mask : result.union(mask, compiler); |
| } |
| return result; |
| } |
| - TypeMask intersectionEmpty(TypeMask other) { |
| + TypeMask intersectionEmpty(FlatTypeMask other) { |
| return new TypeMask(null, EMPTY, isNullable && other.isNullable); |
| } |
| @@ -492,7 +561,7 @@ |
| } |
| bool operator ==(var other) { |
| - if (other is !TypeMask) return false; |
| + if (other is !FlatTypeMask) return false; |
| TypeMask otherMask = other; |
| return (flags == otherMask.flags) && (base == otherMask.base); |
| } |
| @@ -526,7 +595,8 @@ |
| return (subtypes != null) ? subtypes.contains(xElement) : false; |
| } |
| - static Set<ClassElement> commonContainedClasses(TypeMask x, TypeMask y, |
| + static Set<ClassElement> commonContainedClasses(FlatTypeMask x, |
| + FlatTypeMask y, |
| Compiler compiler) { |
| Set<ClassElement> xSubset = x.containedClasses(compiler); |
| if (xSubset == null) return null; |