diff --git a/src/com/google/javascript/jscomp/DefaultPassConfig.java b/src/com/google/javascript/jscomp/DefaultPassConfig.java index f95c0bf5da3..e38f8e91cb9 100644 --- a/src/com/google/javascript/jscomp/DefaultPassConfig.java +++ b/src/com/google/javascript/jscomp/DefaultPassConfig.java @@ -2443,16 +2443,19 @@ protected CompilerPass create(AbstractCompiler compiler) { } }; - /** - * Use data flow analysis to remove dead branches. - */ + /** Use data flow analysis to remove dead branches. */ private final PassFactory removeUnreachableCode = new PassFactory(Compiler.UNREACHABLE_CODE_ELIM_NAME, false) { - @Override - protected CompilerPass create(AbstractCompiler compiler) { - return new UnreachableCodeElimination(compiler, true); - } - }; + @Override + protected CompilerPass create(AbstractCompiler compiler) { + return new UnreachableCodeElimination(compiler, true); + } + + @Override + protected FeatureSet featureSet() { + return ES8; + } + }; /** * Use data flow analysis to remove dead branches. diff --git a/src/com/google/javascript/jscomp/PureFunctionIdentifier.java b/src/com/google/javascript/jscomp/PureFunctionIdentifier.java index 411d22f9f20..e7bf59fe855 100644 --- a/src/com/google/javascript/jscomp/PureFunctionIdentifier.java +++ b/src/com/google/javascript/jscomp/PureFunctionIdentifier.java @@ -510,6 +510,10 @@ public void updateSideEffectsForNode( if (node.hasChildren() && !NodeUtil.evaluatesToLocalValue(node.getFirstChild())) { sideEffectInfo.setTaintsReturn(); } + } else if (node.isYield()) { + if (node.hasChildren() && !NodeUtil.evaluatesToLocalValue(node.getFirstChild())) { + sideEffectInfo.setTaintsReturn(); + } } else { throw new IllegalArgumentException("Unhandled side effect node type " + node.getToken()); } diff --git a/src/com/google/javascript/jscomp/UnreachableCodeElimination.java b/src/com/google/javascript/jscomp/UnreachableCodeElimination.java index 75fe2aef089..e7a43cc783e 100644 --- a/src/com/google/javascript/jscomp/UnreachableCodeElimination.java +++ b/src/com/google/javascript/jscomp/UnreachableCodeElimination.java @@ -202,8 +202,8 @@ private void removeDeadExprStatementSafely(Node n) { } // TODO(user): This is a problem with removeNoOpStatements. - // Every expression in a FOR-IN header looks side effect free on its own. - if (parent.isForIn()) { + // Every expression in a FOR-IN or FOR-OF header looks side effect free on its own. + if (NodeUtil.isEnhancedFor(parent)) { return; } diff --git a/test/com/google/javascript/jscomp/PureFunctionIdentifierTest.java b/test/com/google/javascript/jscomp/PureFunctionIdentifierTest.java index f08a54ec590..edf8307acce 100644 --- a/test/com/google/javascript/jscomp/PureFunctionIdentifierTest.java +++ b/test/com/google/javascript/jscomp/PureFunctionIdentifierTest.java @@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterables; -import com.google.javascript.jscomp.CompilerOptions.LanguageMode; import com.google.javascript.jscomp.NodeTraversal.AbstractPostOrderCallback; import com.google.javascript.rhino.Node; import java.util.ArrayList; @@ -1608,6 +1607,34 @@ public void testMutatesArgumentsArray3() throws Exception { assertNoPureCalls(source); } + public void testCallGenerator1() { + this.mode = TypeInferenceMode.NEITHER; // type check for yield not yet implemented + String source = + LINE_JOINER.join( + "var x = 0;", + "function* f() {", + " x = 2", + " while (true) {", + " yield x;", + " }", + "}", + "var g = f();"); + assertNoPureCalls(source); + Node lastRoot = getLastCompiler().getRoot().getLastChild(); + Node call = findQualifiedNameNode("f", lastRoot).getParent(); + assertThat(call.isNoSideEffectsCall()).isFalse(); + assertEquals( + new Node.SideEffectFlags().setReturnsTainted().valueOf(), call.getSideEffectFlags()); + } + + public void testCallGenerator2() { + this.mode = TypeInferenceMode.NEITHER; // type check for yield not yet implemented + String source = + LINE_JOINER.join( + "function* f() {", " while (true) {", " yield 1;", " }", "}", "var g = f()"); + assertPureCallsMarked(source, ImmutableList.of("f")); + } + public void testCallFunctionFOrG() throws Exception { String source = LINE_JOINER.join( "function f(){}", @@ -1839,13 +1866,6 @@ void assertPureCallsMarked(String source, List expected) { } void assertPureCallsMarked(String source, List expected, DiagnosticType warning) { - assertPureCallsMarked(source, expected, warning, LanguageMode.ECMASCRIPT_2015); - assertPureCallsMarked(source, expected, warning, LanguageMode.ECMASCRIPT5); - } - - void assertPureCallsMarked( - String source, List expected, DiagnosticType warning, LanguageMode mode) { - setAcceptedLanguage(mode); if (warning != null) { testSame(source, warning); } else { @@ -1854,13 +1874,8 @@ void assertPureCallsMarked( assertEquals(expected, noSideEffectCalls); } - void checkLocalityOfMarkedCalls(String source, List expected) { - checkLocalityOfMarkedCalls(source, expected, LanguageMode.ECMASCRIPT_2015); - checkLocalityOfMarkedCalls(source, expected, LanguageMode.ECMASCRIPT5); - } - void checkLocalityOfMarkedCalls(String source, List expected, LanguageMode mode) { - setAcceptedLanguage(mode); + void checkLocalityOfMarkedCalls(String source, List expected) { testSame(source); assertEquals(expected, localResultCalls); } diff --git a/test/com/google/javascript/jscomp/UnreachableCodeEliminationTest.java b/test/com/google/javascript/jscomp/UnreachableCodeEliminationTest.java index 74bd96c1b21..e898607da79 100644 --- a/test/com/google/javascript/jscomp/UnreachableCodeEliminationTest.java +++ b/test/com/google/javascript/jscomp/UnreachableCodeEliminationTest.java @@ -428,4 +428,55 @@ public void testIssue1001() throws Exception { test("function f(x) { x.property = 3; } new f({})", "function f(x) { x.property = 3; }"); } + + public void testLetConstBlocks() { + test("function f() {return 1; let a; }", "function f() {return 1;}"); + + test("function f() {return 1; const a = 1; }", "function f() {return 1;}"); + + test( + "function f() { x = 1; {let g; return x} let y}", + "function f() { x = 1; {let g; return x;}} "); + } + + public void testArrowFunctions() { + test("f(x => {return x; j = 1})", "f(x => {return x;})"); + + testSame("f( () => {return 1;})"); + } + + public void testGenerators() { + test( + LINE_JOINER.join( + "function* f() {", " while(true) {", " yield 1;", " }", " x = 1;", "}"), + LINE_JOINER.join("function* f() {", " while(true) {", " yield 1;", " }", "}")); + + testSame(LINE_JOINER.join("function* f() {", " while(true) {", " yield 1;", " }", "}")); + + testSame( + LINE_JOINER.join( + "function* f() {", + " let i = 0;", + " while (true) {", + " if (i < 10) {", + " yield i;", + " } else {", + " break;", + " }", + " }", + " let x = 1;", + "}")); + } + + public void testForOf() { + test("for(x of i){ 1; }", "for(x of i) {}"); + + testSame("for(x of i){}"); + } + + public void testRemoveUselessTemplateStrings() { + test("`hi`", ""); + + testSame("`hello visitor # ${i++}`"); + } }