Skip to content

Commit e734926

Browse files
eric-millesdaniellansun
authored andcommitted
GROOVY-11739: continue jumps to condition of do/while loop
(cherry picked from commit 8328a76)
1 parent 0204002 commit e734926

2 files changed

Lines changed: 77 additions & 51 deletions

File tree

src/main/java/org/codehaus/groovy/classgen/asm/StatementWriter.java

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -262,12 +262,12 @@ public void writeWhileLoop(final WhileStatement statement) {
262262
controller.getAcg().onLineNumber(statement, "visitWhileLoop");
263263
writeStatementLabel(statement);
264264

265-
MethodVisitor mv = controller.getMethodVisitor();
266-
267-
controller.getCompileStack().pushLoop(statement.getStatementLabels());
268-
Label continueLabel = controller.getCompileStack().getContinueLabel();
269-
Label breakLabel = controller.getCompileStack().getBreakLabel();
265+
CompileStack compileStack = controller.getCompileStack();
266+
compileStack.pushLoop(statement.getStatementLabels());
267+
Label continueLabel = compileStack.getContinueLabel();
268+
Label breakLabel = compileStack.getBreakLabel();
270269

270+
MethodVisitor mv = controller.getMethodVisitor();
271271
mv.visitLabel(continueLabel);
272272

273273
visitConditionOfLoopingStatement(statement.getBooleanExpression(), breakLabel, mv);
@@ -276,26 +276,29 @@ public void writeWhileLoop(final WhileStatement statement) {
276276
mv.visitJumpInsn(GOTO, continueLabel);
277277
mv.visitLabel(breakLabel);
278278

279-
controller.getCompileStack().pop();
279+
compileStack.pop();
280280
}
281281

282282
public void writeDoWhileLoop(final DoWhileStatement statement) {
283283
writeStatementLabel(statement);
284284

285-
controller.getCompileStack().pushLoop(statement.getStatementLabels());
286-
Label continueLabel = controller.getCompileStack().getContinueLabel();
287-
Label breakLabel = controller.getCompileStack().getBreakLabel();
285+
CompileStack compileStack = controller.getCompileStack();
286+
compileStack.pushLoop(statement.getStatementLabels());
287+
Label continueLabel = compileStack.getContinueLabel();
288+
Label breakLabel = compileStack.getBreakLabel();
289+
Label blockLabel = new Label();
288290

289291
MethodVisitor mv = controller.getMethodVisitor();
290-
mv.visitLabel(continueLabel);
292+
mv.visitLabel(blockLabel);
291293

292294
statement.getLoopBlock().visit(controller.getAcg());
295+
mv.visitLabel(continueLabel); // GROOVY-11739: continue jumps to condition
293296
visitConditionOfLoopingStatement(statement.getBooleanExpression(), breakLabel, mv);
294297

295-
mv.visitJumpInsn(GOTO, continueLabel);
298+
mv.visitJumpInsn(GOTO, blockLabel);
296299
mv.visitLabel(breakLabel);
297300

298-
controller.getCompileStack().pop();
301+
compileStack.pop();
299302
}
300303

301304
public void writeIfElse(final IfStatement statement) {

src/test/groovy/groovy/BreakContinueLabelTest.groovy

Lines changed: 62 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -18,110 +18,133 @@
1818
*/
1919
package groovy
2020

21-
import gls.CompilableTestSupport
21+
import org.junit.jupiter.api.Test
2222

23-
/**
24-
* todo: add BreakContinueLabelWithClosureTest (when break is used to return from a Closure)
25-
*/
26-
class BreakContinueLabelTest extends CompilableTestSupport {
23+
import static org.junit.jupiter.api.Assertions.fail
24+
25+
final class BreakContinueLabelTest {
2726

27+
@Test
2828
void testDeclareSimpleLabel() {
2929
label_1: assert true
3030
label_2:
3131
assert true
3232
}
33+
34+
@Test
3335
void testBreakLabelInSimpleForLoop() {
3436
label_1: for (i in [1]) {
3537
break label_1
3638
assert false
3739
}
3840
}
3941

42+
@Test
4043
void testBreakLabelInNestedForLoop() {
4144
label: for (i in [1]) {
4245
for (j in [1]){
4346
break label
44-
assert false, 'did not break inner loop'
47+
assert false : 'did not break inner loop'
4548
}
46-
assert false, 'did not break outer loop'
49+
assert false : 'did not break outer loop'
4750
}
4851
}
4952

53+
@Test
5054
void testUnlabelledBreakInNestedForLoop() {
5155
def reached = false
5256
for (i in [1]) {
53-
for (j in [1]){
57+
for (j in [1]) {
5458
break
55-
assert false, 'did not break inner loop'
59+
assert false : 'did not break inner loop'
5660
}
5761
reached = true
5862
}
59-
assert reached, 'must not break outer loop'
63+
assert reached : 'must not break outer loop'
6064
}
6165

66+
@Test
6267
void testBreakLabelInSimpleWhileLoop() {
6368
label_1: while (true) {
6469
break label_1
6570
assert false
6671
}
6772
}
6873

74+
@Test
6975
void testBreakLabelInNestedWhileLoop() {
7076
def count = 0
7177
label: while (count < 1) {
7278
count++
73-
while (true){
79+
while (true) {
7480
break label
75-
assert false, 'did not break inner loop'
81+
assert false : 'did not break inner loop'
7682
}
77-
assert false, 'did not break outer loop'
83+
assert false : 'did not break outer loop'
7884
}
7985
}
8086

87+
@Test
8188
void testBreakLabelInNestedMixedForAndWhileLoop() {
8289
def count = 0
8390
label_1: while (count < 1) {
8491
count++
85-
for (i in [1]){
92+
for (i in [1]) {
8693
break label_1
87-
assert false, 'did not break inner loop'
94+
assert false : 'did not break inner loop'
8895
}
89-
assert false, 'did not break outer loop'
96+
assert false : 'did not break outer loop'
9097
}
9198
label_2: for (i in [1]) {
92-
while (true){
99+
while (true) {
93100
break label_2
94-
assert false, 'did not break inner loop'
101+
assert false : 'did not break inner loop'
95102
}
96-
assert false, 'did not break outer loop'
103+
assert false : 'did not break outer loop'
97104
}
98105
}
99106

107+
// GROOVY-11739
108+
@Test
109+
void testUnlabelledContinueWithinDoWhileLoop() {
110+
int i = 0;
111+
do {
112+
i += 1
113+
if (i > 1000) break // prevent infinite loop
114+
continue // control should pass to condition
115+
} while (i < 100)
116+
117+
assert i == 100
118+
}
119+
120+
@Test
100121
void testUnlabelledContinueInNestedForLoop() {
101122
def log = ''
102123
for (i in [1,2]) {
103124
log += i
104-
for (j in [3,4]){
125+
for (j in [3,4]) {
105126
if (j==3) continue
106127
log += j
107128
}
108129
}
109-
assertEquals '1424',log
130+
assert log == '1424'
110131
}
111132

133+
@Test
112134
void testContinueLabelInNestedForLoop() {
113135
def log = ''
114136
label: for (i in [1,2]) {
115137
log += i
116-
for (j in [3,4]){
138+
for (j in [3,4]) {
117139
if (j==4) continue label
118140
log += j
119141
}
120142
log += 'never reached'
121143
}
122-
assertEquals '1323',log
144+
assert log == '1323'
123145
}
124146

147+
@Test
125148
void testBreakToLastLabelSucceeds() {
126149
one:
127150
two:
@@ -132,25 +155,25 @@ class BreakContinueLabelTest extends CompilableTestSupport {
132155
}
133156
}
134157

158+
@Test
135159
void testMultipleLabelSupport() {
136-
assertScript """
137-
def visited = []
138-
label1:
139-
label2:
140-
label3:
141-
for (int i = 0; i < 9; i++) {
142-
visited << i
143-
if (i == 1) continue label1
144-
visited << 10 + i
145-
if (i == 3) continue label2
146-
visited << 100 + i
147-
if (i == 5) break label3
148-
}
149-
assert visited == [0, 10, 100, 1, 2, 12, 102, 3, 13, 4, 14, 104, 5, 15, 105]
150-
"""
160+
def visited = []
161+
label1:
162+
label2:
163+
label3:
164+
for (int i = 0; i < 9; i++) {
165+
visited << i
166+
if (i == 1) continue label1
167+
visited << 10 + i
168+
if (i == 3) continue label2
169+
visited << 100 + i
170+
if (i == 5) break label3
171+
}
172+
assert visited == [0, 10, 100, 1, 2, 12, 102, 3, 13, 4, 14, 104, 5, 15, 105]
151173
}
152174

153175
// this is in accordance with Java; Spock Framework relies on this
176+
@Test
154177
void testLabelCanOccurMultipleTimesInSameScope() {
155178
one:
156179
for (i in 1..2) {
@@ -163,4 +186,4 @@ class BreakContinueLabelTest extends CompilableTestSupport {
163186
fail()
164187
}
165188
}
166-
}
189+
}

0 commit comments

Comments
 (0)