diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index dbf51228975..1cebd321e1f 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -55,7 +55,6 @@ import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmClassName; -import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; import org.jetbrains.jet.lang.resolve.scopes.receivers.*; import org.jetbrains.jet.lang.types.JetType; import org.jetbrains.jet.lang.types.checker.JetTypeChecker; @@ -421,22 +420,38 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitDoWhileExpression(JetDoWhileExpression expression, StackValue receiver) { - Label condition = new Label(); - v.mark(condition); + Label continueLabel = new Label(); + v.mark(continueLabel); - Label end = new Label(); + Label breakLabel = new Label(); - blockStackElements.push(new LoopBlockStackElement(end, condition, targetLabel(expression))); + blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression))); - gen(expression.getBody(), Type.VOID_TYPE); + JetExpression body = expression.getBody(); + JetExpression condition = expression.getCondition(); + StackValue conditionValue; - final StackValue conditionValue = gen(expression.getCondition()); - conditionValue.condJump(condition, false, v); + if (body instanceof JetBlockExpression) { + // If body's a block, it can contain variable declarations which may be used in the condition of a do-while loop. + // We handle this case separately because otherwise such variable will be out of the frame map after the block ends + List doWhileStatements = ((JetBlockExpression) body).getStatements(); - v.mark(end); + List statements = new ArrayList(doWhileStatements.size() + 1); + statements.addAll(doWhileStatements); + statements.add(condition); + + conditionValue = generateBlock(statements, true); + } + else { + gen(body, Type.VOID_TYPE); + conditionValue = gen(condition); + } + + conditionValue.condJump(continueLabel, false, v); + v.mark(breakLabel); blockStackElements.pop(); - return StackValue.onStack(Type.VOID_TYPE); + return StackValue.none(); } @Override diff --git a/compiler/testData/codegen/box/controlStructures/doWhile.kt b/compiler/testData/codegen/box/controlStructures/doWhile.kt new file mode 100644 index 00000000000..f9b776c736c --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/doWhile.kt @@ -0,0 +1,15 @@ +fun box(): String { + var x = 0 + do x++ while (x < 5) + if (x != 5) return "Fail 1 $x" + + var y = 0 + do { y++ } while (y < 5) + if (y != 5) return "Fail 2 $y" + + var z = "" + do { z += z.length } while (z.length < 5) + if (z != "01234") return "Fail 3 $z" + + return "OK" +} diff --git a/compiler/testData/codegen/box/controlStructures/doWhileFib.kt b/compiler/testData/codegen/box/controlStructures/doWhileFib.kt new file mode 100644 index 00000000000..088f74cb660 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/doWhileFib.kt @@ -0,0 +1,12 @@ +fun box(): String { + var fx = 1 + var fy = 1 + + do { + var tmp = fy + fy = fx + fy + fx = tmp + } while (fy < 100) + + return if (fy == 144) "OK" else "Fail $fx $fy" +} diff --git a/compiler/testData/codegen/box/controlStructures/kt3280.kt b/compiler/testData/codegen/box/controlStructures/kt3280.kt new file mode 100644 index 00000000000..2a2b87a8f1c --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/kt3280.kt @@ -0,0 +1,24 @@ +fun foo() { + var x = 0 + do { + x++ + var y = x + 5 + } while (y < 10) + if (x != 5) throw AssertionError("$x") +} + +fun bar() { + var b = false + do { + var x = "X" + var y = "Y" + b = true + } while (x + y != "XY") + if (!b) throw AssertionError() +} + +fun box(): String { + foo() + bar() + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 79a2fe432e3..f474b2273dc 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1012,6 +1012,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/continueToLabelInFor.kt"); } + @TestMetadata("doWhile.kt") + public void testDoWhile() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhile.kt"); + } + + @TestMetadata("doWhileFib.kt") + public void testDoWhileFib() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/doWhileFib.kt"); + } + @TestMetadata("finallyOnEmptyReturn.kt") public void testFinallyOnEmptyReturn() throws Exception { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/finallyOnEmptyReturn.kt"); @@ -1157,6 +1167,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3273.kt"); } + @TestMetadata("kt3280.kt") + public void testKt3280() throws Exception { + blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt3280.kt"); + } + @TestMetadata("kt416.kt") public void testKt416() throws Exception { blackBoxFileByFullPath("compiler/testData/codegen/box/controlStructures/kt416.kt");