Skip to content

Commit 742ff74

Browse files
biboudislahodaj
authored andcommitted
8314226: Series of colon-style fallthrough switch cases with guards compiled incorrectly
Backport-of: 3b0a6d2a6842962218b8cebcd9c0672cb4ee6720
1 parent cea4062 commit 742ff74

File tree

2 files changed

+218
-1
lines changed

2 files changed

+218
-1
lines changed

Diff for: src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java

+51-1
Original file line numberDiff line numberDiff line change
@@ -524,6 +524,8 @@ private void handleSwitch(JCTree tree,
524524
boolean previousCompletesNormally = false;
525525
boolean hasDefault = false;
526526

527+
patchCompletingNormallyCases(cases);
528+
527529
for (var c : cases) {
528530
List<JCCaseLabel> clearedPatterns = c.labels;
529531
boolean hasJoinedNull =
@@ -541,7 +543,8 @@ private void handleSwitch(JCTree tree,
541543
validCaseLabelList = clearedPatterns.head.hasTag(Tag.PATTERNCASELABEL);
542544
}
543545

544-
if (validCaseLabelList && !previousCompletesNormally) {
546+
if ((validCaseLabelList && !previousCompletesNormally) ||
547+
c.guard != null) {
545548
List<JCPatternCaseLabel> labels = clearedPatterns.stream().map(cp -> (JCPatternCaseLabel)cp).collect(List.collector());
546549
bindingContext = new BasicBindingContext();
547550
VarSymbol prevCurrentValue = currentValue;
@@ -657,6 +660,53 @@ private void handleSwitch(JCTree tree,
657660
super.visitSwitchExpression((JCSwitchExpression) tree);
658661
}
659662
}
663+
664+
// Duplicates the block statement where needed.
665+
// Processes cases in place, e.g.
666+
// switch (obj) {
667+
// case Integer _ when ((Integer) obj) > 0:
668+
// case String _ when !((String) obj).isEmpty():
669+
// return 1;
670+
// ...
671+
// }
672+
// =>
673+
// switch (typeSwitch(...)) {
674+
// case 0:
675+
// if (!((Integer)obj) > 0) { ... }
676+
// return 1;
677+
// case 1:
678+
// if (!((String)obj).isEmpty()) { ... }
679+
// return 1;
680+
// ...
681+
// }
682+
private static void patchCompletingNormallyCases(List<JCCase> cases) {
683+
while (cases.nonEmpty()) {
684+
var currentCase = cases.head;
685+
686+
if (currentCase.caseKind == CaseKind.STATEMENT &&
687+
currentCase.completesNormally &&
688+
cases.tail.nonEmpty() &&
689+
cases.tail.head.guard != null) {
690+
ListBuffer<JCStatement> newStatements = new ListBuffer<>();
691+
List<JCCase> copyFrom = cases;
692+
693+
while (copyFrom.nonEmpty()) {
694+
newStatements.appendList(copyFrom.head.stats);
695+
696+
if (!copyFrom.head.completesNormally) {
697+
break;
698+
}
699+
700+
copyFrom = copyFrom.tail;
701+
};
702+
703+
currentCase.stats = newStatements.toList();
704+
}
705+
706+
cases = cases.tail;
707+
}
708+
}
709+
660710
//where:
661711
private void fixupContinue(JCTree switchTree, JCCase c, VarSymbol indexVariable, int currentCaseIndex) {
662712
//inject 'index = currentCaseIndex + 1;` before continue which has the current switch as the target

Diff for: test/langtools/tools/javac/patterns/T8314226.java

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
/*
2+
* Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
/**
24+
* @test
25+
* @bug 8314226
26+
* @summary Series of colon-style fallthrough switch cases with guards compiled incorrectly
27+
* @enablePreview
28+
* @compile T8314226.java
29+
* @run main T8314226
30+
*/
31+
32+
public class T8314226 {
33+
int multipleGuardedCases(Object obj) {
34+
switch (obj) {
35+
case Integer _ when ((Integer) obj) > 0:
36+
case String _ when !((String) obj).isEmpty():
37+
return 1;
38+
default:
39+
return -1;
40+
}
41+
}
42+
43+
int multipleGuardedCases2a(Object obj) {
44+
switch (obj) {
45+
case Integer _ when ((Integer) obj) > 0:
46+
case Float _ when ((Float) obj) > 0.0f:
47+
case String _ when !((String) obj).isEmpty():
48+
return 1;
49+
default:
50+
return -1;
51+
}
52+
}
53+
54+
int multipleGuardedCases2b(Object obj) {
55+
switch (obj) {
56+
case Float _ when ((Float) obj) > 0.0f: // reversing the order
57+
case Integer _ when ((Integer) obj) > 0:
58+
case String _ when !((String) obj).isEmpty():
59+
return 1;
60+
default:
61+
return -1;
62+
}
63+
}
64+
65+
int multipleGuardedCasesMultiplePatterns(Object obj) {
66+
switch (obj) {
67+
case String _ when !((String) obj).isEmpty():
68+
case Integer _, Byte _ when ((Number) obj).intValue() > 0:
69+
return 1;
70+
default:
71+
return -1;
72+
}
73+
}
74+
75+
int singleGuardedCase(Object obj) {
76+
switch (obj) {
77+
case String _ when !((String) obj).isEmpty():
78+
return 1;
79+
default:
80+
return -1;
81+
}
82+
}
83+
84+
int multipleCasesWithReturn(Object obj) {
85+
switch (obj) {
86+
case Integer _ when ((Integer) obj) > 0:
87+
case String _ when !((String) obj).isEmpty():
88+
return 1;
89+
case null:
90+
return 2;
91+
default:
92+
return 3;
93+
}
94+
}
95+
96+
int multipleCasesWithEffectNoReturn(Object obj) {
97+
int i = 0;
98+
switch (obj) {
99+
case Integer _ when ((Integer) obj) > 0:
100+
case String _ when !((String) obj).isEmpty():
101+
i = i + 1;
102+
case null:
103+
i = i + 10;
104+
default:
105+
i = i + 100;
106+
}
107+
return i;
108+
}
109+
110+
int multipleCasesWithLoop(Object obj) {
111+
int i = 0;
112+
switch (obj) {
113+
case Integer _ when ((Integer) obj) > 0:
114+
case String _ when !((String) obj).isEmpty():
115+
i = i + 1;
116+
case null:
117+
while (true) {
118+
i = i + 10;
119+
break;
120+
}
121+
default:
122+
i = i + 100;
123+
}
124+
125+
return i;
126+
}
127+
128+
public static void main(String[] args) {
129+
new T8314226().run();
130+
}
131+
132+
private void run() {
133+
assertEquals(1, multipleGuardedCases(42));
134+
assertEquals(1, multipleGuardedCases("test"));
135+
assertEquals(-1, multipleGuardedCases(""));
136+
assertEquals(1, multipleGuardedCases2a(42.0f));
137+
assertEquals(1, multipleGuardedCases2a("test"));
138+
assertEquals(-1, multipleGuardedCases2a(""));
139+
assertEquals(1, multipleGuardedCases2b(42.0f));
140+
assertEquals(1, multipleGuardedCases2b("test"));
141+
assertEquals(-1, multipleGuardedCases2b(""));
142+
assertEquals(1, multipleGuardedCasesMultiplePatterns((byte) 42));
143+
assertEquals(1, multipleGuardedCasesMultiplePatterns("test"));
144+
assertEquals(-1, multipleGuardedCasesMultiplePatterns(""));
145+
assertEquals(-1, singleGuardedCase(42));
146+
assertEquals(1, singleGuardedCase("test"));
147+
assertEquals(-1, singleGuardedCase(""));
148+
assertEquals(1, multipleCasesWithReturn(42));
149+
assertEquals(1, multipleCasesWithReturn("test"));
150+
assertEquals(2, multipleCasesWithReturn(null));
151+
assertEquals(3, multipleCasesWithReturn(""));
152+
assertEquals(111, multipleCasesWithEffectNoReturn(42));
153+
assertEquals(111, multipleCasesWithEffectNoReturn("test"));
154+
assertEquals(110, multipleCasesWithEffectNoReturn(null));
155+
assertEquals(100, multipleCasesWithEffectNoReturn(""));
156+
assertEquals(111, multipleCasesWithLoop(42));
157+
assertEquals(111, multipleCasesWithLoop("test"));
158+
assertEquals(110, multipleCasesWithLoop(null));
159+
assertEquals(100, multipleCasesWithLoop(""));
160+
}
161+
162+
void assertEquals(Object expected, Object actual) {
163+
if (expected != actual) {
164+
throw new AssertionError("Expected: " + expected + ", but got: " + actual);
165+
}
166+
}
167+
}

0 commit comments

Comments
 (0)