diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt index 23b6e409542..ca1b13be8f6 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/optimizations.kt @@ -30,6 +30,7 @@ fun optimizeProgramByIr( fun optimizeFragmentByJsAst(fragment: JsIrProgramFragment) { val optimizer = object : RecursiveJsVisitor() { override fun visitFunction(x: JsFunction) { + super.visitFunction(x) FunctionPostProcessor(x).apply() } diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/optimizer/DeadCodeEliminationTest.kt b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/optimizer/DeadCodeEliminationTest.kt index b6e5a7c380f..5d9383d4112 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/testOld/optimizer/DeadCodeEliminationTest.kt +++ b/js/js.tests/test/org/jetbrains/kotlin/js/testOld/optimizer/DeadCodeEliminationTest.kt @@ -19,5 +19,9 @@ package org.jetbrains.kotlin.js.testOld.optimizer import org.junit.Test class DeadCodeEliminationTest : BasicOptimizerTest("dead-code-elimination") { - @Test fun switchCases() = box() -} \ No newline at end of file + @Test + fun switchCases() = box() + + @Test + fun afterReturn() = box() +} diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java index 8129868166a..ab693b76f16 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirJsBoxTestGenerated.java @@ -6928,6 +6928,12 @@ public class FirJsBoxTestGenerated extends AbstractFirJsBoxTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); } + @Test + @TestMetadata("deadCodeElimination.kt") + public void testDeadCodeElimination() throws Exception { + runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt"); + } + @Test @TestMetadata("tempVarDeclOnAssignment.kt") public void testTempVarDeclOnAssignment() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java index ea9c37c952b..1dbf367057e 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsES6TestGenerated.java @@ -7034,6 +7034,12 @@ public class IrBoxJsES6TestGenerated extends AbstractIrBoxJsES6Test { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR_ES6, true); } + @Test + @TestMetadata("deadCodeElimination.kt") + public void testDeadCodeElimination() throws Exception { + runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt"); + } + @Test @TestMetadata("tempVarDeclOnAssignment.kt") public void testTempVarDeclOnAssignment() throws Exception { diff --git a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java index ea6f1c1d7f3..72e929b8e0c 100644 --- a/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java +++ b/js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/ir/IrBoxJsTestGenerated.java @@ -6928,6 +6928,12 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("js/js.translator/testData/box/jsAstOptimizations"), Pattern.compile("^([^_](.+))\\.kt$"), null, TargetBackend.JS_IR, true); } + @Test + @TestMetadata("deadCodeElimination.kt") + public void testDeadCodeElimination() throws Exception { + runTest("js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt"); + } + @Test @TestMetadata("tempVarDeclOnAssignment.kt") public void testTempVarDeclOnAssignment() throws Exception { diff --git a/js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt b/js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt new file mode 100644 index 00000000000..65137ee238f --- /dev/null +++ b/js/js.translator/testData/box/jsAstOptimizations/deadCodeElimination.kt @@ -0,0 +1,23 @@ +// IGNORE_BACKEND_K2: JS_IR +// FIR works fine, however it generates another names for the temporary variables, therefore ignore it + +fun demo(f: () -> String) = f() + +// EXPECT_GENERATED_JS: function=test$lambda expect=deadCodeEliminationTestLambda.js +fun test(x: String?): String { + val r = demo { + val z = x ?: run { + return@demo "OK" + } + "Fail 1: $z" + } + return r +} + +fun box(): String { + val r = test(null) + if (r != "OK") { + return "Fail test, got $r" + } + return "OK" +} diff --git a/js/js.translator/testData/box/jsAstOptimizations/deadCodeEliminationTestLambda.js b/js/js.translator/testData/box/jsAstOptimizations/deadCodeEliminationTestLambda.js new file mode 100644 index 00000000000..8c76c21d4e0 --- /dev/null +++ b/js/js.translator/testData/box/jsAstOptimizations/deadCodeEliminationTestLambda.js @@ -0,0 +1,15 @@ +function test$lambda($x) { + return function () { + var tmp0_elvis_lhs = $x; + var tmp; + if (tmp0_elvis_lhs == null) { + // Inline function 'kotlin.run' call + // Inline function 'kotlin.contracts.contract' call + return 'OK'; + } else { + tmp = tmp0_elvis_lhs; + } + var z = tmp; + return 'Fail 1: ' + z; + }; +} diff --git a/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.optimized.js b/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.optimized.js new file mode 100644 index 00000000000..1bac5498402 --- /dev/null +++ b/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.optimized.js @@ -0,0 +1,34 @@ +function test1(x) { + var $tmp; + if (x == null) { + return 'OK'; + } else { + $tmp = x; + } + var z = $tmp; + return 'Fail 1: ' + z; +} + +function test2(x) { + return function () { + var $tmp0_elvis_lhs = x; + var $tmp; + if ($tmp0_elvis_lhs == null) { + return 'OK'; + } else { + $tmp = $tmp0_elvis_lhs; + } + var z = $tmp; + return 'Fail 1: ' + z; + } +} + +function box() { + if (test1(null) != "OK") { + return "Fail test1"; + } + if (test2(null)() != "OK") { + return "Fail test2"; + } + return "OK" +} diff --git a/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.original.js b/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.original.js new file mode 100644 index 00000000000..1899fd2e45a --- /dev/null +++ b/js/js.translator/testData/js-optimizer/dead-code-elimination/afterReturn.original.js @@ -0,0 +1,39 @@ +function test1(x) { + var $tmp0_elvis_lhs = x; + var $tmp; + if ($tmp0_elvis_lhs == null) { + var $tmp$ret$0; + return 'OK'; + $tmp = $tmp$ret$0; + } else { + $tmp = $tmp0_elvis_lhs; + } + var z = $tmp; + return 'Fail 1: ' + z; +} + +function test2(x) { + return function () { + var $tmp0_elvis_lhs = x; + var $tmp; + if ($tmp0_elvis_lhs == null) { + var $tmp$ret$0; + return 'OK'; + $tmp = $tmp$ret$0; + } else { + $tmp = $tmp0_elvis_lhs; + } + var z = $tmp; + return 'Fail 1: ' + z; + } +} + +function box() { + if (test1(null) != "OK") { + return "Fail test1"; + } + if (test2(null)() != "OK") { + return "Fail test2"; + } + return "OK" +}