Generate do-while condition within loop body scope

This commit is contained in:
Dmitry Petrov
2017-05-04 13:38:59 +03:00
parent fdb4de355c
commit 8e84862afa
6 changed files with 116 additions and 34 deletions
@@ -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 =
@@ -0,0 +1,5 @@
fun foo() {
do {
val x = 42
} while (x != 42)
}
@@ -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'
@@ -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<String>?) {
L@ while (true) {
for (s in ss ?: continue)
L2@for (s in ss ?: continue)
}
}
fun test4(ss: List<String>?) {
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
}
}
@@ -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<String>?' type=kotlin.collections.List<kotlin.String>? 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<String>' type=kotlin.collections.Iterator<kotlin.String> 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<String>?' type=kotlin.collections.List<kotlin.String>? 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<String>' type=kotlin.collections.Iterator<kotlin.String> 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<String>' type=kotlin.collections.Iterator<kotlin.String> 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
@@ -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");