class UnionTypeBuilder {
/**
* Adds an alternate to the union type under construction. Returns this
* for easy chaining.
*/
UnionTypeBuilder addAlternate(JSType alternate) {
// build() returns the bottom type by default, so we can
// just bail out early here.
if (alternate.isNoType()) {
return this;
}
isAllType = isAllType || alternate.isAllType();
boolean isAlternateUnknown = alternate instanceof UnknownType;
isNativeUnknownType = isNativeUnknownType || isAlternateUnknown;
if (isAlternateUnknown) {
areAllUnknownsChecked = areAllUnknownsChecked &&
alternate.isCheckedUnknownType();
}
if (!isAllType && !isNativeUnknownType) {
if (alternate instanceof UnionType) {
UnionType union = (UnionType) alternate;
for (JSType unionAlt : union.getAlternates()) {
addAlternate(unionAlt);
}
} else {
if (alternates.size() > MAX_UNION_SIZE) {
return this;
}
// Look through the alternates we've got so far,
// and check if any of them are duplicates of
// one another.
Iterator<JSType> it = alternates.iterator();
while (it.hasNext()) {
JSType current = it.next();
if (alternate.isUnknownType() ||
current.isUnknownType()) {
if (alternate.isEquivalentTo(current)) {
// Alternate is unnecessary.
return this;
}
} else {
if (alternate.isSubtype(current)) {
// Alternate is unnecessary.
return this;
} else if (current.isSubtype(alternate)) {
// Alternate makes current obsolete
it.remove();
}
}
}
alternates.add(alternate);
result = null; // invalidate the memoized result
}
} else {
result = null;
}
return this;
}
}