use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method traverseNullishCoalesce.
private FlowScope traverseNullishCoalesce(Node n, FlowScope scope) {
checkArgument(n.isNullishCoalesce() || n.isAssignNullishCoalesce());
Node left = n.getFirstChild();
Node right = n.getLastChild();
scope = traverse(left, scope);
FlowScope rightScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(left, scope, Outcome.NULLISH);
FlowScope scopeAfterTraverseRight = traverse(right, rightScope);
JSType leftType = left.getJSType();
JSType rightType = right.getJSType();
JSType type = unknownType;
if (leftType != null) {
if (!leftType.isNullable() && !leftType.isVoidable()) {
type = leftType;
} else if (rightType != null) {
type = registry.createUnionType(leftType.restrictByNotNullOrUndefined(), rightType);
scope = join(scope, scopeAfterTraverseRight);
// Assignment occurs if lhs is null
if (n.isAssignNullishCoalesce()) {
scope = updateScopeForAssignment(scope, left, type, AssignmentType.ASSIGN);
}
}
}
n.setJSType(type);
return scope;
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method initializeEnhancedForScope.
private FlowScope initializeEnhancedForScope(Node source, FlowScope output) {
Node item = source.getFirstChild();
Node obj = item.getNext();
FlowScope informed = traverse(obj, output);
final AssignmentType assignmentType;
if (NodeUtil.isNameDeclaration(item)) {
item = item.getFirstChild();
assignmentType = AssignmentType.DECLARATION;
} else {
assignmentType = AssignmentType.ASSIGN;
}
if (item.isDestructuringLhs()) {
item = item.getFirstChild();
}
final JSType newType;
switch(source.getToken()) {
case FOR_IN:
{
// item is assigned a property name, so its type should be string
JSType iterKeyType = getNativeType(STRING_TYPE);
JSType objType = getJSType(obj).autobox();
JSType objIndexType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
if (objIndexType != null && !objIndexType.isUnknownType()) {
JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
if (!narrowedKeyType.isEmptyType()) {
iterKeyType = narrowedKeyType;
}
}
newType = iterKeyType;
break;
}
case FOR_OF:
{
// for/of. The type of `item` is the type parameter of the Iterable type.
JSType objType = getJSType(obj).autobox();
TemplateType templateType = registry.getIterableTemplate();
// NOTE: this returns the UNKNOWN_TYPE if objType does not implement Iterable
newType = objType.getTemplateTypeMap().getResolvedTemplateType(templateType);
break;
}
case FOR_AWAIT_OF:
{
// for/await/of. the iterated object is either of the Iterable or AsyncIterable type.
// the type of `item` is the Promise.resolve() type of the object's type parameter.
JSType iterableType = JsIterables.maybeBoxIterableOrAsyncIterable(getJSType(obj), registry).orElse(unknownType);
newType = Promises.getResolvedType(registry, iterableType);
break;
}
default:
throw new IllegalArgumentException("Unexpected source node " + source);
}
// Note that `item` can be an arbitrary LHS expression we need to check.
if (item.isDestructuringPattern()) {
// for (const {x, y} of data) {
informed = traverseDestructuringPattern(item, informed, newType, assignmentType);
} else {
informed = traverse(item, informed);
informed = updateScopeForAssignment(informed, item, newType, assignmentType);
}
return informed;
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method traverseOptChain.
/**
* Traversal requires holding scopes from the unconditional start (lhs of the `?.`) and the
* conditional part (rhs of the `?.`), and using the startType to determine the resulting scope.
*/
private FlowScope traverseOptChain(Node n, FlowScope scope) {
checkArgument(NodeUtil.isOptChainNode(n));
if (NodeUtil.isEndOfOptChainSegment(n)) {
// Create new optional chain tracking object and push it onto the stack.
final Node startOfChain = NodeUtil.getStartOfOptChainSegment(n);
OptChainInfo optChainInfo = new OptChainInfo(n, startOfChain);
optChainArrayDeque.addFirst(optChainInfo);
}
FlowScope lhsScope = traverse(n.getFirstChild(), scope);
if (n.isOptionalChainStart()) {
// Store lhsScope into top-of-stack as unexecuted (unconditional) scope.
optChainArrayDeque.peekFirst().unconditionalScope = lhsScope;
}
// Traverse the remaining children and capture their changes into a new FlowScope var
// `aboutToExecuteScope`. This FlowScope must be constructed on top of the `lhsScope` and not
// the original scope `scope`, otherwise changes to outer variable that are preserved in the
// lhsScope would not be captured in the `aboutToExecuteScope`.
FlowScope aboutToExecuteScope = lhsScope;
Node nextChild = n.getSecondChild();
while (nextChild != null) {
aboutToExecuteScope = traverse(nextChild, aboutToExecuteScope);
nextChild = nextChild.getNext();
}
// Assigns the type to `n` assuming the entire chain executes and returns the the executed
// scope.
FlowScope executedScope = setOptChainNodeTypeAfterChildrenTraversed(n, aboutToExecuteScope);
// Unlike CALL, the OPTCHAIN_CALL nodes must not remain untyped when left child is untyped.
if (n.getJSType() == null) {
n.setJSType(unknownType);
}
if (NodeUtil.isEndOfOptChainSegment(n)) {
// Use the startNode's type to selectively join the executed scope with the unexecuted scope,
// and update the type assigned to `n` in `setXAfterChildrenTraversed()`
final Node startOfChain = NodeUtil.getStartOfOptChainSegment(n);
// Pop the stack to obtain the current chain.
OptChainInfo currentChain = optChainArrayDeque.removeFirst();
// Sanity check that the popped chain correctly corresponds to the current optional chain
checkState(currentChain.endOfChain == n);
checkState(currentChain.startOfChain == startOfChain);
final Node startNode = checkNotNull(startOfChain.getFirstChild());
return updateTypeWhenEndOfOptChain(n, startNode, currentChain, executedScope);
} else {
// executedScope.
return executedScope;
}
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method traverseShortCircuitingBinOpAssignment.
private FlowScope traverseShortCircuitingBinOpAssignment(Node n, FlowScope scope) {
Node left = n.getFirstChild();
boolean nIsAnd = n.isAssignAnd();
BooleanOutcomePair leftOutcome = traverseWithinShortCircuitingBinOp(left, scope);
BooleanOutcomePair outcome = traverseShortCircuitingBinOp(n, left, leftOutcome);
FlowScope outcomeJoinedFlowScope = outcome.getJoinedFlowScope();
if (leftOutcome.toBooleanOutcomes == BooleanLiteralSet.get(!nIsAnd)) {
// The scope is otherwise updated according to the result of an assignment.
return outcomeJoinedFlowScope;
}
return updateScopeForAssignment(outcomeJoinedFlowScope, n.getFirstChild(), n.getJSType(), AssignmentType.ASSIGN);
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class SemanticReverseAbstractInterpreterTest method testInequalitiesCondition2.
/**
* Tests reverse interpretation of a COMPARE(NAME, NAME) expression, where COMPARE can be LE, LT,
* GE or GT.
*/
@Test
public void testInequalitiesCondition2() {
for (Token op : Arrays.asList(Token.LT, Token.GT, Token.LE, Token.GE)) {
FlowScope[] blind = newScope();
testBinop(blind, op, createVar(blind, "a", createUnionType(getNativeStringType(), getNativeNumberType(), getNativeVoidType())), createVar(blind, "b", createUnionType(getNativeNumberType(), getNativeNullType())), ImmutableSet.of(new TypedName("a", createUnionType(getNativeStringType(), getNativeNumberType())), new TypedName("b", createUnionType(getNativeNumberType(), getNativeNullType()))), ImmutableSet.of(new TypedName("a", createUnionType(getNativeStringType(), getNativeNumberType(), getNativeVoidType())), new TypedName("b", createUnionType(getNativeNumberType(), getNativeNullType()))));
}
}
Aggregations