use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method traverseShortCircuitingBinOp.
private BooleanOutcomePair traverseShortCircuitingBinOp(Node n, Node left, BooleanOutcomePair leftOutcome) {
checkArgument(n.isAnd() || n.isOr() || n.isAssignAnd() || n.isAssignOr());
boolean nIsAnd = n.isAnd() || n.isAssignAnd();
Node right = n.getLastChild();
// type the left node
JSType leftType = left.getJSType();
// reverse abstract interpret the left node to produce the correct
// scope in which to verify the right node
FlowScope rightScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(left, leftOutcome.getOutcomeFlowScope(left.getToken(), nIsAnd), Outcome.forBoolean(nIsAnd));
// type the right node
BooleanOutcomePair rightOutcome = traverseWithinShortCircuitingBinOp(right, rightScope);
JSType rightType = right.getJSType();
JSType type;
BooleanOutcomePair outcome;
if (leftType != null && rightType != null) {
leftType = leftType.getRestrictedTypeGivenOutcome(Outcome.forBoolean(!nIsAnd));
if (leftOutcome.toBooleanOutcomes == BooleanLiteralSet.get(!nIsAnd)) {
// Either n is && and lhs is false, or n is || and lhs is true.
// Use the restricted left type; the right side never gets evaluated.
type = leftType;
outcome = leftOutcome;
} else {
// Use the join of the restricted left type knowing the outcome of the
// ToBoolean predicate and of the right type.
type = leftType.getLeastSupertype(rightType);
outcome = new BooleanOutcomePair(joinBooleanOutcomes(nIsAnd, leftOutcome.toBooleanOutcomes, rightOutcome.toBooleanOutcomes), joinBooleanOutcomes(nIsAnd, leftOutcome.booleanValues, rightOutcome.booleanValues), leftOutcome.getJoinedFlowScope(), rightOutcome.getJoinedFlowScope());
}
// can never actually be returned.
if (outcome.booleanValues == BooleanLiteralSet.EMPTY && getNativeType(BOOLEAN_TYPE).isSubtypeOf(type)) {
// Exclusion only makes sense for a union type.
if (type.isUnionType()) {
type = type.toMaybeUnionType().getRestrictedUnion(getNativeType(BOOLEAN_TYPE));
}
}
} else {
type = unknownType;
outcome = new BooleanOutcomePair(BooleanLiteralSet.BOTH, BooleanLiteralSet.BOTH, leftOutcome.getJoinedFlowScope(), rightOutcome.getJoinedFlowScope());
}
n.setJSType(type);
return outcome;
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method flowThrough.
@Override
@CheckReturnValue
FlowScope flowThrough(Node n, FlowScope input) {
// want to infer anything about this scope.
if (input == bottomScope) {
return input;
}
// This method also does some logic for ES modules right before and after entering/exiting the
// scope rooted at the module. The reasoning for separating out this logic is that we can just
// ignore the actual AST nodes for IMPORT/EXPORT, in most cases, because we have already
// created an abstraction of imports and exports.
Node root = NodeUtil.getEnclosingScopeRoot(n);
// Inferred types of ES module imports/exports aren't knowable until after TypeInference runs.
// First update the type of all imports in the scope, then do flow-sensitive inference, then
// update the implicit '*exports*' object.
Module module = ModuleImportResolver.getModuleFromScopeRoot(compiler.getModuleMap(), compiler, root);
TypedScope syntacticBlockScope = scopeCreator.createScope(root);
if (module != null && module.metadata().isEs6Module()) {
moduleImportResolver.declareEsModuleImports(module, syntacticBlockScope, compiler.getInput(NodeUtil.getInputId(n)));
}
// This logic is not specific to ES modules.
FlowScope output = input.withSyntacticScope(syntacticBlockScope);
output = inferDeclarativelyUnboundVarsWithoutTypes(output);
output = traverse(n, output);
updateModuleScope(module, syntacticBlockScope);
return output;
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method updateTypeWhenEndOfOptChain.
// Uses the startNode's type to selectively join the executed scope with the unexecuted scope, and
// updates the type assigned to `optChain` in `setXAfterChildrenTraversed()`
private FlowScope updateTypeWhenEndOfOptChain(Node optChain, Node startNode, OptChainInfo currentChain, FlowScope executedScope) {
JSType startType = getJSType(startNode);
if (startType.isUnknownType()) {
// Unknown startType: Conditional part may execute. Result type must be unknown.
optChain.setJSType(unknownType);
return join(executedScope, currentChain.unconditionalScope);
} else if (startType.isNullType() || startType.isVoidType()) {
// Conditional part will not execute.
optChain.setJSType(registry.getNativeType(VOID_TYPE));
return currentChain.unconditionalScope;
} else if (!startType.isNullable()) {
// `setXAfterChildrenTraversed()`.
return executedScope;
} else {
// Nullable start: Conditional part may execute. Need to add a VOID_TYPE to the type
// assigned to `optChain` within `setXAfterChildrenTraversed()`.
optChain.setJSType(registry.createUnionType(registry.getNativeType(VOID_TYPE), optChain.getJSType()));
final FlowScope unexecutedScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(startNode, currentChain.unconditionalScope, Outcome.NULLISH);
return join(executedScope, unexecutedScope);
}
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class ClosureReverseAbstractInterpreterTest method testClosureFunction.
private void testClosureFunction(String function, JSType type, JSType trueType, JSType falseType) {
// function(a) where a : type
Node n = compiler.parseTestCode("var a; " + function + "(a)");
Node call = n.getLastChild().getLastChild();
Node name = call.getLastChild();
Node root = IR.root(IR.root(), IR.root(n));
TypedScope scope = new TypedScopeCreator(compiler).createScope(root, null);
FlowScope flowScope = LinkedFlowScope.createEntryLattice(compiler, scope);
assertThat(call.getToken()).isEqualTo(Token.CALL);
assertThat(name.getToken()).isEqualTo(Token.NAME);
flowScope = flowScope.inferSlotType("a", type);
ClosureReverseAbstractInterpreter rai = new ClosureReverseAbstractInterpreter(registry);
// trueScope
assertType(rai.getPreciserScopeKnowingConditionOutcome(call, flowScope, Outcome.TRUE).getSlot("a").getType()).isEqualTo(trueType);
// falseScope
JSType aType = rai.getPreciserScopeKnowingConditionOutcome(call, flowScope, Outcome.FALSE).getSlot("a").getType();
if (falseType == null) {
assertThat(aType).isNull();
} else {
assertType(aType).isEqualTo(falseType);
}
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class LinkedFlowScopeTest method testFindUniqueSlot.
public void testFindUniqueSlot() {
FlowScope childA = localEntry.createChildFlowScope();
childA.inferSlotType("localB", NUMBER_TYPE);
FlowScope childAB = childA.createChildFlowScope();
childAB.inferSlotType("localB", STRING_TYPE);
FlowScope childABC = childAB.createChildFlowScope();
childABC.inferSlotType("localA", BOOLEAN_TYPE);
assertNull(childABC.findUniqueRefinedSlot(childABC));
assertTypeEquals(BOOLEAN_TYPE, childABC.findUniqueRefinedSlot(childAB).getType());
assertNull(childABC.findUniqueRefinedSlot(childA));
assertNull(childABC.findUniqueRefinedSlot(localEntry));
assertTypeEquals(STRING_TYPE, childAB.findUniqueRefinedSlot(childA).getType());
assertTypeEquals(STRING_TYPE, childAB.findUniqueRefinedSlot(localEntry).getType());
assertTypeEquals(NUMBER_TYPE, childA.findUniqueRefinedSlot(localEntry).getType());
}
Aggregations