Index: pkg/compiler/lib/src/types/union_type_mask.dart |
diff --git a/pkg/compiler/lib/src/types/union_type_mask.dart b/pkg/compiler/lib/src/types/union_type_mask.dart |
deleted file mode 100644 |
index 0ad1cc67095241a9ac67ed5849be6389ab535ed6..0000000000000000000000000000000000000000 |
--- a/pkg/compiler/lib/src/types/union_type_mask.dart |
+++ /dev/null |
@@ -1,347 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// for details. All rights reserved. Use of this source code is governed by a |
-// BSD-style license that can be found in the LICENSE file. |
- |
-part of types; |
- |
-class UnionTypeMask implements TypeMask { |
- final Iterable<FlatTypeMask> disjointMasks; |
- |
- static const int MAX_UNION_LENGTH = 4; |
- |
- UnionTypeMask._internal(this.disjointMasks) { |
- assert(disjointMasks.length > 1); |
- assert(disjointMasks.every((TypeMask mask) => !mask.isUnion)); |
- } |
- |
- static TypeMask unionOf(Iterable<TypeMask> masks, ClassWorld classWorld) { |
- assert(masks.every((mask) => TypeMask.assertIsNormalized(mask, classWorld))); |
- List<FlatTypeMask> disjoint = <FlatTypeMask>[]; |
- unionOfHelper(masks, disjoint, classWorld); |
- if (disjoint.isEmpty) return new TypeMask.nonNullEmpty(); |
- if (disjoint.length > MAX_UNION_LENGTH) { |
- return flatten(disjoint, classWorld); |
- } |
- if (disjoint.length == 1) return disjoint[0]; |
- UnionTypeMask union = new UnionTypeMask._internal(disjoint); |
- assert(TypeMask.assertIsNormalized(union, classWorld)); |
- return union; |
- } |
- |
- static void unionOfHelper(Iterable<TypeMask> masks, |
- List<FlatTypeMask> disjoint, |
- ClassWorld classWorld) { |
- // TODO(johnniwinther): Impose an order on the mask to ensure subclass masks |
- // are preferred to subtype masks. |
- for (TypeMask mask in masks) { |
- mask = TypeMask.nonForwardingMask(mask); |
- if (mask.isUnion) { |
- UnionTypeMask union = mask; |
- unionOfHelper(union.disjointMasks, disjoint, classWorld); |
- } else if (mask.isEmpty && !mask.isNullable) { |
- continue; |
- } else { |
- FlatTypeMask flatMask = mask; |
- int inListIndex = -1; |
- bool covered = false; |
- |
- // Iterate over [disjoint] to find out if one of the mask |
- // already covers [mask]. |
- for (int i = 0; i < disjoint.length; i++) { |
- FlatTypeMask current = disjoint[i]; |
- if (current == null) continue; |
- TypeMask newMask = flatMask.union(current, classWorld); |
- // If we have found a disjoint union, continue iterating. |
- if (newMask.isUnion) continue; |
- covered = true; |
- // We found a mask that is either equal to [mask] or is a |
- // supertype of [mask]. |
- if (current == newMask) break; |
- |
- // [mask] is a supertype of [current], replace the [disjoint] |
- // list with [newMask] instead of [current]. Note that |
- // [newMask] may contain different information than [mask], |
- // like nullability. |
- disjoint[i] = newMask; |
- flatMask = newMask; |
- |
- if (inListIndex != -1) { |
- // If the mask was already covered, we remove the previous |
- // place where it was inserted. This new mask subsumes the |
- // previously covered one. |
- disjoint.removeAt(inListIndex); |
- i--; |
- } |
- // Record where the mask was inserted. |
- inListIndex = i; |
- } |
- // If none of the masks in [disjoint] covers [mask], we just |
- // add [mask] to the list. |
- if (!covered) disjoint.add(flatMask); |
- } |
- } |
- } |
- |
- static TypeMask flatten(List<FlatTypeMask> masks, ClassWorld classWorld) { |
- assert(masks.length > 1); |
- // If either type mask is a subtype type mask, we cannot use a |
- // subclass type mask to represent their union. |
- bool useSubclass = masks.every((e) => !e.isSubtype); |
- bool isNullable = masks.any((e) => e.isNullable); |
- |
- Iterable<ClassElement> candidates = |
- classWorld.commonSupertypesOf(masks.map((mask) => mask.base)); |
- |
- // Compute the best candidate and its kind. |
- ClassElement bestElement; |
- int bestKind; |
- int bestSize; |
- for (ClassElement candidate in candidates) { |
- Iterable<ClassElement> subclasses = useSubclass |
- ? classWorld.subclassesOf(candidate) |
- : const <ClassElement>[]; |
- int size; |
- int kind; |
- if (masks.every((t) => subclasses.contains(t.base))) { |
- // If both [this] and [other] are subclasses of the supertype, |
- // then we prefer to construct a subclass type mask because it |
- // will always be at least as small as the corresponding |
- // subtype type mask. |
- kind = FlatTypeMask.SUBCLASS; |
- size = subclasses.length; |
- assert(size <= classWorld.subtypesOf(candidate).length); |
- } else { |
- kind = FlatTypeMask.SUBTYPE; |
- size = classWorld.subtypesOf(candidate).length; |
- } |
- // Update the best candidate if the new one is better. |
- if (bestElement == null || size < bestSize) { |
- bestElement = candidate; |
- bestSize = size; |
- bestKind = kind; |
- } |
- } |
- return new TypeMask(bestElement, bestKind, isNullable, classWorld); |
- } |
- |
- TypeMask union(var other, ClassWorld classWorld) { |
- other = TypeMask.nonForwardingMask(other); |
- if (!other.isUnion && disjointMasks.contains(other)) return this; |
- |
- List<FlatTypeMask> newList = |
- new List<FlatTypeMask>.from(disjointMasks); |
- if (!other.isUnion) { |
- newList.add(other); |
- } else { |
- assert(other is UnionTypeMask); |
- newList.addAll(other.disjointMasks); |
- } |
- return new TypeMask.unionOf(newList, classWorld); |
- } |
- |
- TypeMask intersection(var other, ClassWorld classWorld) { |
- other = TypeMask.nonForwardingMask(other); |
- if (!other.isUnion && disjointMasks.contains(other)) return other; |
- |
- List<TypeMask> intersections = <TypeMask>[]; |
- for (TypeMask current in disjointMasks) { |
- if (other.isUnion) { |
- for (FlatTypeMask flatOther in other.disjointMasks) { |
- intersections.add(current.intersection(flatOther, classWorld)); |
- } |
- } else { |
- intersections.add(current.intersection(other, classWorld)); |
- } |
- } |
- return new TypeMask.unionOf(intersections, classWorld); |
- } |
- |
- TypeMask nullable() { |
- if (isNullable) return this; |
- List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks); |
- newList[0] = newList[0].nullable(); |
- return new UnionTypeMask._internal(newList); |
- } |
- |
- TypeMask nonNullable() { |
- if (!isNullable) return this; |
- Iterable<FlatTypeMask> newIterable = |
- disjointMasks.map((e) => e.nonNullable()); |
- return new UnionTypeMask._internal(newIterable); |
- } |
- |
- bool get isEmpty => false; |
- bool get isNullable => disjointMasks.any((e) => e.isNullable); |
- bool get isExact => false; |
- bool get isUnion => true; |
- bool get isContainer => false; |
- bool get isMap => false; |
- bool get isDictionary => false; |
- bool get isForwarding => false; |
- bool get isValue => false; |
- |
- /** |
- * Checks whether [other] is contained in this union. |
- * |
- * Invariants: |
- * - [other] may not be a [UnionTypeMask] itself |
- * - the cheap test matching against individual members of [disjointMasks] |
- * must have failed. |
- */ |
- bool slowContainsCheck(TypeMask other, ClassWorld classWorld) { |
- // Unions should never make it here. |
- assert(!other.isUnion); |
- // Ensure the cheap test fails. |
- assert(!disjointMasks.any((mask) => mask.containsMask(other, classWorld))); |
- // If we cover object, we should never get here. |
- assert(!contains(classWorld.objectClass, classWorld)); |
- // Likewise, nullness should be covered. |
- assert(isNullable || !other.isNullable); |
- // The fast test is precise for exact types. |
- if (other.isExact) return false; |
- // We cannot contain object. |
- if (other.contains(classWorld.objectClass, classWorld)) return false; |
- FlatTypeMask flat = TypeMask.nonForwardingMask(other); |
- // Check we cover the base class. |
- if (!contains(flat.base, classWorld)) return false; |
- // Check for other members. |
- Iterable<ClassElement> members; |
- if (flat.isSubclass) { |
- members = classWorld.subclassesOf(flat.base); |
- } else { |
- assert(flat.isSubtype); |
- members = classWorld.subtypesOf(flat.base); |
- } |
- return members.every((ClassElement cls) => this.contains(cls, classWorld)); |
- } |
- |
- bool isInMask(TypeMask other, ClassWorld classWorld) { |
- other = TypeMask.nonForwardingMask(other); |
- if (isNullable && !other.isNullable) return false; |
- if (other.isUnion) { |
- UnionTypeMask union = other; |
- bool containedInAnyOf(FlatTypeMask mask, Iterable<FlatTypeMask> masks) { |
- // null is not canonicalized for the union but stored only on some |
- // masks in [disjointMask]. It has been checked in the surrounding |
- // context, so we can safely ignore it here. |
- FlatTypeMask maskDisregardNull = mask.nonNullable(); |
- return masks.any((FlatTypeMask other) { |
- return other.containsMask(maskDisregardNull, classWorld); |
- }); |
- } |
- return disjointMasks.every((FlatTypeMask disjointMask) { |
- bool contained = containedInAnyOf(disjointMask, union.disjointMasks); |
- assert(contained || !union.slowContainsCheck(disjointMask, classWorld)); |
- return contained; |
- }); |
- } |
- return disjointMasks.every((mask) => mask.isInMask(other, classWorld)); |
- } |
- |
- bool containsMask(TypeMask other, ClassWorld classWorld) { |
- other = TypeMask.nonForwardingMask(other); |
- if (other.isNullable && !isNullable) return false; |
- if (other.isUnion) return other.isInMask(this, classWorld); |
- other = other.nonNullable(); // nullable is not canonicalized, so drop it. |
- bool contained = |
- disjointMasks.any((mask) => mask.containsMask(other, classWorld)); |
- assert(contained || !slowContainsCheck(other, classWorld)); |
- return contained; |
- } |
- |
- bool containsOnlyInt(ClassWorld classWorld) { |
- return disjointMasks.every((mask) => mask.containsOnlyInt(classWorld)); |
- } |
- |
- bool containsOnlyDouble(ClassWorld classWorld) { |
- return disjointMasks.every((mask) => mask.containsOnlyDouble(classWorld)); |
- } |
- |
- bool containsOnlyNum(ClassWorld classWorld) { |
- return disjointMasks.every((mask) { |
- return mask.containsOnlyNum(classWorld); |
- }); |
- } |
- |
- bool containsOnlyBool(ClassWorld classWorld) { |
- return disjointMasks.every((mask) => mask.containsOnlyBool(classWorld)); |
- } |
- |
- bool containsOnlyString(ClassWorld classWorld) { |
- return disjointMasks.every((mask) => mask.containsOnlyString(classWorld)); |
- } |
- |
- bool containsOnly(ClassElement element) { |
- return disjointMasks.every((mask) => mask.containsOnly(element)); |
- } |
- |
- bool satisfies(ClassElement cls, ClassWorld classWorld) { |
- return disjointMasks.every((mask) => mask.satisfies(cls, classWorld)); |
- } |
- |
- bool contains(ClassElement type, ClassWorld classWorld) { |
- return disjointMasks.any((e) => e.contains(type, classWorld)); |
- } |
- |
- bool containsAll(ClassWorld classWorld) { |
- return disjointMasks.any((mask) => mask.containsAll(classWorld)); |
- } |
- |
- ClassElement singleClass(ClassWorld classWorld) => null; |
- |
- bool needsNoSuchMethodHandling(Selector selector, ClassWorld classWorld) { |
- return disjointMasks.any( |
- (e) => e.needsNoSuchMethodHandling(selector, classWorld)); |
- } |
- |
- bool canHit(Element element, Selector selector, ClassWorld classWorld) { |
- return disjointMasks.any((e) => e.canHit(element, selector, classWorld)); |
- } |
- |
- Element locateSingleElement(Selector selector, Compiler compiler) { |
- Element candidate; |
- for (FlatTypeMask mask in disjointMasks) { |
- Element current = mask.locateSingleElement(selector, compiler); |
- if (current == null) { |
- return null; |
- } else if (candidate == null) { |
- candidate = current; |
- } else if (candidate != current) { |
- return null; |
- } |
- } |
- return candidate; |
- } |
- |
- String toString() { |
- String masksString = (disjointMasks.map((TypeMask mask) => mask.toString()) |
- .toList()..sort()).join(", "); |
- return 'Union of [$masksString]'; |
- } |
- |
- bool operator==(other) { |
- if (identical(this, other)) return true; |
- |
- bool containsAll() { |
- return other.disjointMasks.every((e) { |
- var map = disjointMasks.map((e) => e.nonNullable()); |
- return map.contains(e.nonNullable()); |
- }); |
- } |
- |
- return other is UnionTypeMask |
- && other.isNullable == isNullable |
- && other.disjointMasks.length == disjointMasks.length |
- && containsAll(); |
- } |
- |
- int get hashCode { |
- int hashCode = isNullable ? 86 : 43; |
- // The order of the masks in [disjointMasks] must not affect the |
- // hashCode. |
- for (var mask in disjointMasks) { |
- hashCode = (hashCode ^ mask.nonNullable().hashCode) & 0x3fffffff; |
- } |
- return hashCode; |
- } |
-} |