JSType meet(JSType that) { UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternatesWithoutStucturalTyping) { if (alternate.isSubtype(that)) { builder.addAlternate(alternate); } } if (that.isUnionType()) { for (JSType otherAlternate : that.toMaybeUnionType().alternatesWithoutStucturalTyping) { if (otherAlternate.isSubtype(this)) { builder.addAlternate(otherAlternate); } } } else if (that.isSubtype(this)) { builder.addAlternate(that); } JSType result = builder.build(); if (!result.isNoType()) { return result; } else if (this.isObject() && (that.isObject() && !that.isNoType())) { return getNativeType(JSTypeNative.NO_OBJECT_TYPE); } else { return getNativeType(JSTypeNative.NO_TYPE); } }
@Override public JSType restrictByNotNullOrUndefined() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternatesWithoutStucturalTyping) { restricted.addAlternate(t.restrictByNotNullOrUndefined()); } return restricted.build(); }
@Override public JSType autobox() { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternatesWithoutStucturalTyping) { restricted.addAlternate(t.autobox()); } return restricted.build(); }
@Override public JSType getRestrictedTypeGivenToBooleanOutcome(boolean outcome) { // gather elements after restriction UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType element : alternatesWithoutStucturalTyping) { restricted.addAlternate(element.getRestrictedTypeGivenToBooleanOutcome(outcome)); } return restricted.build(); }
/** * Returns a more restricted union type than {@code this} one, in which all subtypes of {@code * type} have been removed. * * <p>Examples: * * <ul> * <li>{@code (number,string)} restricted by {@code number} is {@code string} * <li>{@code (null, EvalError, URIError)} restricted by {@code Error} is {@code null} * </ul> * * @param type the supertype of the types to remove from this union type */ public JSType getRestrictedUnion(JSType type) { UnionTypeBuilder restricted = new UnionTypeBuilder(registry); for (JSType t : alternatesWithoutStucturalTyping) { // Keep all unknown/unresolved types. if (t.isUnknownType() || t.isNoResolvedType() || !t.isSubtype(type)) { restricted.addAlternate(t); } } return restricted.build(); }
JSType getGreatestSubtypeHelper(JSType that) { if (that.isRecordType()) { RecordType thatRecord = that.toMaybeRecordType(); RecordTypeBuilder builder = new RecordTypeBuilder(registry); builder.setSynthesized(true); // The greatest subtype consists of those *unique* properties of both // record types. If any property conflicts, then the NO_TYPE type // is returned. for (String property : getOwnPropertyNames()) { if (thatRecord.hasProperty(property) && !thatRecord.getPropertyType(property).isInvariant(getPropertyType(property))) { return registry.getNativeObjectType(JSTypeNative.NO_TYPE); } builder.addProperty(property, getPropertyType(property), getPropertyNode(property)); } for (String property : thatRecord.getOwnPropertyNames()) { if (!hasProperty(property)) { builder.addProperty( property, thatRecord.getPropertyType(property), thatRecord.getPropertyNode(property)); } } return builder.build(); } JSType greatestSubtype = registry.getNativeType(JSTypeNative.NO_OBJECT_TYPE); JSType thatRestrictedToObj = registry.getNativeType(JSTypeNative.OBJECT_TYPE).getGreatestSubtype(that); if (!thatRestrictedToObj.isEmptyType()) { // In this branch, the other type is some object type. We find // the greatest subtype with the following algorithm: // 1) For each property "x" of this record type, take the union // of all classes with a property "x" with a compatible property type. // and which are a subtype of {@code that}. // 2) Take the intersection of all of these unions. for (String propName : getOwnPropertyNames()) { JSType propType = getPropertyType(propName); UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (ObjectType alt : registry.getEachReferenceTypeWithProperty(propName)) { JSType altPropType = alt.getPropertyType(propName); if (altPropType != null && !alt.isEquivalentTo(this) && alt.isSubtype(that) && propType.isInvariant(altPropType)) { builder.addAlternate(alt); } } greatestSubtype = greatestSubtype.getLeastSupertype(builder.build()); } } return greatestSubtype; }
/** * Creates a union type. * * @param alternatesWithoutStructuralTyping the alternates of the union without structural typing * subtype */ UnionType(JSTypeRegistry registry, Collection<JSType> alternatesWithoutStructuralTyping) { super(registry); this.alternatesWithoutStucturalTyping = alternatesWithoutStructuralTyping; UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternatesWithoutStructuralTyping) { builder.addAlternate(alternate, true); } this.alternates = builder.getAlternates(); this.hashcode = this.alternatesWithoutStucturalTyping.hashCode(); }
/** * Use UnionTypeBuilder to rebuild the list of alternates and hashcode of the current UnionType. */ private void rebuildAlternates() { UnionTypeBuilder builder = new UnionTypeBuilder(registry); for (JSType alternate : alternatesWithoutStucturalTyping) { builder.addAlternate(alternate); } alternatesWithoutStucturalTyping = builder.getAlternates(); builder = new UnionTypeBuilder(registry); for (JSType alternate : alternatesWithoutStucturalTyping) { builder.addAlternate(alternate, true); } alternates = builder.getAlternates(); hashcode = alternatesWithoutStucturalTyping.hashCode(); }
@Override public TypePair getTypesUnderShallowInequality(JSType that) { UnionTypeBuilder thisRestricted = new UnionTypeBuilder(registry); UnionTypeBuilder thatRestricted = new UnionTypeBuilder(registry); for (JSType element : alternatesWithoutStucturalTyping) { TypePair p = element.getTypesUnderShallowInequality(that); if (p.typeA != null) { thisRestricted.addAlternate(p.typeA); } if (p.typeB != null) { thatRestricted.addAlternate(p.typeB); } } return new TypePair(thisRestricted.build(), thatRestricted.build()); }