Skip to content

Commit

Permalink
Visit children of an 'export default' in TypeInference
Browse files Browse the repository at this point in the history
-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=246035749
  • Loading branch information
lauraharker authored and brad4d committed May 1, 2019
1 parent 9a51ac3 commit 6a0ac84
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 7 deletions.
7 changes: 6 additions & 1 deletion src/com/google/javascript/jscomp/TypeInference.java
Expand Up @@ -714,6 +714,12 @@ private FlowScope traverse(Node n, FlowScope scope) {
scope = traverseChildren(n, scope); scope = traverseChildren(n, scope);
break; break;


case EXPORT:
if (n.getBooleanProp(Node.EXPORT_DEFAULT)) {
scope = traverseChildren(n, scope);
}
break;

case ROOT: case ROOT:
case SCRIPT: case SCRIPT:
case MODULE_BODY: case MODULE_BODY:
Expand All @@ -736,7 +742,6 @@ private FlowScope traverse(Node n, FlowScope scope) {
case WITH: case WITH:
case DEBUGGER: case DEBUGGER:
case IMPORT: case IMPORT:
case EXPORT:
case IMPORT_SPEC: case IMPORT_SPEC:
case IMPORT_SPECS: case IMPORT_SPECS:
// These don't need to be typed here, since they only affect control flow. // These don't need to be typed here, since they only affect control flow.
Expand Down
50 changes: 44 additions & 6 deletions test/com/google/javascript/jscomp/TypeInferenceTest.java
Expand Up @@ -48,6 +48,8 @@
import com.google.javascript.jscomp.CompilerOptions.LanguageMode; import com.google.javascript.jscomp.CompilerOptions.LanguageMode;
import com.google.javascript.jscomp.DataFlowAnalysis.BranchedFlowState; import com.google.javascript.jscomp.DataFlowAnalysis.BranchedFlowState;
import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback;
import com.google.javascript.jscomp.deps.ModuleLoader.ResolutionMode;
import com.google.javascript.jscomp.modules.ModuleMapCreator;
import com.google.javascript.jscomp.testing.ScopeSubject; import com.google.javascript.jscomp.testing.ScopeSubject;
import com.google.javascript.jscomp.type.FlowScope; import com.google.javascript.jscomp.type.FlowScope;
import com.google.javascript.jscomp.type.ReverseAbstractInterpreter; import com.google.javascript.jscomp.type.ReverseAbstractInterpreter;
Expand Down Expand Up @@ -139,6 +141,22 @@ private void inFunction(String js) {
parseAndRunTypeInference("(" + thisBlock + " function() {" + js + "});"); parseAndRunTypeInference("(" + thisBlock + " function() {" + js + "});");
} }


private void inModule(String js) {
Node script = compiler.parseTestCode(js);
assertWithMessage("parsing error: " + Joiner.on(", ").join(compiler.getErrors()))
.that(compiler.getErrorCount())
.isEqualTo(0);
Node root = IR.root(IR.root(), IR.root(script));
new GatherModuleMetadata(compiler, /* processCommonJsModules= */ false, ResolutionMode.BROWSER)
.process(root.getFirstChild(), root.getSecondChild());
new ModuleMapCreator(compiler, compiler.getModuleMetadataMap())
.process(root.getFirstChild(), root.getSecondChild());

// SCRIPT -> MODULE_BODY
Node moduleBody = script.getFirstChild();
parseAndRunTypeInference(root, moduleBody);
}

private void inGenerator(String js) { private void inGenerator(String js) {
checkState(assumedThisType == null); checkState(assumedThisType == null);
parseAndRunTypeInference("(function *() {" + js + "});"); parseAndRunTypeInference("(function *() {" + js + "});");
Expand All @@ -153,8 +171,11 @@ private void parseAndRunTypeInference(String js) {


// SCRIPT -> EXPR_RESULT -> FUNCTION // SCRIPT -> EXPR_RESULT -> FUNCTION
// `(function() { TEST CODE HERE });` // `(function() { TEST CODE HERE });`
Node n = script.getFirstFirstChild(); Node function = script.getFirstFirstChild();
parseAndRunTypeInference(root, function);
}


private void parseAndRunTypeInference(Node root, Node cfgRoot) {
// Create the scope with the assumptions. // Create the scope with the assumptions.
TypedScopeCreator scopeCreator = new TypedScopeCreator(compiler); TypedScopeCreator scopeCreator = new TypedScopeCreator(compiler);
// Also populate a map allowing us to look up labeled statements later. // Also populate a map allowing us to look up labeled statements later.
Expand All @@ -179,13 +200,13 @@ public void visit(NodeTraversal t, Node n, Node parent) {
}, },
scopeCreator) scopeCreator)
.traverse(root); .traverse(root);
TypedScope assumedScope = scopeCreator.createScope(n); TypedScope assumedScope = scopeCreator.createScope(cfgRoot);
for (Map.Entry<String,JSType> entry : assumptions.entrySet()) { for (Map.Entry<String,JSType> entry : assumptions.entrySet()) {
assumedScope.declare(entry.getKey(), null, entry.getValue(), null, false); assumedScope.declare(entry.getKey(), null, entry.getValue(), null, false);
} }
// Create the control graph. // Create the control graph.
ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false); ControlFlowAnalysis cfa = new ControlFlowAnalysis(compiler, false, false);
cfa.process(null, n); cfa.process(null, cfgRoot);
ControlFlowGraph<Node> cfg = cfa.getCfg(); ControlFlowGraph<Node> cfg = cfa.getCfg();
// Create a simple reverse abstract interpreter. // Create a simple reverse abstract interpreter.
ReverseAbstractInterpreter rai = compiler.getReverseAbstractInterpreter(); ReverseAbstractInterpreter rai = compiler.getReverseAbstractInterpreter();
Expand All @@ -196,9 +217,15 @@ public void visit(NodeTraversal t, Node n, Node parent) {
// Get the scope of the implicit return. // Get the scope of the implicit return.
BranchedFlowState<FlowScope> rtnState = BranchedFlowState<FlowScope> rtnState =
cfg.getImplicitReturn().getAnnotation(); cfg.getImplicitReturn().getAnnotation();
// Reset the flow scope's syntactic scope to the function block, rather than the function node if (cfgRoot.isFunction()) {
// itself. This allows pulling out local vars from the function by name to verify their types. // Reset the flow scope's syntactic scope to the function block, rather than the function node
returnScope = rtnState.getIn().withSyntacticScope(scopeCreator.createScope(n.getLastChild())); // itself. This allows pulling out local vars from the function by name to verify their
// types.
returnScope =
rtnState.getIn().withSyntacticScope(scopeCreator.createScope(cfgRoot.getLastChild()));
} else {
returnScope = rtnState.getIn();
}
} }


private LabeledStatement getLabeledStatement(String label) { private LabeledStatement getLabeledStatement(String label) {
Expand Down Expand Up @@ -2693,6 +2720,17 @@ public void constDeclarationWithCtorJSDoc_ignoresKnownMixinReturnType() {
assertType(fooWithInterfaceType).toStringIsEqualTo("function(new:FooExtended): ?"); assertType(fooWithInterfaceType).toStringIsEqualTo("function(new:FooExtended): ?");
} }


@Test
public void testSideEffectsInEsExportDefaultInferred() {
assuming("foo", NUMBER_TYPE);
assuming("bar", UNKNOWN_TYPE);

inModule("export default (bar = foo, foo = 'not a number');");

assertType(getType("bar")).isNumber();
assertType(getType("foo")).isString();
}

private ObjectType getNativeObjectType(JSTypeNative t) { private ObjectType getNativeObjectType(JSTypeNative t) {
return registry.getNativeObjectType(t); return registry.getNativeObjectType(t);
} }
Expand Down

0 comments on commit 6a0ac84

Please sign in to comment.