private static void resolvedTemplateType( Map<TemplateType, JSType> map, TemplateType template, JSType resolved) { JSType previous = map.get(template); if (!resolved.isUnknownType()) { if (previous == null) { map.put(template, resolved); } else { JSType join = previous.getLeastSupertype(resolved); map.put(template, join); } } }
private static void resolvedTemplateType( Map<TemplateType, JSType> map, TemplateType template, JSType resolved) { JSType previous = map.get(template); if (!resolved.isUnknownType()) { if (previous == null) { map.put(template, resolved); } else { JSType join = previous.getLeastSupertype(resolved); map.put(template, join); } } }
@Override public JSType caseUnionType(UnionType type) { JSType restricted = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; }
@Override public JSType getLeastSupertype(JSType that) { if (!that.isUnknownType() && !that.isUnionType()) { for (int i = 0; i < alternatesRetainingStructuralSubtypes.size(); i++) { JSType alternate = alternatesRetainingStructuralSubtypes.get(i); if (!alternate.isUnknownType() && that.isSubtypeOf(alternate)) { return this; } } } return JSType.getLeastSupertype(this, that); }
@Override public JSType caseUnionType(UnionType type) { JSType restricted = null; for (JSType alternate : type.getAlternates()) { JSType restrictedAlternate = alternate.visit(this); if (restrictedAlternate != null) { if (restricted == null) { restricted = restrictedAlternate; } else { restricted = restrictedAlternate.getLeastSupertype(restricted); } } } return restricted; }
/** * Gets the least supertype of {@code this} and {@code that}. * The least supertype is the join (∨) or supremum of both types in the * type lattice.<p> * Examples: * <ul> * <li><code>number ∨ *</code> = {@code *}</li> * <li><code>number ∨ Object</code> = {@code (number, Object)}</li> * <li><code>Number ∨ Object</code> = {@code Object}</li> * </ul> * @return <code>this ∨ that</code> */ public JSType getLeastSupertype(JSType that) { if (that.isUnionType()) { // Union types have their own implementation of getLeastSupertype. return that.toMaybeUnionType().getLeastSupertype(this); } return getLeastSupertype(this, that); }
@Override public JSType findPropertyType(String propertyName) { JSType propertyType = null; for (JSType alternate : getAlternates()) { // Filter out the null/undefined type. if (alternate.isNullType() || alternate.isVoidType()) { continue; } JSType altPropertyType = alternate.findPropertyType(propertyName); if (altPropertyType == null) { continue; } if (propertyType == null) { propertyType = altPropertyType; } else { propertyType = propertyType.getLeastSupertype(altPropertyType); } } return propertyType; }
@Override protected JSType findPropertyTypeWithoutConsideringTemplateTypes(String propertyName) { JSType propertyType = null; for (JSType alternate : getAlternates()) { // Filter out the null/undefined type. if (alternate.isNullType() || alternate.isVoidType()) { continue; } JSType altPropertyType = alternate.findPropertyType(propertyName); if (altPropertyType == null) { continue; } if (propertyType == null) { propertyType = altPropertyType; } else { propertyType = propertyType.getLeastSupertype(altPropertyType); } } return propertyType; }
return unwrap(blindScope); JSType type = leftVar.getType().getLeastSupertype(rightVar.getType()); return unwrap(blindScope).inferSlotType(leftVar.getName(), type);
public void matchRecordTypeConstraint(ObjectType constraintObj) { for (String prop : constraintObj.getOwnPropertyNames()) { JSType propType = constraintObj.getPropertyType(prop); if (!isPropertyTypeDeclared(prop)) { JSType typeToInfer = propType; if (!hasProperty(prop)) { typeToInfer = getNativeType(JSTypeNative.VOID_TYPE) .getLeastSupertype(propType); } defineInferredProperty(prop, typeToInfer, null); } } }
public void matchRecordTypeConstraint(ObjectType constraintObj) { for (String prop : constraintObj.getOwnPropertyNames()) { JSType propType = constraintObj.getPropertyType(prop); if (!isPropertyTypeDeclared(prop)) { JSType typeToInfer = propType; if (!hasProperty(prop)) { typeToInfer = getNativeType(JSTypeNative.VOID_TYPE) .getLeastSupertype(propType); } defineInferredProperty(prop, typeToInfer, null); } } }
case BOTH: result.setJSType(leftType.getLeastSupertype(rightType)); break; default:
/** * Gets the least supertype of {@code this} and {@code that}. The least supertype is the join * (∨) or supremum of both types in the type lattice. * * <p>Examples: * * <ul> * <li><code>number ∨ *</code> = {@code *} * <li><code>number ∨ Object</code> = {@code (number, Object)} * <li><code>Number ∨ Object</code> = {@code Object} * </ul> * * @return <code>this ∨ that</code> */ @SuppressWarnings("AmbiguousMethodReference") public JSType getLeastSupertype(JSType that) { if (areIdentical(this, that)) { return this; } that = filterNoResolvedType(that); if (that.isUnionType()) { // Union types have their own implementation of getLeastSupertype. return that.toMaybeUnionType().getLeastSupertype(this); } return getLeastSupertype(this, that); }
/** * Defines a property whose type is inferred. * @param propertyName the property's name * @param type the type * @param propertyNode the node corresponding to the inferred definition of * property that might later be accessed using {@code getPropertyNode}. */ public final boolean defineInferredProperty(String propertyName, JSType type, Node propertyNode) { if (hasProperty(propertyName)) { if (isPropertyTypeDeclared(propertyName)) { // We never want to hide a declared property with an inferred property. return true; } JSType originalType = getPropertyType(propertyName); type = originalType == null ? type : originalType.getLeastSupertype(type); } boolean result = defineProperty(propertyName, type, true, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; }
case BOTH: result.setJSType(leftType.getLeastSupertype(rightType)); break; default:
/** * Defines a property whose type is inferred. * @param propertyName the property's name * @param type the type * @param propertyNode the node corresponding to the inferred definition of * property that might later be accessed using {@code getPropertyNode}. */ public final boolean defineInferredProperty(String propertyName, JSType type, Node propertyNode) { if (hasProperty(propertyName)) { if (isPropertyTypeDeclared(propertyName)) { // We never want to hide a declared property with an inferred property. return true; } JSType originalType = getPropertyType(propertyName); type = originalType == null ? type : originalType.getLeastSupertype(type); } boolean result = defineProperty(propertyName, type, true, propertyNode); // All property definitions go through this method // or defineDeclaredProperty. Because the properties defined an an // object can affect subtyping, it's slightly more efficient // to register this after defining the property. registry.registerPropertyOnType(propertyName, this); return result; }
? call.returnType.getLeastSupertype(other.call.returnType) : call.returnType.getGreatestSubtype(other.call.returnType); JSType maybeNewTypeOfThis = leastSuper ? typeOfThis.getLeastSupertype(other.typeOfThis) : typeOfThis.getGreatestSubtype(other.typeOfThis); newTypeOfThis = maybeNewTypeOfThis;
private FlowScope caseAndOrMaybeShortCircuiting(Node left, Node right, FlowScope blindScope, boolean outcome) { FlowScope leftScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, !outcome); StaticTypedSlot<JSType> leftVar = leftScope.findUniqueRefinedSlot(blindScope); if (leftVar == null) { // If we did create a more precise scope, blindScope has a child and // it is frozen. We can't just throw it away to return it. So we // must create a child instead. return blindScope == leftScope ? blindScope : blindScope.createChildFlowScope(); } FlowScope rightScope = firstPreciserScopeKnowingConditionOutcome( left, blindScope, outcome); rightScope = firstPreciserScopeKnowingConditionOutcome( right, rightScope, !outcome); StaticTypedSlot<JSType> rightVar = rightScope.findUniqueRefinedSlot(blindScope); if (rightVar == null || !leftVar.getName().equals(rightVar.getName())) { return blindScope == rightScope ? blindScope : blindScope.createChildFlowScope(); } JSType type = leftVar.getType().getLeastSupertype(rightVar.getType()); FlowScope informed = blindScope.createChildFlowScope(); informed.inferSlotType(leftVar.getName(), type); return informed; }
private FlowScope traverseHook(Node n, FlowScope scope) { Node condition = n.getFirstChild(); Node trueNode = condition.getNext(); Node falseNode = n.getLastChild(); // verify the condition scope = traverse(condition, scope); // reverse abstract interpret the condition to produce two new scopes FlowScope trueScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, true); FlowScope falseScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, false); // traverse the true node with the trueScope traverse(trueNode, trueScope); // traverse the false node with the falseScope traverse(falseNode, falseScope); // meet true and false nodes' types and assign JSType trueType = trueNode.getJSType(); JSType falseType = falseNode.getJSType(); if (trueType != null && falseType != null) { n.setJSType(trueType.getLeastSupertype(falseType)); } else { n.setJSType(null); } return scope; }
private FlowScope traverseHook(Node n, FlowScope scope) { Node condition = n.getFirstChild(); Node trueNode = condition.getNext(); Node falseNode = n.getLastChild(); // verify the condition scope = traverse(condition, scope); // reverse abstract interpret the condition to produce two new scopes FlowScope trueScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, true); FlowScope falseScope = reverseInterpreter. getPreciserScopeKnowingConditionOutcome( condition, scope, false); // traverse the true node with the trueScope traverse(trueNode, trueScope.createChildFlowScope()); // traverse the false node with the falseScope traverse(falseNode, falseScope.createChildFlowScope()); // meet true and false nodes' types and assign JSType trueType = trueNode.getJSType(); JSType falseType = falseNode.getJSType(); if (trueType != null && falseType != null) { n.setJSType(trueType.getLeastSupertype(falseType)); } else { n.setJSType(null); } return scope.createChildFlowScope(); }