From 8e84862afab8764c21edb70801a08674b2995463 Mon Sep 17 00:00:00 2001 From: Dmitry Petrov Date: Thu, 4 May 2017 13:38:59 +0300 Subject: [PATCH] Generate do-while condition within loop body scope --- .../generators/LoopExpressionGenerator.kt | 58 +++++++++++-------- .../irText/declarations/localVarInDoWhile.kt | 5 ++ .../irText/declarations/localVarInDoWhile.txt | 12 ++++ .../expressions/breakContinueInLoopHeader.kt | 20 +++++-- .../expressions/breakContinueInLoopHeader.txt | 49 ++++++++++++++-- .../kotlin/ir/IrTextTestCaseGenerated.java | 6 ++ 6 files changed, 116 insertions(+), 34 deletions(-) create mode 100644 compiler/testData/ir/irText/declarations/localVarInDoWhile.kt create mode 100644 compiler/testData/ir/irText/declarations/localVarInDoWhile.txt diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt index 9e2dd3705b6..49c54b4d41d 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/LoopExpressionGenerator.kt @@ -30,38 +30,46 @@ import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue import org.jetbrains.kotlin.resolve.BindingContext class LoopExpressionGenerator(statementGenerator: StatementGenerator) : StatementGeneratorExtension(statementGenerator){ - fun generateWhileLoop(ktWhile: KtWhileExpression): IrExpression = - generateConditionalLoop(ktWhile, - IrWhileLoopImpl(ktWhile.startOffset, ktWhile.endOffset, - context.builtIns.unitType, IrStatementOrigin.WHILE_LOOP)) + fun generateWhileLoop(ktWhile: KtWhileExpression): IrExpression { + val irLoop = IrWhileLoopImpl(ktWhile.startOffset, ktWhile.endOffset, + context.builtIns.unitType, IrStatementOrigin.WHILE_LOOP) - fun generateDoWhileLoop(ktDoWhile: KtDoWhileExpression): IrExpression = - generateConditionalLoop(ktDoWhile, - IrDoWhileLoopImpl(ktDoWhile.startOffset, ktDoWhile.endOffset, - context.builtIns.unitType, IrStatementOrigin.DO_WHILE_LOOP)) + irLoop.condition = statementGenerator.generateExpression(ktWhile.condition!!) - private fun generateConditionalLoop(ktLoop: KtWhileExpressionBase, irLoop: IrLoopBase): IrExpression { - irLoop.condition = statementGenerator.generateExpression(ktLoop.condition!!) - statementGenerator.bodyGenerator.putLoop(ktLoop, irLoop) - irLoop.body = ktLoop.body?.let { ktLoopBody -> - if (ktLoopBody is KtBlockExpression) { - if (ktLoop is KtDoWhileExpression) - generateDoWhileLoopBody(ktLoopBody) - else - generateWhileLoopBody(ktLoopBody) - } + statementGenerator.bodyGenerator.putLoop(ktWhile, irLoop) + + irLoop.body = ktWhile.body?.let { ktLoopBody -> + if (ktLoopBody is KtBlockExpression) + generateWhileLoopBody(ktLoopBody) else statementGenerator.generateExpression(ktLoopBody) } - irLoop.label = getLoopLabel(ktLoop) - return if (ktLoop is KtDoWhileExpression) { - IrBlockImpl(ktLoop.startOffset, ktLoop.endOffset, context.builtIns.unitType).apply { - statements.add(irLoop) - } + irLoop.label = getLoopLabel(ktWhile) + + return irLoop + } + + fun generateDoWhileLoop(ktDoWhile: KtDoWhileExpression): IrExpression { + val irLoop = IrDoWhileLoopImpl(ktDoWhile.startOffset, ktDoWhile.endOffset, + context.builtIns.unitType, IrStatementOrigin.DO_WHILE_LOOP) + + statementGenerator.bodyGenerator.putLoop(ktDoWhile, irLoop) + + irLoop.body = ktDoWhile.body?.let { ktLoopBody -> + if (ktLoopBody is KtBlockExpression) + generateDoWhileLoopBody(ktLoopBody) + else + statementGenerator.generateExpression(ktLoopBody) + } + + irLoop.condition = statementGenerator.generateExpression(ktDoWhile.condition!!) + + irLoop.label = getLoopLabel(ktDoWhile) + + return IrBlockImpl(ktDoWhile.startOffset, ktDoWhile.endOffset, context.builtIns.unitType).apply { + statements.add(irLoop) } - else - irLoop } private fun generateWhileLoopBody(ktLoopBody: KtBlockExpression): IrExpression = diff --git a/compiler/testData/ir/irText/declarations/localVarInDoWhile.kt b/compiler/testData/ir/irText/declarations/localVarInDoWhile.kt new file mode 100644 index 00000000000..7d7d7ad1b1b --- /dev/null +++ b/compiler/testData/ir/irText/declarations/localVarInDoWhile.kt @@ -0,0 +1,5 @@ +fun foo() { + do { + val x = 42 + } while (x != 42) +} \ No newline at end of file diff --git a/compiler/testData/ir/irText/declarations/localVarInDoWhile.txt b/compiler/testData/ir/irText/declarations/localVarInDoWhile.txt new file mode 100644 index 00000000000..cb43498d9fb --- /dev/null +++ b/compiler/testData/ir/irText/declarations/localVarInDoWhile.txt @@ -0,0 +1,12 @@ +FILE /localVarInDoWhile.kt + FUN public fun foo(): kotlin.Unit + BLOCK_BODY + BLOCK type=kotlin.Unit origin=null + DO_WHILE label=null origin=DO_WHILE_LOOP + body: COMPOSITE type=kotlin.Unit origin=null + VAR val x: kotlin.Int = 42 + CONST Int type=kotlin.Int value='42' + condition: CALL 'NOT(Boolean): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EXCLEQ + arg0: GET_VAR 'x: Int' type=kotlin.Int origin=null + arg1: CONST Int type=kotlin.Int value='42' diff --git a/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt b/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt index cf3af3e01ca..a9abfff7a37 100644 --- a/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt +++ b/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.kt @@ -1,23 +1,35 @@ fun test1(c: Boolean?) { L@ while (true) { - while (c ?: break) + L2@while (c ?: break) } } fun test2(c: Boolean?) { L@ while (true) { - while (c ?: continue) + L2@while (c ?: continue) } } fun test3(ss: List?) { L@ while (true) { - for (s in ss ?: continue) + L2@for (s in ss ?: continue) } } fun test4(ss: List?) { L@ while (true) { - for (s in ss ?: break) + L2@for (s in ss ?: break) + } +} + +fun test5() { + var i = 0 + Outer@while (true) { + ++i + var j = 0 + Inner@do { + ++j + } while (if (j >= 3) false else break) // break@Inner + if (i == 3) break } } \ No newline at end of file diff --git a/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.txt b/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.txt index f2458cdf4b6..58e51bc5094 100644 --- a/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.txt +++ b/compiler/testData/ir/irText/expressions/breakContinueInLoopHeader.txt @@ -5,7 +5,7 @@ FILE /breakContinueInLoopHeader.kt WHILE label=L origin=WHILE_LOOP condition: CONST Boolean type=kotlin.Boolean value='true' body: BLOCK type=kotlin.Unit origin=null - WHILE label=null origin=WHILE_LOOP + WHILE label=L2 origin=WHILE_LOOP condition: BLOCK type=kotlin.Boolean origin=ELVIS VAR IR_TEMPORARY_VARIABLE val tmp0_elvis_lhs: kotlin.Boolean? GET_VAR 'value-parameter c: Boolean?' type=kotlin.Boolean? origin=null @@ -24,7 +24,7 @@ FILE /breakContinueInLoopHeader.kt WHILE label=L origin=WHILE_LOOP condition: CONST Boolean type=kotlin.Boolean value='true' body: BLOCK type=kotlin.Unit origin=null - WHILE label=null origin=WHILE_LOOP + WHILE label=L2 origin=WHILE_LOOP condition: BLOCK type=kotlin.Boolean origin=ELVIS VAR IR_TEMPORARY_VARIABLE val tmp0_elvis_lhs: kotlin.Boolean? GET_VAR 'value-parameter c: Boolean?' type=kotlin.Boolean? origin=null @@ -58,7 +58,7 @@ FILE /breakContinueInLoopHeader.kt BRANCH if: CONST Boolean type=kotlin.Boolean value='true' then: GET_VAR 'tmp0_elvis_lhs: List?' type=kotlin.collections.List? origin=null - WHILE label=null origin=FOR_LOOP_INNER_WHILE + WHILE label=L2 origin=FOR_LOOP_INNER_WHILE condition: CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT $this: GET_VAR 'tmp1_iterator: Iterator' type=kotlin.collections.Iterator origin=null body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE @@ -86,11 +86,50 @@ FILE /breakContinueInLoopHeader.kt BRANCH if: CONST Boolean type=kotlin.Boolean value='true' then: GET_VAR 'tmp0_elvis_lhs: List?' type=kotlin.collections.List? origin=null - WHILE label=null origin=FOR_LOOP_INNER_WHILE + WHILE label=L2 origin=FOR_LOOP_INNER_WHILE condition: CALL 'hasNext(): Boolean' type=kotlin.Boolean origin=FOR_LOOP_HAS_NEXT $this: GET_VAR 'tmp1_iterator: Iterator' type=kotlin.collections.Iterator origin=null body: BLOCK type=kotlin.Unit origin=FOR_LOOP_INNER_WHILE VAR val s: kotlin.String CALL 'next(): String' type=kotlin.String origin=FOR_LOOP_NEXT $this: GET_VAR 'tmp1_iterator: Iterator' type=kotlin.collections.Iterator origin=null - + FUN public fun test5(): kotlin.Unit + BLOCK_BODY + VAR var i: kotlin.Int + CONST Int type=kotlin.Int value='0' + WHILE label=Outer origin=WHILE_LOOP + condition: CONST Boolean type=kotlin.Boolean value='true' + body: BLOCK type=kotlin.Unit origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Int origin=PREFIX_INCR + SET_VAR 'i: Int' type=kotlin.Unit origin=PREFIX_INCR + CALL 'inc(): Int' type=kotlin.Int origin=PREFIX_INCR + $this: GET_VAR 'i: Int' type=kotlin.Int origin=PREFIX_INCR + GET_VAR 'i: Int' type=kotlin.Int origin=PREFIX_INCR + VAR var j: kotlin.Int + CONST Int type=kotlin.Int value='0' + BLOCK type=kotlin.Unit origin=null + DO_WHILE label=Inner origin=DO_WHILE_LOOP + body: COMPOSITE type=kotlin.Unit origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + BLOCK type=kotlin.Int origin=PREFIX_INCR + SET_VAR 'j: Int' type=kotlin.Unit origin=PREFIX_INCR + CALL 'inc(): Int' type=kotlin.Int origin=PREFIX_INCR + $this: GET_VAR 'j: Int' type=kotlin.Int origin=PREFIX_INCR + GET_VAR 'j: Int' type=kotlin.Int origin=PREFIX_INCR + condition: WHEN type=kotlin.Boolean origin=null + BRANCH + if: CALL 'GTEQ0(Int): Boolean' type=kotlin.Boolean origin=GTEQ + arg0: CALL 'compareTo(Int): Int' type=kotlin.Int origin=GTEQ + $this: GET_VAR 'j: Int' type=kotlin.Int origin=null + other: CONST Int type=kotlin.Int value='3' + then: CONST Boolean type=kotlin.Boolean value='false' + BRANCH + if: CONST Boolean type=kotlin.Boolean value='true' + then: BREAK label=null loop.label=Inner + WHEN type=kotlin.Unit origin=null + BRANCH + if: CALL 'EQEQ(Any?, Any?): Boolean' type=kotlin.Boolean origin=EQEQ + arg0: GET_VAR 'i: Int' type=kotlin.Int origin=null + arg1: CONST Int type=kotlin.Int value='3' + then: BREAK label=null loop.label=Outer diff --git a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java index 82628b67c3b..83d2c94fb96 100644 --- a/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/ir/IrTextTestCaseGenerated.java @@ -275,6 +275,12 @@ public class IrTextTestCaseGenerated extends AbstractIrTextTestCase { doTest(fileName); } + @TestMetadata("localVarInDoWhile.kt") + public void testLocalVarInDoWhile() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/localVarInDoWhile.kt"); + doTest(fileName); + } + @TestMetadata("packageLevelProperties.kt") public void testPackageLevelProperties() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/ir/irText/declarations/packageLevelProperties.kt");