[JS IR BE] process empty loops correctly in BlockDecomposerLowering

This commit is contained in:
Zalim Bashorov
2018-10-10 14:23:51 +03:00
parent 6d592ae66b
commit 8013a56286
6 changed files with 70 additions and 6 deletions
@@ -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) }
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
do while (false);
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JS_IR
fun box(): String {
while (false);
@@ -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");
@@ -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");
@@ -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"
}