diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index 45570c96490..c649c59f3a9 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -506,7 +506,17 @@ public class ExpressionCodegen extends KtVisitor impleme } @Override - public StackValue visitWhileExpression(@NotNull KtWhileExpression expression, StackValue receiver) { + public StackValue visitWhileExpression(@NotNull final KtWhileExpression expression, StackValue receiver) { + return StackValue.operation(Type.VOID_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter adapter) { + generateWhile(expression); + return Unit.INSTANCE; + } + }); + } + + private void generateWhile(@NotNull KtWhileExpression expression) { Label condition = new Label(); v.mark(condition); @@ -523,13 +533,20 @@ public class ExpressionCodegen extends KtVisitor impleme v.mark(end); blockStackElements.pop(); - - return StackValue.onStack(Type.VOID_TYPE); } - @Override - public StackValue visitDoWhileExpression(@NotNull KtDoWhileExpression expression, StackValue receiver) { + public StackValue visitDoWhileExpression(@NotNull final KtDoWhileExpression expression, StackValue receiver) { + return StackValue.operation(Type.VOID_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter adapter) { + generateDoWhile(expression); + return Unit.INSTANCE; + } + }); + } + + private void generateDoWhile(@NotNull KtDoWhileExpression expression) { Label beginLoopLabel = new Label(); v.mark(beginLoopLabel); @@ -567,25 +584,34 @@ public class ExpressionCodegen extends KtVisitor impleme v.mark(breakLabel); blockStackElements.pop(); - return StackValue.none(); } @Override - public StackValue visitForExpression(@NotNull KtForExpression forExpression, StackValue receiver) { + public StackValue visitForExpression(@NotNull final KtForExpression forExpression, StackValue receiver) { + return StackValue.operation(Type.VOID_TYPE, new Function1() { + @Override + public Unit invoke(InstructionAdapter adapter) { + generateFor(forExpression); + return Unit.INSTANCE; + } + }); + } + + private void generateFor(@NotNull KtForExpression forExpression) { ResolvedCall loopRangeCall = RangeCodegenUtil.getLoopRangeResolvedCall(forExpression, bindingContext); if (loopRangeCall != null) { CallableDescriptor loopRangeCallee = loopRangeCall.getResultingDescriptor(); if (RangeCodegenUtil.isOptimizableRangeTo(loopRangeCallee)) { generateForLoop(createForInRangeLiteralLoopGenerator(forExpression, loopRangeCall)); - return StackValue.none(); + return; } else if (RangeCodegenUtil.isArrayOrPrimitiveArrayIndices(loopRangeCallee)) { generateForLoop(createForInArrayIndicesRangeLoopGenerator(forExpression, loopRangeCall)); - return StackValue.none(); + return; } else if (RangeCodegenUtil.isCollectionIndices(loopRangeCallee)) { generateForLoop(createForInCollectionIndicesRangeLoopGenerator(forExpression, loopRangeCall)); - return StackValue.none(); + return; } } @@ -596,21 +622,16 @@ public class ExpressionCodegen extends KtVisitor impleme Type asmLoopRangeType = asmType(loopRangeType); if (asmLoopRangeType.getSort() == Type.ARRAY) { generateForLoop(new ForInArrayLoopGenerator(forExpression)); - return StackValue.none(); } - - if (RangeCodegenUtil.isRange(loopRangeType)) { + else if (RangeCodegenUtil.isRange(loopRangeType)) { generateForLoop(new ForInRangeInstanceLoopGenerator(forExpression)); - return StackValue.none(); } - - if (RangeCodegenUtil.isProgression(loopRangeType)) { + else if (RangeCodegenUtil.isProgression(loopRangeType)) { generateForLoop(new ForInProgressionExpressionLoopGenerator(forExpression)); - return StackValue.none(); } - - generateForLoop(new IteratorForLoopGenerator(forExpression)); - return StackValue.none(); + else { + generateForLoop(new IteratorForLoopGenerator(forExpression)); + } } private AbstractForLoopGenerator createForInRangeLiteralLoopGenerator( @@ -1705,6 +1726,7 @@ public class ExpressionCodegen extends KtVisitor impleme } // Note that this result value is potentially unused (in case of handleResult coroutine call) + // It's supposed here that no bytecode is emitted until 'put' call on relevant StackValue object StackValue result = isExpression ? gen(possiblyLabeledStatement) : genStatement(possiblyLabeledStatement); if (!iterator.hasNext()) { diff --git a/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt b/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt new file mode 100644 index 00000000000..d5686ab6128 --- /dev/null +++ b/compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt @@ -0,0 +1,51 @@ +class Controller { + var result = "" + var ok = false + suspend fun suspendHere(v: String, x: Continuation) { + result += v + x.resume(Unit) + } + + operator fun handleResult(u: Unit, v: Continuation) { + ok = true + } +} + +fun builder(coroutine c: Controller.() -> Continuation): String { + val controller = Controller() + c(controller).resume(Unit) + if (!controller.ok) throw java.lang.RuntimeException("Fail ok") + return controller.result +} + +fun box(): String { + val r1 = builder { + for (i in 5..6) { + suspendHere(i.toString()) + } + } + + if (r1 != "56") return "fail 1: $r1" + + val r2 = builder { + var i = 7 + while (i <= 8) { + suspendHere(i.toString()) + i++ + } + } + + if (r2 != "78") return "fail 2: $r2" + + val r3 = builder { + var i = 9 + do { + suspendHere(i.toString()) + i++ + } while (i <= 10); + } + + if (r3 != "910") return "fail 3: $r3" + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 047b6165515..e9ea4900d7f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -4183,6 +4183,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("lastExpressionIsLoop.kt") + public void testLastExpressionIsLoop() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastExpressionIsLoop.kt"); + doTest(fileName); + } + @TestMetadata("lastUnitExpression.kt") public void testLastUnitExpression() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/lastUnitExpression.kt");