Generate do-while condition within loop body scope
This commit is contained in:
+33
-25
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user