use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class LinkedFlowScopeTest method testOptimize.
public void testOptimize() {
assertEquals(localEntry, localEntry.optimize());
FlowScope child = localEntry.createChildFlowScope();
assertEquals(localEntry, child.optimize());
child.inferSlotType("localB", NUMBER_TYPE);
assertEquals(child, child.optimize());
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class LinkedFlowScopeTest method testLongChain1.
/**
* Create a long chain of flow scopes where each link in the chain
* contains one slot.
*/
public void testLongChain1() {
FlowScope chainA = localEntry.createChildFlowScope();
FlowScope chainB = localEntry.createChildFlowScope();
for (int i = 0; i < LONG_CHAIN_LENGTH; i++) {
localScope.declare("local" + i, null, null, null);
chainA.inferSlotType("local" + i, i % 2 == 0 ? NUMBER_TYPE : BOOLEAN_TYPE);
chainB.inferSlotType("local" + i, i % 3 == 0 ? STRING_TYPE : BOOLEAN_TYPE);
chainA = chainA.createChildFlowScope();
chainB = chainB.createChildFlowScope();
}
verifyLongChains(chainA, chainB);
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method branchedFlowThrough.
@Override
@SuppressWarnings({ "fallthrough", "incomplete-switch" })
List<FlowScope> branchedFlowThrough(Node source, FlowScope input) {
// NOTE(nicksantos): Right now, we just treat ON_EX edges like UNCOND
// edges. If we wanted to be perfect, we'd actually JOIN all the out
// lattices of this flow with the in lattice, and then make that the out
// lattice for the ON_EX edge. But it's probably too expensive to be
// worthwhile.
FlowScope output = flowThrough(source, input);
Node condition = null;
FlowScope conditionFlowScope = null;
BooleanOutcomePair conditionOutcomes = null;
List<DiGraphEdge<Node, Branch>> branchEdges = getCfg().getOutEdges(source);
List<FlowScope> result = new ArrayList<>(branchEdges.size());
for (DiGraphEdge<Node, Branch> branchEdge : branchEdges) {
Branch branch = branchEdge.getValue();
FlowScope newScope = output;
switch(branch) {
case ON_TRUE:
if (source.isForIn() || source.isForOf()) {
Node item = source.getFirstChild();
Node obj = item.getNext();
FlowScope informed = traverse(obj, output.createChildFlowScope());
if (item.isVar()) {
item = item.getFirstChild();
}
if (source.isForIn()) {
// item is assigned a property name, so its type should be string.
if (item.isName()) {
JSType iterKeyType = getNativeType(STRING_TYPE);
ObjectType objType = getJSType(obj).dereference();
JSType objIndexType = objType == null ? null : objType.getTemplateTypeMap().getResolvedTemplateType(registry.getObjectIndexKey());
if (objIndexType != null && !objIndexType.isUnknownType()) {
JSType narrowedKeyType = iterKeyType.getGreatestSubtype(objIndexType);
if (!narrowedKeyType.isEmptyType()) {
iterKeyType = narrowedKeyType;
}
}
redeclareSimpleVar(informed, item, iterKeyType);
}
} else {
// for/of. The type of `item` is the type parameter of the Iterable type.
ObjectType objType = getJSType(obj).dereference();
if (objType.isSubtypeOf(getNativeType(JSTypeNative.ITERABLE_TYPE))) {
if (objType.isTemplatizedType()) {
JSType newType = objType.getTemplateTypeMap().getResolvedTemplateType(registry.getIterableTemplate());
redeclareSimpleVar(informed, item, newType);
}
}
}
newScope = informed;
break;
}
case ON_FALSE:
if (condition == null) {
condition = NodeUtil.getConditionExpression(source);
if (condition == null && source.isCase()) {
condition = source;
// of the loop.
if (conditionFlowScope == null) {
conditionFlowScope = traverse(condition.getFirstChild(), output.createChildFlowScope());
}
}
}
if (condition != null) {
if (condition.isAnd() || condition.isOr()) {
// of the loop.
if (conditionOutcomes == null) {
conditionOutcomes = condition.isAnd() ? traverseAnd(condition, output.createChildFlowScope()) : traverseOr(condition, output.createChildFlowScope());
}
newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionOutcomes.getOutcomeFlowScope(condition.getToken(), branch == Branch.ON_TRUE), branch == Branch.ON_TRUE);
} else {
// of the loop.
if (conditionFlowScope == null) {
conditionFlowScope = traverse(condition, output.createChildFlowScope());
}
newScope = reverseInterpreter.getPreciserScopeKnowingConditionOutcome(condition, conditionFlowScope, branch == Branch.ON_TRUE);
}
}
break;
default:
break;
}
result.add(newScope.optimize());
}
return result;
}
use of com.google.javascript.jscomp.type.FlowScope in project closure-compiler by google.
the class TypeInference method traverseShortCircuitingBinOp.
private BooleanOutcomePair traverseShortCircuitingBinOp(Node n, FlowScope scope) {
checkArgument(n.isAnd() || n.isOr());
boolean nIsAnd = n.isAnd();
Node left = n.getFirstChild();
Node right = n.getLastChild();
// type the left node
BooleanOutcomePair leftOutcome = traverseWithinShortCircuitingBinOp(left, scope.createChildFlowScope());
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), nIsAnd);
// type the right node
BooleanOutcomePair rightOutcome = traverseWithinShortCircuitingBinOp(right, rightScope.createChildFlowScope());
JSType rightType = right.getJSType();
JSType type;
BooleanOutcomePair outcome;
if (leftType != null && rightType != null) {
leftType = leftType.getRestrictedTypeGivenToBooleanOutcome(!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 = null;
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 SemanticReverseAbstractInterpreterTest method testBinop.
private void testBinop(FlowScope blind, Token binop, Node left, Node right, Collection<TypedName> trueOutcome, Collection<TypedName> falseOutcome) {
Node condition = new Node(binop);
condition.addChildToBack(left);
condition.addChildToBack(right);
// true outcome.
FlowScope informedTrue = interpreter.getPreciserScopeKnowingConditionOutcome(condition, blind, true);
for (TypedName p : trueOutcome) {
assertTypeEquals(p.name, p.type, getVarType(informedTrue, p.name));
}
// false outcome.
FlowScope informedFalse = interpreter.getPreciserScopeKnowingConditionOutcome(condition, blind, false);
for (TypedName p : falseOutcome) {
assertTypeEquals(p.type, getVarType(informedFalse, p.name));
}
}
Aggregations