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

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

Issue 14997006: Introduce a UnionTypeMask, currently limited to 4 types. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 7 years, 7 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
Index: sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart
===================================================================
--- sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart (revision 0)
+++ sdk/lib/_internal/compiler/implementation/types/union_type_mask.dart (revision 0)
@@ -0,0 +1,257 @@
+// 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._(this.disjointMasks);
+
+ static TypeMask unionOf(Iterable<TypeMask> masks, Compiler compiler) {
+ List<FlatTypeMask> disjoint = <FlatTypeMask>[];
+ unionOfHelper(masks, disjoint, compiler);
+ if (disjoint.isEmpty) return new TypeMask.nonNullEmpty();
+ if (disjoint.length > MAX_UNION_LENGTH) return flatten(disjoint, compiler);
+ if (disjoint.length == 1) return disjoint[0];
+ return new UnionTypeMask._(disjoint);
+ }
+
+ static void unionOfHelper(Iterable<TypeMask> masks,
+ List<FlatTypeMask> disjoint,
+ Compiler compiler) {
+ for (TypeMask mask in masks) {
+ if (mask.isUnion) {
+ UnionTypeMask union = mask;
+ unionOfHelper(union.disjointMasks, disjoint, compiler);
+ } else if (mask.isEmpty && !mask.isNullable) {
+ continue;
+ } else {
+ assert(mask.base == null || mask.base.element != compiler.dynamicClass);
+ assert(mask is FlatTypeMask);
+ 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 = mask.union(current, compiler);
+ // 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;
+ mask = 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(mask);
+ }
+ }
+ }
+
+ static TypeMask flatten(List<FlatTypeMask> masks, Compiler compiler) {
+ 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);
+
+ // Compute the common supertypes of the two types.
+ ClassElement firstElement = masks[0].base.element;
+ ClassElement secondElement = masks[1].base.element;
+ Iterable<ClassElement> candidates =
+ compiler.world.commonSupertypesOf(firstElement, secondElement);
+ for (int i = 2; i < masks.length; i++) {
+ ClassElement element = masks[i].base.element;
+ Set<ClassElement> supertypes = compiler.world.supertypesOf(element);
+ if (supertypes == null) {
+ candidates.clear();
+ break;
+ }
+ candidates = candidates.where((e) => supertypes.contains(e));
+ }
+
+ if (candidates.isEmpty) {
+ // TODO(kasperl): Get rid of this check. It can only happen when
+ // at least one of the two base types is 'unseen'.
+ return new TypeMask(compiler.objectClass.rawType,
+ FlatTypeMask.SUBCLASS,
+ isNullable);
+ }
+ // Compute the best candidate and its kind.
+ ClassElement bestElement;
+ int bestKind;
+ int bestSize;
+ for (ClassElement candidate in candidates) {
+ Set<ClassElement> subclasses = useSubclass
+ ? compiler.world.subclassesOf(candidate)
+ : null;
+ int size;
+ int kind;
+ if (subclasses != null
+ && masks.every((t) => subclasses.contains(t.base.element))) {
+ // 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 <= compiler.world.subtypesOf(candidate).length);
+ } else {
+ kind = FlatTypeMask.SUBTYPE;
+ size = compiler.world.subtypesOf(candidate).length;
+ }
+ // Update the best candidate if the new one is better.
+ if (bestElement == null || size < bestSize) {
+ bestElement = candidate;
+ bestSize = size;
+ bestKind = kind;
+ }
+ }
+ if (bestElement == compiler.objectClass) bestKind = FlatTypeMask.SUBCLASS;
+ return new TypeMask(bestElement.computeType(compiler),
+ bestKind,
+ isNullable);
+ }
+
+ TypeMask union(var other, Compiler compiler) {
+ 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, compiler);
+ }
+
+ TypeMask intersection(var other, Compiler compiler) {
+ 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, compiler));
+ }
+ } else {
+ intersections.add(current.intersection(other, compiler));
+ }
+ }
+ return new TypeMask.unionOf(intersections, compiler);
+ }
+
+ TypeMask nullable() {
+ if (isNullable) return this;
+ List<FlatTypeMask> newList = new List<FlatTypeMask>.from(disjointMasks);
+ newList[0] = newList[0].nullable();
+ return new UnionTypeMask._(newList);
+ }
+
+ TypeMask nonNullable() {
+ if (!isNullable) return this;
+ Iterable<FlatTypeMask> newIterable =
+ disjointMasks.map((e) => e.nonNullable());
+ return new UnionTypeMask._(newIterable);
+ }
+
+ TypeMask simplify(Compiler compiler) => flatten(disjointMasks, compiler);
+
+ bool get isEmpty => false;
+ bool get isNullable => disjointMasks.any((e) => e.isNullable);
+ bool get isExact => false;
+ bool get isUnion => true;
+
+ bool containsOnlyInt(Compiler compiler) => false;
+ bool containsOnlyDouble(Compiler compiler) => false;
+ bool containsOnlyNum(Compiler compiler) {
+ return disjointMasks.every((mask) {
+ return mask.containsOnlyInt(compiler)
+ || mask.containsOnlyDouble(compiler)
+ || mask.containsOnlyNum(compiler);
+ });
+ }
+ bool containsOnlyNull(Compiler compiler) => false;
+ bool containsOnlyBool(Compiler compiler) => false;
+ bool containsOnlyString(Compiler compiler) => false;
+ bool containsOnly(ClassElement element) => false;
+ bool satisfies(ClassElement cls, Compiler compiler) {
+ return disjointMasks.every((mask) => mask.satisfies(cls, compiler));
+ }
+
+ bool contains(DartType type, Compiler compiler) {
+ return disjointMasks.any((e) => e.contains(type, compiler));
+ }
+
+ bool containsAll(Compiler compiler) => false;
+
+ ClassElement singleClass(Compiler compiler) => null;
+
+ Set<ClassElement> containedClasses(Compiler compiler) {
+ Set<ClassElement> set = new Set<ClassElement>();
+ disjointMasks.forEach((e) => set.addAll(e.containedClasses(compiler)));
+ return set;
+ }
+
+ /**
+ * Returns whether a [selector] call will hit a method at runtime,
+ * and not go through [noSuchMethod].
+ */
+ bool willHit(Selector selector, Compiler compiler) {
+ return disjointMasks.every((e) => e.willHit(selector, compiler));
+ }
+
+ bool canHit(Element element, Selector selector, Compiler compiler) {
+ return disjointMasks.any((e) => e.canHit(element, selector, compiler));
+ }
+
+ 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() => 'Union of $disjointMasks';
+
+ bool operator==(other) {
+ if (identical(this, other)) return true;
+ return other is UnionTypeMask
+ && other.disjointMasks.length == disjointMasks.length
+ && other.disjointMasks.every((e) => disjointMasks.contains(e));
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698