diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt index 47eb9c0b510..122cc6d8bf0 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/BlockDecomposerLowering.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.util.transformFlat import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid +import org.jetbrains.kotlin.utils.addIfNotNull class BlockDecomposerLowering(context: JsIrBackendContext) : DeclarationContainerLoweringPass { @@ -265,7 +266,7 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo } newLoopBody.statements += JsIrBuilder.buildIfElse(unitType, breakCond, thenBlock) - newLoopBody.statements += newBody!! + newLoopBody.statements.addIfNotNull(newBody) return loop.apply { condition = constTrue @@ -293,16 +294,22 @@ class BlockDecomposerTransformer(context: JsIrBackendContext) : IrElementTransfo // } while (cond) // override fun visitDoWhileLoop(loop: IrDoWhileLoop): IrExpression { - val newBody = loop.body?.transform(statementTransformer, null)!! + val newBody = loop.body?.transform(statementTransformer, null) val newCondition = loop.condition.transform(expressionTransformer, null) if (newCondition is IrComposite) { - val innerLoop = IrDoWhileLoopImpl(loop.startOffset, loop.endOffset, unitType, loop.origin, newBody, constFalse).apply { + val innerLoop = IrDoWhileLoopImpl(loop.startOffset, loop.endOffset, unitType, loop.origin).apply { + condition = constFalse + body = newBody label = makeLoopLabel() } val newLoopCondition = newCondition.statements.last() as IrExpression - val newLoopBody = IrBlockImpl(newCondition.startOffset, newBody.endOffset, newBody.type).apply { + val newLoopBody = IrBlockImpl( + newCondition.startOffset, + newBody?.endOffset ?: newCondition.endOffset, + newBody?.type ?: unitType + ).apply { statements += innerLoop statements += newCondition.statements.run { subList(0, lastIndex) } } diff --git a/compiler/testData/codegen/box/controlStructures/emptyDoWhile.kt b/compiler/testData/codegen/box/controlStructures/emptyDoWhile.kt index 0f5aed17115..0f52a36e3b6 100644 --- a/compiler/testData/codegen/box/controlStructures/emptyDoWhile.kt +++ b/compiler/testData/codegen/box/controlStructures/emptyDoWhile.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR fun box(): String { do while (false); diff --git a/compiler/testData/codegen/box/controlStructures/emptyWhile.kt b/compiler/testData/codegen/box/controlStructures/emptyWhile.kt index 6777c304b26..c52c5124f52 100644 --- a/compiler/testData/codegen/box/controlStructures/emptyWhile.kt +++ b/compiler/testData/codegen/box/controlStructures/emptyWhile.kt @@ -1,4 +1,3 @@ -// IGNORE_BACKEND: JS_IR fun box(): String { while (false); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java index 64bf388125c..185eb2852d9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/BoxJsTestGenerated.java @@ -2149,6 +2149,11 @@ public class BoxJsTestGenerated extends AbstractBoxJsTest { runTest("js/js.translator/testData/box/expression/evaluationOrder/elvisWithBreakContinueReturn.kt"); } + @TestMetadata("emptyLoopWithBreakContinueReturnInCondition.kt") + public void testEmptyLoopWithBreakContinueReturnInCondition() throws Exception { + runTest("js/js.translator/testData/box/expression/evaluationOrder/emptyLoopWithBreakContinueReturnInCondition.kt"); + } + @TestMetadata("equalsIntrinsicWithSideEffect.kt") public void testEqualsIntrinsicWithSideEffect() throws Exception { runTest("js/js.translator/testData/box/expression/evaluationOrder/equalsIntrinsicWithSideEffect.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java index c6bec58bdfa..aea191f2ab9 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/IrBoxJsTestGenerated.java @@ -2149,6 +2149,11 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest { runTest("js/js.translator/testData/box/expression/evaluationOrder/elvisWithBreakContinueReturn.kt"); } + @TestMetadata("emptyLoopWithBreakContinueReturnInCondition.kt") + public void testEmptyLoopWithBreakContinueReturnInCondition() throws Exception { + runTest("js/js.translator/testData/box/expression/evaluationOrder/emptyLoopWithBreakContinueReturnInCondition.kt"); + } + @TestMetadata("equalsIntrinsicWithSideEffect.kt") public void testEqualsIntrinsicWithSideEffect() throws Exception { runTest("js/js.translator/testData/box/expression/evaluationOrder/equalsIntrinsicWithSideEffect.kt"); diff --git a/js/js.translator/testData/box/expression/evaluationOrder/emptyLoopWithBreakContinueReturnInCondition.kt b/js/js.translator/testData/box/expression/evaluationOrder/emptyLoopWithBreakContinueReturnInCondition.kt new file mode 100644 index 00000000000..fd5fc033ae0 --- /dev/null +++ b/js/js.translator/testData/box/expression/evaluationOrder/emptyLoopWithBreakContinueReturnInCondition.kt @@ -0,0 +1,49 @@ +// EXPECTED_REACHABLE_NODES: 1236 +package foo + +fun whileReturn(): String { + var log = "" + var i = 0 + while(if (i<2) { log += "A"; i++; true } else { return log + ":whileReturn:"}); + return ":whileReturn:after:" +} + +fun whileImmediateReturn(): String { + while(return ":whileImmediateReturn:") { + } + return ":whileImmediateReturn:after" +} + +fun doWhileReturn(): String { + var log = "" + var i = 0 + do while(if (i<2) { log += "A"; i++; true} else { return log + ":doWhileReturn:"}) + return ":doWhileReturn:after:" +} + +fun doWhileReturnFromCondition(): String { + do { + } while(return ":doWhileReturnFromCondition:") + return ":doWhileReturnFromCondition:after" +} + +fun forReturn(b: Boolean): String { + for(i in (if (b) 1..2 else { return ":forReturn:"})); + return ":forReturn:after:" +} + +fun box(): String { + assertEquals("AA:whileReturn:", whileReturn()) + + assertEquals(":whileImmediateReturn:", whileImmediateReturn()) + + assertEquals("AA:doWhileReturn:", doWhileReturn()) + + assertEquals(":doWhileReturnFromCondition:", doWhileReturnFromCondition()) + + assertEquals(":forReturn:after:", forReturn(true)) + + assertEquals(":forReturn:", forReturn(false)) + + return "OK" +}