From 25a0854dbd401901d4753b08d5e0218ed724b2b3 Mon Sep 17 00:00:00 2001 From: Michael Nedzelsky Date: Tue, 26 Aug 2014 16:47:22 +0400 Subject: [PATCH] fix KT-5645: 'continue' inside 'do...while' statement works as goto to the beginning of the loop (not checking loop condition) #KT-5645 Fixed --- .../jet/codegen/ExpressionCodegen.java | 18 +++++++++++----- .../jet/lang/cfg/JetControlFlowBuilder.java | 2 ++ .../cfg/JetControlFlowBuilderAdapter.java | 6 ++++++ .../jet/lang/cfg/JetControlFlowProcessor.java | 6 +++++- .../JetControlFlowInstructionsGenerator.java | 8 +++++++ .../controlStructures/doWhileWithContinue.kt | 21 +++++++++++++++++++ .../BlackBoxCodegenTestGenerated.java | 5 +++++ 7 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/codegen/box/controlStructures/doWhileWithContinue.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index c7842d923ba..22b516924f3 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -424,10 +424,11 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitDoWhileExpression(@NotNull JetDoWhileExpression expression, StackValue receiver) { - Label continueLabel = new Label(); - v.mark(continueLabel); + Label beginLoopLabel = new Label(); + v.mark(beginLoopLabel); Label breakLabel = new Label(); + Label continueLabel = new Label(); blockStackElements.push(new LoopBlockStackElement(breakLabel, continueLabel, targetLabel(expression))); @@ -444,17 +445,17 @@ public class ExpressionCodegen extends JetVisitor implem statements.addAll(doWhileStatements); statements.add(condition); - conditionValue = generateBlock(statements, true); + conditionValue = generateBlock(statements, true, continueLabel); } else { if (body != null) { gen(body, Type.VOID_TYPE); } - + v.mark(continueLabel); conditionValue = gen(condition); } - conditionValue.condJump(continueLabel, false, v); + conditionValue.condJump(beginLoopLabel, false, v); v.mark(breakLabel); blockStackElements.pop(); @@ -1411,6 +1412,10 @@ public class ExpressionCodegen extends JetVisitor implem } private StackValue generateBlock(List statements, boolean lastStatementIsExpression) { + return generateBlock(statements, lastStatementIsExpression, null); + } + + private StackValue generateBlock(List statements, boolean lastStatementIsExpression, Label labelBeforeLastExpression) { Label blockEnd = new Label(); List> leaveTasks = Lists.newArrayList(); @@ -1443,6 +1448,9 @@ public class ExpressionCodegen extends JetVisitor implem } boolean isExpression = !iterator.hasNext() && lastStatementIsExpression; + if (isExpression && labelBeforeLastExpression != null) { + v.mark(labelBeforeLastExpression); + } StackValue result = isExpression ? gen(statement) : genStatement(statement); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java index aba297f4f63..4a977e19144 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilder.java @@ -52,6 +52,8 @@ public interface JetControlFlowBuilder { Label getEntryPoint(@NotNull JetElement labelElement); @NotNull Label getExitPoint(@NotNull JetElement labelElement); + @NotNull + Label getConditionEntryPoint(@NotNull JetElement labelElement); // Declarations void declareParameter(@NotNull JetParameter parameter); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java index 75ecb2361a2..0e1fd9c52ae 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowBuilderAdapter.java @@ -183,6 +183,12 @@ public abstract class JetControlFlowBuilderAdapter implements JetControlFlowBuil return getDelegateBuilder().getExitPoint(labelElement); } + @NotNull + @Override + public Label getConditionEntryPoint(@NotNull JetElement labelElement) { + return getDelegateBuilder().getConditionEntryPoint(labelElement); + } + @Override public LoopInfo enterLoop(@NotNull JetExpression expression, @Nullable Label loopExitPoint, Label conditionEntryPoint) { return getDelegateBuilder().enterLoop(expression, loopExitPoint, conditionEntryPoint); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java index 97b1be40fc4..811d2c531af 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/JetControlFlowProcessor.java @@ -953,7 +953,11 @@ public class JetControlFlowProcessor { JetElement loop = getCorrespondingLoop(expression); if (loop != null) { checkJumpDoesNotCrossFunctionBoundary(expression, loop); - builder.jump(builder.getEntryPoint(loop), expression); + if (loop instanceof JetDoWhileExpression) { + builder.jump(builder.getConditionEntryPoint(loop), expression); + } else { + builder.jump(builder.getEntryPoint(loop), expression); + } } } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java index 5c3a00b225f..2547c3cc97d 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/cfg/pseudocode/JetControlFlowInstructionsGenerator.java @@ -200,6 +200,14 @@ public class JetControlFlowInstructionsGenerator extends JetControlFlowBuilderAd return elementToBlockInfo.get(labelElement).getEntryPoint(); } + @NotNull + @Override + public Label getConditionEntryPoint(@NotNull JetElement labelElement) { + BreakableBlockInfo blockInfo = elementToBlockInfo.get(labelElement); + assert blockInfo instanceof LoopInfo : "expected LoopInfo for " + labelElement.getText() ; + return ((LoopInfo)blockInfo).getConditionEntryPoint(); + } + @NotNull @Override public Label getExitPoint(@NotNull JetElement labelElement) { diff --git a/compiler/testData/codegen/box/controlStructures/doWhileWithContinue.kt b/compiler/testData/codegen/box/controlStructures/doWhileWithContinue.kt new file mode 100644 index 00000000000..bb9c73dc6a8 --- /dev/null +++ b/compiler/testData/codegen/box/controlStructures/doWhileWithContinue.kt @@ -0,0 +1,21 @@ +fun box(): String { + var i = 0 + do { + if (i++ > 100) break; + continue; + } while(false) + if (i != 1) return "Fail 1, expected 1, but $i" + + i = 0 + do { + if (i++ > 100) break; + continue; + } while(i<10) + if (i != 10) return "Fail 2, expected 10, but $i" + + i = 0 + do continue while(i++<10) + if (i != 11) return "Fail 3, expected 11, but $i" + + 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 9e56e157289..ee6eb1c38a7 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -1468,6 +1468,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/controlStructures/doWhileFib.kt"); } + @TestMetadata("doWhileWithContinue.kt") + public void testDoWhileWithContinue() throws Exception { + doTest("compiler/testData/codegen/box/controlStructures/doWhileWithContinue.kt"); + } + @TestMetadata("emptyDoWhile.kt") public void testEmptyDoWhile() throws Exception { doTest("compiler/testData/codegen/box/controlStructures/emptyDoWhile.kt");