diff --git a/src/com/google/javascript/rhino/jstype/JSType.java b/src/com/google/javascript/rhino/jstype/JSType.java
index 98e30edaa4c..e595959c69d 100644
--- a/src/com/google/javascript/rhino/jstype/JSType.java
+++ b/src/com/google/javascript/rhino/jstype/JSType.java
@@ -44,13 +44,14 @@
import com.google.common.base.Preconditions;
import com.google.common.base.Predicate;
import com.google.common.collect.HashBasedTable;
-import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
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.
@@ -78,8 +79,8 @@ public abstract class JSType implements TypeI, Serializable {
private static final CanCastToVisitor CAN_CAST_TO_VISITOR =
new CanCastToVisitor();
- private static final ImmutableList COVARIANT_TYPES =
- ImmutableList.of("Object", "IArrayLike", "Array");
+ private static final ImmutableSet COVARIANT_TYPES =
+ ImmutableSet.of("Object", "IArrayLike", "Array");
/**
* Total ordering on types based on their textual representation.
@@ -302,7 +303,9 @@ public boolean containsArray() {
// Check if this is a union that contains an array
if (this.isUnionType()) {
JSType arrayType = registry.getNativeType(JSTypeNative.ARRAY_TYPE);
- for (JSType alternate : this.toMaybeUnionType().getAlternates()) {
+ List alternates = this.toMaybeUnionType().getAlternates();
+ for (int i = 0; i < alternates.size(); i++) {
+ JSType alternate = alternates.get(i);
if (alternate.isSubtype(arrayType)) {
return true;
}
@@ -1126,7 +1129,9 @@ static JSType filterNoResolvedType(JSType type) {
} else if (type.isUnionType()) {
UnionType unionType = type.toMaybeUnionType();
boolean needsFiltering = false;
- for (JSType alt : unionType.getAlternates()) {
+ List alternates = unionType.getAlternates();
+ for (int i = 0; i < alternates.size(); i++) {
+ JSType alt = alternates.get(i);
if (alt.isNoResolvedType()) {
needsFiltering = true;
break;
@@ -1406,8 +1411,10 @@ static boolean isSubtypeHelper(JSType thisType, JSType thatType,
// unions
if (thatType.isUnionType()) {
UnionType union = thatType.toMaybeUnionType();
- for (JSType element : union.alternatesWithoutStucturalTyping) {
- if (thisType.isSubtype(element, implicitImplCache, subtypingMode)) {
+ 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)) {
return true;
}
}
diff --git a/src/com/google/javascript/rhino/jstype/UnionType.java b/src/com/google/javascript/rhino/jstype/UnionType.java
index 0b852d92aed..1d640203d82 100644
--- a/src/com/google/javascript/rhino/jstype/UnionType.java
+++ b/src/com/google/javascript/rhino/jstype/UnionType.java
@@ -44,9 +44,7 @@
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;
@@ -62,26 +60,29 @@
* 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
- Collection alternatesWithoutStucturalTyping;
+ List alternatesWithoutStucturalTyping;
// alternates under structural typing
- Collection alternates;
+ List 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,
- Collection alternatesWithoutStructuralTyping) {
+ UnionType(JSTypeRegistry registry, List alternatesWithoutStructuralTyping) {
super(registry);
this.alternatesWithoutStucturalTyping = alternatesWithoutStructuralTyping;
@@ -95,11 +96,12 @@ 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 Collection getAlternates() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ public List getAlternates() {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isUnionType()) {
rebuildAlternates();
break;
@@ -109,13 +111,14 @@ public Collection 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 Collection getAlternatesWithoutStructuralTyping() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ public List getAlternatesWithoutStructuralTyping() {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isUnionType()) {
rebuildAlternates();
break;
@@ -235,7 +238,8 @@ public JSType findPropertyType(String propertyName) {
@Override
public boolean canBeCalled() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (!t.canBeCalled()) {
return false;
}
@@ -246,7 +250,8 @@ public boolean canBeCalled() {
@Override
public JSType autobox() {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
restricted.addAlternate(t.autobox());
}
return restricted.build();
@@ -255,7 +260,8 @@ public JSType autobox() {
@Override
public JSType restrictByNotNullOrUndefined() {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
restricted.addAlternate(t.restrictByNotNullOrUndefined());
}
return restricted.build();
@@ -264,7 +270,8 @@ public JSType restrictByNotNullOrUndefined() {
@Override
public TernaryValue testForEquality(JSType that) {
TernaryValue result = null;
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
TernaryValue test = t.testForEquality(that);
if (result == null) {
result = test;
@@ -285,7 +292,8 @@ public TernaryValue testForEquality(JSType that) {
*/
@Override
public boolean isNullable() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isNullable()) {
return true;
}
@@ -298,7 +306,8 @@ public boolean isNullable() {
*/
@Override
public boolean isVoidable() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isVoidable()) {
return true;
}
@@ -311,7 +320,8 @@ public boolean isVoidable() {
*/
@Override
public boolean isExplicitlyVoidable() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isExplicitlyVoidable()) {
return true;
}
@@ -321,7 +331,8 @@ public boolean isExplicitlyVoidable() {
@Override
public boolean isUnknownType() {
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
if (t.isUnknownType()) {
return true;
}
@@ -331,7 +342,9 @@ public boolean isUnknownType() {
@Override
public boolean isStruct() {
- for (JSType typ : getAlternates()) {
+ List alternates = getAlternates();
+ for (int i = 0; i < alternates.size(); i++) {
+ JSType typ = alternates.get(i);
if (typ.isStruct()) {
return true;
}
@@ -341,7 +354,9 @@ public boolean isStruct() {
@Override
public boolean isDict() {
- for (JSType typ : getAlternates()) {
+ List alternates = getAlternates();
+ for (int i = 0; i < alternates.size(); i++) {
+ JSType typ = alternates.get(i);
if (typ.isDict()) {
return true;
}
@@ -352,7 +367,8 @@ public boolean isDict() {
@Override
public JSType getLeastSupertype(JSType that) {
if (!that.isUnknownType() && !that.isUnionType()) {
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
if (!alternate.isUnknownType() && that.isSubtype(alternate)) {
return this;
}
@@ -364,14 +380,18 @@ public JSType getLeastSupertype(JSType that) {
JSType meet(JSType that) {
UnionTypeBuilder builder = new UnionTypeBuilder(registry);
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
if (alternate.isSubtype(that)) {
builder.addAlternate(alternate);
}
}
if (that.isUnionType()) {
- for (JSType otherAlternate : that.toMaybeUnionType().alternatesWithoutStucturalTyping) {
+ List thoseAlternatesWithoutStucturalTyping =
+ that.toMaybeUnionType().alternatesWithoutStucturalTyping;
+ for (int i = 0; i < thoseAlternatesWithoutStucturalTyping.size(); i++) {
+ JSType otherAlternate = thoseAlternatesWithoutStucturalTyping.get(i);
if (otherAlternate.isSubtype(this)) {
builder.addAlternate(otherAlternate);
}
@@ -395,13 +415,14 @@ JSType meet(JSType that) {
*/
boolean checkUnionEquivalenceHelper(
UnionType that, EquivalenceMethod eqMethod, EqCache eqCache) {
- Collection thatAlternates = that.getAlternatesWithoutStructuralTyping();
+ List thatAlternates = that.getAlternatesWithoutStructuralTyping();
if (eqMethod == EquivalenceMethod.IDENTITY
&& getAlternatesWithoutStructuralTyping().size() != thatAlternates.size()) {
return false;
}
- for (JSType alternate : thatAlternates) {
- if (!hasAlternate(alternate, eqMethod, eqCache)) {
+ for (int i = 0; i < thatAlternates.size(); i++) {
+ JSType thatAlternate = thatAlternates.get(i);
+ if (!hasAlternate(thatAlternate, eqMethod, eqCache)) {
return false;
}
}
@@ -410,7 +431,9 @@ && getAlternatesWithoutStructuralTyping().size() != thatAlternates.size()) {
private boolean hasAlternate(JSType type, EquivalenceMethod eqMethod,
EqCache eqCache) {
- for (JSType alternate : getAlternatesWithoutStructuralTyping()) {
+ List alternatesWithoutStructuralTyping = getAlternatesWithoutStructuralTyping();
+ for (int i = 0; i < alternatesWithoutStructuralTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStructuralTyping.get(i);
if (alternate.checkEquivalenceHelper(type, eqMethod, eqCache)) {
return true;
}
@@ -420,7 +443,8 @@ private boolean hasAlternate(JSType type, EquivalenceMethod eqMethod,
@Override
public boolean hasProperty(String pname) {
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
if (alternate.hasProperty(pname)) {
return true;
}
@@ -440,7 +464,8 @@ public UnionType toMaybeUnionType() {
@Override
public boolean isObject() {
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
if (!alternate.isObject()) {
return false;
}
@@ -457,7 +482,8 @@ public boolean isObject() {
* @return {@code true} if the alternate is in the union
*/
public boolean contains(JSType type) {
- for (JSType alt : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alt = alternatesWithoutStucturalTyping.get(i);
if (alt.isEquivalentTo(type)) {
return true;
}
@@ -481,7 +507,8 @@ public boolean contains(JSType type) {
*/
public JSType getRestrictedUnion(JSType type) {
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
- for (JSType t : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType t = alternatesWithoutStucturalTyping.get(i);
// Keep all unknown/unresolved types.
if (t.isUnknownType() || t.isNoResolvedType() || !t.isSubtype(type)) {
restricted.addAlternate(t);
@@ -524,7 +551,8 @@ protected boolean isSubtype(JSType that,
if (that.isAllType()) {
return true;
}
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
if (subtypingMode == SubtypingMode.IGNORE_NULL_UNDEFINED
&& (element.isNullType() || element.isVoidType())) {
continue;
@@ -540,7 +568,8 @@ protected boolean isSubtype(JSType that,
public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
// gather elements after restriction
UnionTypeBuilder restricted = new UnionTypeBuilder(registry);
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
restricted.addAlternate(
element.getRestrictedTypeGivenToBooleanOutcome(outcome));
}
@@ -550,7 +579,8 @@ public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) {
@Override
public BooleanLiteralSet getPossibleToBooleanOutcomes() {
BooleanLiteralSet literals = BooleanLiteralSet.EMPTY;
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
literals = literals.union(element.getPossibleToBooleanOutcomes());
if (literals == BooleanLiteralSet.BOTH) {
break;
@@ -563,7 +593,8 @@ public BooleanLiteralSet getPossibleToBooleanOutcomes() {
public TypePair getTypesUnderEquality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
TypePair p = element.getTypesUnderEquality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
@@ -581,7 +612,8 @@ public TypePair getTypesUnderEquality(JSType that) {
public TypePair getTypesUnderInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
TypePair p = element.getTypesUnderInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
@@ -599,7 +631,8 @@ public TypePair getTypesUnderInequality(JSType that) {
public TypePair getTypesUnderShallowInequality(JSType that) {
UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry);
UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry);
- for (JSType element : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType element = alternatesWithoutStucturalTyping.get(i);
TypePair p = element.getTypesUnderShallowInequality(that);
if (p.typeA != null) {
thisRestricted.addAlternate(p.typeA);
@@ -626,9 +659,8 @@ public T visit(Visitor visitor) {
JSType resolveInternal(ErrorReporter t, StaticTypedScope scope) {
setResolvedTypeInternal(this); // for circularly defined types.
- // Just resolve the alternates, but do not update as that breaks some error
- // reporting cases.
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
alternate.resolve(t, scope);
}
// Ensure the union is in a normalized state.
@@ -647,7 +679,8 @@ public String toDebugHashCodeString() {
@Override
public boolean setValidator(Predicate validator) {
- for (JSType a : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType a = alternatesWithoutStucturalTyping.get(i);
a.setValidator(validator);
}
return true;
@@ -657,7 +690,8 @@ public boolean setValidator(Predicate validator) {
public JSType collapseUnion() {
JSType currentValue = null;
ObjectType currentCommonSuper = null;
- for (JSType a : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType a = alternatesWithoutStucturalTyping.get(i);
if (a.isUnknownType()) {
return getNativeType(JSTypeNative.UNKNOWN_TYPE);
}
@@ -686,14 +720,16 @@ public JSType collapseUnion() {
@Override
public void matchConstraint(JSType constraint) {
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
alternate.matchConstraint(constraint);
}
}
@Override
public boolean hasAnyTemplateTypesInternal() {
- for (JSType alternate : alternatesWithoutStucturalTyping) {
+ for (int i = 0; i < alternatesWithoutStucturalTyping.size(); i++) {
+ JSType alternate = alternatesWithoutStucturalTyping.get(i);
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 0ab70652e15..3a223d3398c 100644
--- a/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java
+++ b/src/com/google/javascript/rhino/jstype/UnionTypeBuilder.java
@@ -48,10 +48,8 @@
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;
@@ -110,7 +108,7 @@ public UnionTypeBuilder(JSTypeRegistry registry) {
this.maxUnionSize = maxUnionSize;
}
- Collection getAlternates() {
+ List getAlternates() {
JSType specialCaseType = reduceAlternatesWithoutUnion();
if (specialCaseType != null) {
return ImmutableList.of(specialCaseType);
@@ -161,7 +159,10 @@ public UnionTypeBuilder addAlternate(JSType alternate, boolean isStructural) {
if (!isAllType && !isNativeUnknownType) {
if (alternate.isUnionType()) {
UnionType union = alternate.toMaybeUnionType();
- for (JSType unionAlt : union.getAlternatesWithoutStructuralTyping()) {
+ List alternatesWithoutStructuralTyping =
+ union.getAlternatesWithoutStructuralTyping();
+ for (int i = 0; i < alternatesWithoutStructuralTyping.size(); i++) {
+ JSType unionAlt = alternatesWithoutStructuralTyping.get(i);
addAlternate(unionAlt);
}
} else {