diff --git a/src/com/google/javascript/rhino/jstype/JSType.java b/src/com/google/javascript/rhino/jstype/JSType.java index e595959c69d..98e30edaa4c 100644 --- a/src/com/google/javascript/rhino/jstype/JSType.java +++ b/src/com/google/javascript/rhino/jstype/JSType.java @@ -44,14 +44,13 @@ import com.google.common.base.Preconditions; import com.google.common.base.Predicate; import com.google.common.collect.HashBasedTable; -import com.google.common.collect.ImmutableSet; +import com.google.common.collect.ImmutableList; import com.google.javascript.rhino.ErrorReporter; import com.google.javascript.rhino.JSDocInfo; import com.google.javascript.rhino.TypeI; import java.io.Serializable; import java.util.Comparator; import java.util.IdentityHashMap; -import java.util.List; /** * Represents JavaScript value types.

@@ -79,8 +78,8 @@ public abstract class JSType implements TypeI, Serializable { private static final CanCastToVisitor CAN_CAST_TO_VISITOR = new CanCastToVisitor(); - private static final ImmutableSet COVARIANT_TYPES = - ImmutableSet.of("Object", "IArrayLike", "Array"); + private static final ImmutableList COVARIANT_TYPES = + ImmutableList.of("Object", "IArrayLike", "Array"); /** * Total ordering on types based on their textual representation. @@ -303,9 +302,7 @@ public boolean containsArray() { // Check if this is a union that contains an array if (this.isUnionType()) { JSType arrayType = registry.getNativeType(JSTypeNative.ARRAY_TYPE); - List alternates = this.toMaybeUnionType().getAlternates(); - for (int i = 0; i < alternates.size(); i++) { - JSType alternate = alternates.get(i); + for (JSType alternate : this.toMaybeUnionType().getAlternates()) { if (alternate.isSubtype(arrayType)) { return true; } @@ -1129,9 +1126,7 @@ static JSType filterNoResolvedType(JSType type) { } else if (type.isUnionType()) { UnionType unionType = type.toMaybeUnionType(); boolean needsFiltering = false; - List alternates = unionType.getAlternates(); - for (int i = 0; i < alternates.size(); i++) { - JSType alt = alternates.get(i); + for (JSType alt : unionType.getAlternates()) { if (alt.isNoResolvedType()) { needsFiltering = true; break; @@ -1411,10 +1406,8 @@ static boolean isSubtypeHelper(JSType thisType, JSType thatType, // unions if (thatType.isUnionType()) { UnionType union = thatType.toMaybeUnionType(); - List alternates = union.alternatesWithoutStucturalTyping; - // use indexed iteration to avoid iterator allocations - for (int i = 0; i < alternates.size(); i++) { - if (thisType.isSubtype(alternates.get(i), implicitImplCache, subtypingMode)) { + for (JSType element : union.alternatesWithoutStucturalTyping) { + if (thisType.isSubtype(element, implicitImplCache, subtypingMode)) { return true; } } diff --git a/src/com/google/javascript/rhino/jstype/UnionType.java b/src/com/google/javascript/rhino/jstype/UnionType.java index 1d640203d82..0b852d92aed 100644 --- a/src/com/google/javascript/rhino/jstype/UnionType.java +++ b/src/com/google/javascript/rhino/jstype/UnionType.java @@ -44,7 +44,9 @@ import com.google.common.base.Joiner; import com.google.common.base.Predicate; import com.google.javascript.rhino.ErrorReporter; + import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.SortedSet; import java.util.TreeSet; @@ -60,29 +62,26 @@ * statement is captured by making {@code (String,boolean)} and * {@code (boolean,String)} equal.

* - * * The implementation of this class prevents the creation of nested * unions.

*/ public class UnionType extends JSType { private static final long serialVersionUID = 1L; - // NOTE: to avoid allocating iterators, all the loops below iterate over alternates by index - // instead of using the for-each loop idiom. - // alternates without merging structural interfaces and their subtypes - List alternatesWithoutStucturalTyping; + Collection alternatesWithoutStucturalTyping; // alternates under structural typing - List alternates; + Collection alternates; private int hashcode; /** * Creates a union type. * - * @param alternatesWithoutStructuralTyping the alternates of the union without structural typing - * subtype + * @param alternatesWithoutStructuralTyping the alternates of the union without + * structural typing subtype */ - UnionType(JSTypeRegistry registry, List alternatesWithoutStructuralTyping) { + UnionType(JSTypeRegistry registry, + Collection alternatesWithoutStructuralTyping) { super(registry); this.alternatesWithoutStucturalTyping = alternatesWithoutStructuralTyping; @@ -96,12 +95,11 @@ public class UnionType extends JSType { /** * Gets the alternate types of this union type. - * - * @return The alternate types of this union type. The returned set is immutable. + * @return The alternate types of this union type. The returned set is + * immutable. */ - public List getAlternates() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + public Collection getAlternates() { + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isUnionType()) { rebuildAlternates(); break; @@ -111,14 +109,13 @@ public List getAlternates() { } /** - * Gets the alternate types of this union type, including structural interfaces and implicit - * implementations as are distinct alternates. - * - * @return The alternate types of this union type. The returned set is immutable. + * Gets the alternate types of this union type, including structural interfaces + * and implicit implementations as are distinct alternates. + * @return The alternate types of this union type. The returned set is + * immutable. */ - public List getAlternatesWithoutStructuralTyping() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + public Collection getAlternatesWithoutStructuralTyping() { + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isUnionType()) { rebuildAlternates(); break; @@ -238,8 +235,7 @@ public JSType findPropertyType(String propertyName) { @Override public boolean canBeCalled() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { if (!t.canBeCalled()) { return false; } @@ -250,8 +246,7 @@ public boolean canBeCalled() { @Override public JSType autobox() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { restricted.addAlternate(t.autobox()); } return restricted.build(); @@ -260,8 +255,7 @@ public JSType autobox() { @Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); @@ -270,8 +264,7 @@ public JSType restrictByNotNullOrUndefined() { @Override public TernaryValue testForEquality(JSType that) { TernaryValue result = null; - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { TernaryValue test = t.testForEquality(that); if (result == null) { result = test; @@ -292,8 +285,7 @@ public TernaryValue testForEquality(JSType that) { */ @Override public boolean isNullable() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isNullable()) { return true; } @@ -306,8 +298,7 @@ public boolean isNullable() { */ @Override public boolean isVoidable() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isVoidable()) { return true; } @@ -320,8 +311,7 @@ public boolean isVoidable() { */ @Override public boolean isExplicitlyVoidable() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isExplicitlyVoidable()) { return true; } @@ -331,8 +321,7 @@ public boolean isExplicitlyVoidable() { @Override public boolean isUnknownType() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { if (t.isUnknownType()) { return true; } @@ -342,9 +331,7 @@ public boolean isUnknownType() { @Override public boolean isStruct() { - List alternates = getAlternates(); - for (int i = 0; i < alternates.size(); i++) { - JSType typ = alternates.get(i); + for (JSType typ : getAlternates()) { if (typ.isStruct()) { return true; } @@ -354,9 +341,7 @@ public boolean isStruct() { @Override public boolean isDict() { - List alternates = getAlternates(); - for (int i = 0; i < alternates.size(); i++) { - JSType typ = alternates.get(i); + for (JSType typ : getAlternates()) { if (typ.isDict()) { return true; } @@ -367,8 +352,7 @@ public boolean isDict() { @Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { if (!alternate.isUnknownType() && that.isSubtype(alternate)) { return this; } @@ -380,18 +364,14 @@ public JSType getLeastSupertype(JSType that) { JSType meet(JSType that) { UnionTypeBuilder builder = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that.isUnionType()) { - List thoseAlternatesWithoutStucturalTyping = - that.toMaybeUnionType().alternatesWithoutStucturalTyping; - for (int i = 0; i < thoseAlternatesWithoutStucturalTyping.size(); i++) { - JSType otherAlternate = thoseAlternatesWithoutStucturalTyping.get(i); + for (JSType otherAlternate : that.toMaybeUnionType().alternatesWithoutStucturalTyping) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } @@ -415,14 +395,13 @@ JSType meet(JSType that) { */ boolean checkUnionEquivalenceHelper( UnionType that, EquivalenceMethod eqMethod, EqCache eqCache) { - List thatAlternates = that.getAlternatesWithoutStructuralTyping(); + Collection thatAlternates = that.getAlternatesWithoutStructuralTyping(); if (eqMethod == EquivalenceMethod.IDENTITY && getAlternatesWithoutStructuralTyping().size() != thatAlternates.size()) { return false; } - for (int i = 0; i < thatAlternates.size(); i++) { - JSType thatAlternate = thatAlternates.get(i); - if (!hasAlternate(thatAlternate, eqMethod, eqCache)) { + for (JSType alternate : thatAlternates) { + if (!hasAlternate(alternate, eqMethod, eqCache)) { return false; } } @@ -431,9 +410,7 @@ && getAlternatesWithoutStructuralTyping().size() != thatAlternates.size()) { private boolean hasAlternate(JSType type, EquivalenceMethod eqMethod, EqCache eqCache) { - List alternatesWithoutStructuralTyping = getAlternatesWithoutStructuralTyping(); - for (int i = 0; i < alternatesWithoutStructuralTyping.size(); i++) { - JSType alternate = alternatesWithoutStructuralTyping.get(i); + for (JSType alternate : getAlternatesWithoutStructuralTyping()) { if (alternate.checkEquivalenceHelper(type, eqMethod, eqCache)) { return true; } @@ -443,8 +420,7 @@ private boolean hasAlternate(JSType type, EquivalenceMethod eqMethod, @Override public boolean hasProperty(String pname) { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { if (alternate.hasProperty(pname)) { return true; } @@ -464,8 +440,7 @@ public UnionType toMaybeUnionType() { @Override public boolean isObject() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { if (!alternate.isObject()) { return false; } @@ -482,8 +457,7 @@ public boolean isObject() { * @return {@code true} if the alternate is in the union */ public boolean contains(JSType type) { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alt = alternatesWithoutStucturalTyping.get(i); + for (JSType alt : alternatesWithoutStucturalTyping) { if (alt.isEquivalentTo(type)) { return true; } @@ -507,8 +481,7 @@ public boolean contains(JSType type) { */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType t = alternatesWithoutStucturalTyping.get(i); + for (JSType t : alternatesWithoutStucturalTyping) { // Keep all unknown/unresolved types. if (t.isUnknownType() || t.isNoResolvedType() || !t.isSubtype(type)) { restricted.addAlternate(t); @@ -551,8 +524,7 @@ protected boolean isSubtype(JSType that, if (that.isAllType()) { return true; } - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { if (subtypingMode == SubtypingMode.IGNORE_NULL_UNDEFINED && (element.isNullType() || element.isVoidType())) { continue; @@ -568,8 +540,7 @@ protected boolean isSubtype(JSType that, public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { restricted.addAlternate( element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } @@ -579,8 +550,7 @@ public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { @Override public BooleanLiteralSet getPossibleToBooleanOutcomes() { BooleanLiteralSet literals = BooleanLiteralSet.EMPTY; - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { literals = literals.union(element.getPossibleToBooleanOutcomes()); if (literals == BooleanLiteralSet.BOTH) { break; @@ -593,8 +563,7 @@ public BooleanLiteralSet getPossibleToBooleanOutcomes() { public TypePair getTypesUnderEquality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { TypePair p = element.getTypesUnderEquality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); @@ -612,8 +581,7 @@ public TypePair getTypesUnderEquality(JSType that) { public TypePair getTypesUnderInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { TypePair p = element.getTypesUnderInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); @@ -631,8 +599,7 @@ public TypePair getTypesUnderInequality(JSType that) { public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType element = alternatesWithoutStucturalTyping.get(i); + for (JSType element : alternatesWithoutStucturalTyping) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); @@ -659,8 +626,9 @@ public T visit(Visitor visitor) { JSType resolveInternal(ErrorReporter t, StaticTypedScope scope) { setResolvedTypeInternal(this); // for circularly defined types. - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + // Just resolve the alternates, but do not update as that breaks some error + // reporting cases. + for (JSType alternate : alternatesWithoutStucturalTyping) { alternate.resolve(t, scope); } // Ensure the union is in a normalized state. @@ -679,8 +647,7 @@ public String toDebugHashCodeString() { @Override public boolean setValidator(Predicate validator) { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType a = alternatesWithoutStucturalTyping.get(i); + for (JSType a : alternatesWithoutStucturalTyping) { a.setValidator(validator); } return true; @@ -690,8 +657,7 @@ public boolean setValidator(Predicate validator) { public JSType collapseUnion() { JSType currentValue = null; ObjectType currentCommonSuper = null; - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType a = alternatesWithoutStucturalTyping.get(i); + for (JSType a : alternatesWithoutStucturalTyping) { if (a.isUnknownType()) { return getNativeType(JSTypeNative.UNKNOWN_TYPE); } @@ -720,16 +686,14 @@ public JSType collapseUnion() { @Override public void matchConstraint(JSType constraint) { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { alternate.matchConstraint(constraint); } } @Override public boolean hasAnyTemplateTypesInternal() { - for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) { - JSType alternate = alternatesWithoutStucturalTyping.get(i); + for (JSType alternate : alternatesWithoutStucturalTyping) { if (alternate.hasAnyTemplateTypes()) { return true; } diff --git a/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java b/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java index 3a223d3398c..0ab70652e15 100644 --- a/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java +++ b/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java @@ -48,8 +48,10 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.javascript.rhino.jstype.JSType.SubtypingMode; + import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -108,7 +110,7 @@ public UnionTypeBuilder(JSTypeRegistry registry) { this.maxUnionSize = maxUnionSize; } - List getAlternates() { + Collection getAlternates() { JSType specialCaseType = reduceAlternatesWithoutUnion(); if (specialCaseType != null) { return ImmutableList.of(specialCaseType); @@ -159,10 +161,7 @@ public UnionTypeBuilder addAlternate(JSType alternate, boolean isStructural) { if (!isAllType && !isNativeUnknownType) { if (alternate.isUnionType()) { UnionType union = alternate.toMaybeUnionType(); - List alternatesWithoutStructuralTyping = - union.getAlternatesWithoutStructuralTyping(); - for (int i = 0; i < alternatesWithoutStructuralTyping.size(); i++) { - JSType unionAlt = alternatesWithoutStructuralTyping.get(i); + for (JSType unionAlt : union.getAlternatesWithoutStructuralTyping()) { addAlternate(unionAlt); } } else {