| 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 e1c158b22b94d77f60c58877176d1e7b2a187fd8..351d298cbfe3ce8f9703fbf4cd38bcaecc6f4228 100644
|
| --- a/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
|
| +++ b/sdk/lib/_internal/compiler/implementation/types/type_mask.dart
|
| @@ -11,9 +11,10 @@ part of types;
|
| */
|
| class TypeMask {
|
|
|
| - static const int EXACT = 0;
|
| - static const int SUBCLASS = 1;
|
| - static const int SUBTYPE = 2;
|
| + static const int EMPTY = 0;
|
| + static const int EXACT = 1;
|
| + static const int SUBCLASS = 2;
|
| + static const int SUBTYPE = 3;
|
|
|
| final DartType base;
|
| final int flags;
|
| @@ -21,6 +22,8 @@ class TypeMask {
|
| TypeMask(DartType base, int kind, bool isNullable)
|
| : this.internal(base, (kind << 1) | (isNullable ? 1 : 0));
|
|
|
| + const TypeMask.empty()
|
| + : this.internal(null, (EMPTY << 1) | 1);
|
| const TypeMask.exact(DartType base)
|
| : this.internal(base, (EXACT << 1) | 1);
|
| const TypeMask.subclass(DartType base)
|
| @@ -28,6 +31,8 @@ class TypeMask {
|
| const TypeMask.subtype(DartType base)
|
| : this.internal(base, (SUBTYPE << 1) | 1);
|
|
|
| + const TypeMask.nonNullEmpty()
|
| + : this.internal(null, EMPTY << 1);
|
| const TypeMask.nonNullExact(DartType base)
|
| : this.internal(base, EXACT << 1);
|
| const TypeMask.nonNullSubclass(DartType base)
|
| @@ -37,8 +42,9 @@ class TypeMask {
|
|
|
| const TypeMask.internal(this.base, this.flags);
|
|
|
| - bool get isNullable => (flags & 1) != 0;
|
| + bool get isEmpty => (flags >> 1) == EMPTY;
|
| bool get isExact => (flags >> 1) == EXACT;
|
| + bool get isNullable => (flags & 1) != 0;
|
|
|
| // TODO(kasperl): Get rid of these. They should not be a visible
|
| // part of the implementation because they make it hard to add
|
| @@ -46,6 +52,8 @@ class TypeMask {
|
| bool get isSubclass => (flags >> 1) == SUBCLASS;
|
| bool get isSubtype => (flags >> 1) == SUBTYPE;
|
|
|
| + DartType get exactType => isExact ? base : null;
|
| +
|
| /**
|
| * Returns a nullable variant of [this] type mask.
|
| */
|
| @@ -53,13 +61,20 @@ class TypeMask {
|
| return isNullable ? this : new TypeMask.internal(base, flags | 1);
|
| }
|
|
|
| - DartType get exactType => isExact ? base : null;
|
| + /**
|
| + * Returns a non-nullable variant of [this] type mask.
|
| + */
|
| + TypeMask nonNullable() {
|
| + return isNullable ? new TypeMask.internal(base, flags & ~1) : this;
|
| + }
|
|
|
| /**
|
| * Returns whether or not this type mask contains the given type.
|
| */
|
| bool contains(DartType type, Compiler compiler) {
|
| - if (identical(base.element, type.element)) {
|
| + if (isEmpty) {
|
| + return false;
|
| + } else if (identical(base.element, type.element)) {
|
| return true;
|
| } else if (isExact) {
|
| return false;
|
| @@ -71,20 +86,23 @@ class TypeMask {
|
| }
|
| }
|
|
|
| - // TODO(kasperl): Try to get rid of this method. It shouldn't really
|
| +// TODO(kasperl): Try to get rid of this method. It shouldn't really
|
| // be necessary.
|
| bool containsAll(Compiler compiler) {
|
| + if (isEmpty || isExact) return false;
|
| // TODO(kasperl): Do this error handling earlier.
|
| if (base.kind != TypeKind.INTERFACE) return false;
|
| - // TODO(kasperl): Should we take nullability into account here?
|
| - if (isExact) return false;
|
| ClassElement baseElement = base.element;
|
| return identical(baseElement, compiler.objectClass)
|
| || identical(baseElement, compiler.dynamicClass);
|
| }
|
|
|
| TypeMask union(TypeMask other, Compiler compiler) {
|
| - if (base.asRaw() == other.base.asRaw()) {
|
| + if (isEmpty) {
|
| + return isNullable ? other.nullable() : other;
|
| + } else if (other.isEmpty) {
|
| + return other.isNullable ? nullable() : this;
|
| + } else if (base.asRaw() == other.base.asRaw()) {
|
| return unionSame(other, compiler);
|
| } else if (isSubclassOf(other.base, base, compiler)) {
|
| return unionSubclass(other, compiler);
|
| @@ -204,7 +222,11 @@ class TypeMask {
|
| }
|
|
|
| TypeMask intersection(TypeMask other, Compiler compiler) {
|
| - if (base.asRaw() == other.base.asRaw()) {
|
| + if (isEmpty) {
|
| + return other.isNullable ? this : nonNullable();
|
| + } else if (other.isEmpty) {
|
| + return isNullable ? other : other.nonNullable();
|
| + } else if (base.asRaw() == other.base.asRaw()) {
|
| return intersectionSame(other, compiler);
|
| } else if (isSubclassOf(other.base, base, compiler)) {
|
| return intersectionSubclass(other, compiler);
|
| @@ -337,6 +359,7 @@ class TypeMask {
|
| }
|
|
|
| String toString() {
|
| + if (isEmpty) return isNullable ? '[null]' : '[empty]';
|
| StringBuffer buffer = new StringBuffer();
|
| if (isNullable) buffer.write('null|');
|
| if (isExact) buffer.write('exact=');
|
|
|