1 /*
2 * Copyright (c) 2024, 2026, 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 import jdk.incubator.code.CodeTransformer;
25 import jdk.incubator.code.Op;
26 import jdk.incubator.code.Reflect;
27 import jdk.incubator.code.dialect.core.CoreOp;
28 import jdk.incubator.code.extern.OpWriter;
29 import org.junit.jupiter.api.Assertions;
30 import org.junit.jupiter.api.Test;
31
32 import java.io.IOException;
33 import java.io.OutputStream;
34 import java.io.StringWriter;
35 import java.lang.invoke.MethodHandles;
36 import java.lang.reflect.Method;
37 import java.util.*;
38 import java.util.stream.Stream;
39
40 /*
41 * @test
42 * @modules jdk.incubator.code
43 * @library lib
44 * @run junit TestSwitchStatementOp
45 * @run main Unreflect TestSwitchStatementOp
46 * @run junit TestSwitchStatementOp
47 *
48 */
49 public class TestSwitchStatementOp {
50
51 @Test
52 void testCaseConstantBehaviorIsSyntaxIndependent() {
53 CoreOp.FuncOp ruleExpression = lower("caseConstantRuleExpression");
54 CoreOp.FuncOp ruleBlock = lower("caseConstantRuleBlock");
55 CoreOp.FuncOp statement = lower("caseConstantStatement");
56
57 String[] args = {"FOO", "BAR", "BAZ", "OTHER"};
58
59 for (String arg : args) {
60 Assertions.assertEquals(Interpreter.invoke(MethodHandles.lookup(), ruleBlock, arg), Interpreter.invoke(MethodHandles.lookup(), ruleExpression, arg));
61 Assertions.assertEquals(Interpreter.invoke(MethodHandles.lookup(), statement, arg), Interpreter.invoke(MethodHandles.lookup(), ruleExpression, arg));
62 }
63 }
64
65 @Reflect
66 public static String caseConstantRuleExpression(String r) {
67 String s = "";
68 switch (r) {
69 case "FOO" -> s += "BAR";
70 case "BAR" -> s += "BAZ";
71 case "BAZ" -> s += "FOO";
72 default -> s += "else";
73 }
74 return s;
75 }
76
77 @Reflect
78 public static String caseConstantRuleBlock(String r) {
79 String s = "";
80 switch (r) {
81 case "FOO" -> {
82 s += "BAR";
83 }
84 case "BAR" -> {
85 s += "BAZ";
86 }
87 case "BAZ" -> {
88 s += "FOO";
89 }
90 default -> {
91 s += "else";
92 }
93 }
94 return s;
95 }
96
97 @Reflect
98 private static String caseConstantStatement(String s) {
99 String r = "";
100 switch (s) {
101 case "FOO":
102 r += "BAR";
103 break;
104 case "BAR":
105 r += "BAZ";
106 break;
107 case "BAZ":
108 r += "FOO";
109 break;
110 default:
111 r += "else";
112 }
113 return r;
114 }
115
116 @Test
117 void testCaseConstantMultiLabels() {
118 CoreOp.FuncOp lmodel = lower("caseConstantMultiLabels");
119 char[] args = {'a', 'e', 'i', 'o', 'u', 'j', 'p', 'g'};
120 for (char arg : args) {
121 Assertions.assertEquals(caseConstantMultiLabels(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
122 }
123 }
124
125 @Reflect
126 private static String caseConstantMultiLabels(char c) {
127 String r = "";
128 switch (Character.toLowerCase(c)) {
129 case 'a', 'e', 'i', 'o', 'u':
130 r += "vowel";
131 break;
132 default:
133 r += "consonant";
134 }
135 return r;
136 }
137
138 @Test
139 void testCasePatternMultiLabel() {
140 CoreOp.FuncOp lmodel = lower("casePatternMultiLabel");
141 Object[] args = {(byte) 1, (short) 2, 'A', 3, 4L, 5f, 6d, true, "str"};
142 for (Object arg : args) {
143 Assertions.assertEquals(casePatternMultiLabel(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
144 }
145 }
146
147 @Reflect
148 private static String casePatternMultiLabel(Object o) {
149 String s = null;
150 switch (o) {
151 case Integer _, Long _, Character _, Byte _, Short _-> s = "integral type";
152 default -> s = "non integral type";
153 };
154 return s;
155 }
156
157 @Test
158 void testCasePatternGuardedMultiLabel() {
159 CoreOp.FuncOp lmodel = lower("casePatternGuardedMultiLabel");
160 Object[] args = {(byte) -1, (short) 2, 'A', -3, 4L, -5f, 6d, true, "str"};
161 for (Object arg : args) {
162 Assertions.assertEquals(casePatternGuardedMultiLabel(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
163 }
164 }
165
166 @Reflect
167 private static String casePatternGuardedMultiLabel(Object o) {
168 String s = null;
169 switch (o) {
170 case Integer _, Long _, Byte _, Short _ when ((Number)o).intValue() > 0 -> s = "integral type";
171 default -> s = "non integral type";
172 };
173 return s;
174 }
175
176 @Test
177 void testCaseConstantThrow() {
178 CoreOp.FuncOp lmodel = lower("caseConstantThrow");
179
180 Assertions.assertThrows(IllegalArgumentException.class, () -> Interpreter.invoke(MethodHandles.lookup(), lmodel, 8));
181
182 int[] args = {9, 10};
183 for (int arg : args) {
184 Assertions.assertEquals(caseConstantThrow(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
185 }
186 }
187
188 @Reflect
189 private static String caseConstantThrow(Integer i) {
190 String r = "";
191 switch (i) {
192 case 8 -> throw new IllegalArgumentException();
193 case 9 -> r += "Nine";
194 default -> r += "An integer";
195 }
196 return r;
197 }
198
199 @Test
200 void testCaseConstantNullLabel() {
201 CoreOp.FuncOp lmodel = lower("caseConstantNullLabel");
202 String[] args = {null, "non null"};
203 for (String arg : args) {
204 Assertions.assertEquals(caseConstantNullLabel(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
205 }
206 }
207
208 @Reflect
209 private static String caseConstantNullLabel(String s) {
210 String r = "";
211 switch (s) {
212 case null -> r += "null";
213 default -> r += "non null";
214 }
215 return r;
216 }
217
218 @Test
219 void testCaseConstantFallThrough() {
220 CoreOp.FuncOp lmodel = lower("caseConstantFallThrough");
221 char[] args = {'A', 'B', 'C'};
222 for (char arg : args) {
223 Assertions.assertEquals(caseConstantFallThrough(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
224 }
225 }
226
227 @Reflect
228 private static String caseConstantFallThrough(char c) {
229 String r = "";
230 switch (c) {
231 case 'A':
232 case 'B':
233 r += "A or B";
234 break;
235 default:
236 r += "Neither A nor B";
237 }
238 return r;
239 }
240
241 @Test
242 void testCaseConstantNullAndDefault() {
243 CoreOp.FuncOp lmodel = lower("caseConstantNullAndDefault");
244 String[] args = { "abc", "hello", null };
245 for (String arg : args) {
246 Assertions.assertEquals(caseConstantNullAndDefault(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
247 }
248 }
249
250 @Reflect
251 private static String caseConstantNullAndDefault(String s) {
252 String res = null;
253 switch (s) {
254 case "abc" -> res = "alphabet";
255 case null, default -> res = "null or default";
256 };
257 return res;
258 }
259
260 @Test
261 void testOnlyDefault() {
262 CoreOp.FuncOp lmodel = lower("onlyDefault");
263 String[] args = {"A", "X"};
264 for (String arg : args) {
265 Assertions.assertEquals(onlyDefault(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
266 }
267 }
268
269 @Reflect
270 static String onlyDefault(String s) {
271 String res = null;
272 switch (s) {
273 default : res = "A";
274 };
275 return res;
276 }
277
278 @Test
279 void testCaseConstantEnum() {
280 CoreOp.FuncOp lmodel = lower("caseConstantEnum");
281 for (Day day : Day.values()) {
282 Assertions.assertEquals(caseConstantEnum(day), Interpreter.invoke(MethodHandles.lookup(), lmodel, day));
283 }
284 }
285
286 enum Day {
287 MON, TUE, WED, THU, FRI, SAT, SUN
288 }
289 @Reflect
290 private static String caseConstantEnum(Day d) {
291 String r = "";
292 switch (d) {
293 case MON, FRI, SUN -> r += 6;
294 case TUE -> r += 7;
295 case THU, SAT -> r += 8;
296 case WED -> r += 9;
297 }
298 return r;
299 }
300
301 @Test
302 void testCaseConstantEnumWithDefaultFallThrough() {
303 CoreOp.FuncOp lmodel = lower("caseConstantEnumWithDefaultFallThrough");
304 for (Day day : Day.values()) {
305 Assertions.assertEquals(caseConstantEnumWithDefaultFallThrough(day), Interpreter.invoke(MethodHandles.lookup(), lmodel, day));
306 }
307 }
308
309 @Reflect
310 private static int caseConstantEnumWithDefaultFallThrough(Day d) {
311 switch (d) {
312 case MON, FRI, SUN: return 0;
313 case TUE:
314 default:
315 case WED: return 1;
316 }
317 }
318
319 @Test
320 void testCaseConstantOtherKindsOfExpr() {
321 CoreOp.FuncOp lmodel = lower("caseConstantOtherKindsOfExpr");
322 for (int i = 0; i < 14; i++) {
323 Assertions.assertEquals(caseConstantOtherKindsOfExpr(i), Interpreter.invoke(MethodHandles.lookup(), lmodel, i));
324 }
325 }
326
327 static class Constants {
328 static final int c1 = 12;
329 }
330 @Reflect
331 private static String caseConstantOtherKindsOfExpr(int i) {
332 String r = "";
333 final int eleven = 11;
334 switch (i) {
335 case 1 & 0xF -> r += 1;
336 case 4>>1 -> r += "2";
337 case (int) 3L -> r += 3;
338 case 2<<1 -> r += 4;
339 case 10 / 2 -> r += 5;
340 case 12 - 6 -> r += 6;
341 case 3 + 4 -> r += 7;
342 case 2 * 2 * 2 -> r += 8;
343 case 8 | 1 -> r += 9;
344 case (10) -> r += 10;
345 case eleven -> r += 11;
346 case Constants.c1 -> r += Constants.c1;
347 case 1 > 0 ? 13 : 133 -> r += 13;
348 default -> r += "an int";
349 }
350 return r;
351 }
352
353 @Test
354 void testCaseConstantConv() {
355 CoreOp.FuncOp lmodel = lower("caseConstantConv");
356 for (short i = 1; i < 5; i++) {
357 Assertions.assertEquals(caseConstantConv(i), Interpreter.invoke(MethodHandles.lookup(), lmodel, i));
358 }
359 }
360
361 @Reflect
362 static String caseConstantConv(short a) {
363 final short s = 1;
364 final byte b = 2;
365 String r = "";
366 switch (a) {
367 case s -> r += "one"; // identity, short -> short
368 case b -> r += "two"; // widening primitive conversion, byte -> short
369 case 3 -> r += "three"; // narrowing primitive conversion, int -> short
370 default -> r += "else";
371 }
372 return r;
373 }
374
375 @Test
376 void testCaseConstantConv2() {
377 CoreOp.FuncOp lmodel = lower("caseConstantConv2");
378 Byte[] args = {1, 2, 3};
379 for (Byte arg : args) {
380 Assertions.assertEquals(caseConstantConv2(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
381 }
382 }
383
384 @Reflect
385 static String caseConstantConv2(Byte a) {
386 final byte b = 2;
387 String r = "";
388 switch (a) {
389 case 1 -> r+= "one"; // narrowing primitive conversion followed by a boxing conversion, int -> bye -> Byte
390 case b -> r+= "two"; // boxing, byte -> Byte
391 default -> r+= "default";
392 }
393 return r;
394 }
395
396 @Test
397 void testNonEnhancedSwStatNoDefault() {
398 CoreOp.FuncOp lmodel = lower("nonEnhancedSwStatNoDefault");
399 for (int i = 1; i < 4; i++) {
400 Assertions.assertEquals(nonEnhancedSwStatNoDefault(i), Interpreter.invoke(MethodHandles.lookup(), lmodel, i));
401 }
402 }
403
404 @Reflect
405 static String nonEnhancedSwStatNoDefault(int a) {
406 String r = "";
407 switch (a) {
408 case 1 -> r += "1";
409 case 2 -> r += 2;
410 }
411 return r;
412 }
413
414 // no reason to test enhanced switch statement that has no default
415 // because we can't test for MatchException without separate compilation
416
417 @Test
418 void testEnhancedSwStatUnconditionalPattern() {
419 CoreOp.FuncOp lmodel = lower("enhancedSwStatUnconditionalPattern");
420 String[] args = {"A", "B"};
421 for (String arg : args) {
422 Assertions.assertEquals(enhancedSwStatUnconditionalPattern(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
423 }
424 }
425
426 @Reflect
427 static String enhancedSwStatUnconditionalPattern(String s) {
428 String r = "";
429 switch (s) {
430 case "A" -> r += "A";
431 case Object o -> r += "obj";
432 }
433 return r;
434 }
435
436 @Test
437 void testCasePatternBehaviorIsSyntaxIndependent() {
438 CoreOp.FuncOp ruleExpression = lower("casePatternRuleExpression");
439 CoreOp.FuncOp ruleBlock = lower("casePatternRuleBlock");
440 CoreOp.FuncOp statement = lower("casePatternStatement");
441
442 Object[] args = {1, "2", 3L};
443
444 for (Object arg : args) {
445 Assertions.assertEquals(Interpreter.invoke(MethodHandles.lookup(), ruleBlock, arg), Interpreter.invoke(MethodHandles.lookup(), ruleExpression, arg));
446 Assertions.assertEquals(Interpreter.invoke(MethodHandles.lookup(), statement, arg), Interpreter.invoke(MethodHandles.lookup(), ruleExpression, arg));
447 }
448 }
449
450 @Reflect
451 private static String casePatternRuleExpression(Object o) {
452 String r = "";
453 switch (o) {
454 case Integer i -> r += "integer";
455 case String s -> r+= "string";
456 default -> r+= "else";
457 }
458 return r;
459 }
460
461 @Reflect
462 private static String casePatternRuleBlock(Object o) {
463 String r = "";
464 switch (o) {
465 case Integer i -> {
466 r += "integer";
467 }
468 case String s -> {
469 r += "string";
470 }
471 default -> {
472 r += "else";
473 }
474 }
475 return r;
476 }
477
478 @Reflect
479 private static String casePatternStatement(Object o) {
480 String r = "";
481 switch (o) {
482 case Integer i:
483 r += "integer";
484 break;
485 case String s:
486 r += "string";
487 break;
488 default:
489 r += "else";
490 }
491 return r;
492 }
493
494 @Test
495 void testCasePatternThrow() {
496 CoreOp.FuncOp lmodel = lower("casePatternThrow");
497
498 Object[] args = {Byte.MAX_VALUE, Short.MIN_VALUE, 0, 1L, 11f, 22d};
499 for (Object arg : args) {
500 Assertions.assertThrows(IllegalArgumentException.class, () -> Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
501 }
502
503 Object[] args2 = {"abc", List.of()};
504 for (Object arg : args2) {
505 Assertions.assertEquals(casePatternThrow(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
506 }
507 }
508
509 @Reflect
510 private static String casePatternThrow(Object o) {
511 String r = "";
512 switch (o) {
513 case Number n -> throw new IllegalArgumentException();
514 case String s -> r += "a string";
515 default -> r += o.getClass().getName();
516 }
517 return r;
518 }
519
520 // @@@ when multi patterns is supported, we will test it
521
522 @Test
523 void testCasePatternWithCaseConstant() {
524 CoreOp.FuncOp lmodel = lower("casePatternWithCaseConstant");
525 int[] args = {42, 43, -44, 0};
526 for (int arg : args) {
527 Assertions.assertEquals(casePatternWithCaseConstant(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
528 }
529 }
530
531 @Reflect
532 static String casePatternWithCaseConstant(Integer a) {
533 String r = "";
534 switch (a) {
535 case 42 -> r += "forty two";
536 // @@@ case int will not match, because of the way InstanceOfOp is interpreted
537 case Integer i when i > 0 -> r += "positive int";
538 case Integer i when i < 0 -> r += "negative int";
539 default -> r += "zero";
540 }
541 return r;
542 }
543
544 @Test
545 void testCaseTypePattern() {
546 CoreOp.FuncOp lmodel = lower("caseTypePattern");
547 Object[] args = {"str", new ArrayList<>(), new int[]{}, new Stack[][]{}, new Collection[][][]{}, 8, 'x'};
548 for (Object arg : args) {
549 Assertions.assertEquals(caseTypePattern(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
550 }
551 }
552
553 @Reflect
554 static String caseTypePattern(Object o) {
555 String r = "";
556 switch (o) {
557 case String _ -> r+= "String"; // class
558 case RandomAccess _ -> r+= "RandomAccess"; // interface
559 case int[] _ -> r+= "int[]"; // array primitive
560 case Stack[][] _ -> r+= "Stack[][]"; // array class
561 case Collection[][][] _ -> r+= "Collection[][][]"; // array interface
562 case final Number n -> r+= "Number"; // final modifier
563 default -> r+= "something else";
564 }
565 return r;
566 }
567
568 @Test
569 void testCaseRecordPattern() {
570 // @@@ new R(null) must match the pattern R(Number c), but it doesn't
571 // @@@ test with generic record
572 CoreOp.FuncOp lmodel = lower("caseRecordPattern");
573 Object[] args = {new R(8), new R(1.0), new R(2L), "abc"};
574 for (Object arg : args) {
575 Assertions.assertEquals(caseRecordPattern(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
576 }
577 }
578
579 record R(Number n) {}
580 @Reflect
581 static String caseRecordPattern(Object o) {
582 String r = "";
583 switch (o) {
584 case R(Number n) -> r += "R(_)";
585 default -> r+= "else";
586 }
587 return r;
588 }
589
590 @Test
591 void testCasePatternGuard() {
592 CoreOp.FuncOp lmodel = lower("casePatternGuard");
593 Object[] args = {"c++", "java", new R(8), new R(2L), new R(3f), new R(4.0)};
594 for (Object arg : args) {
595 Assertions.assertEquals(casePatternGuard(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
596 }
597 }
598
599 @Reflect
600 static String casePatternGuard(Object obj) {
601 String r = "";
602 switch (obj) {
603 case String s when s.length() > 3 -> r += "str with length > %d".formatted(s.length());
604 case R(Number n) when n.getClass().equals(Double.class) -> r += "R(Double)";
605 default -> r += "else";
606 }
607 return r;
608 }
609
610 @Test
611 void testDefaultCaseNotTheLast() {
612 CoreOp.FuncOp lmodel = lower("defaultCaseNotTheLast");
613 String[] args = {"something", "M", "A"};
614 for (String arg : args) {
615 Assertions.assertEquals(defaultCaseNotTheLast(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
616 }
617 }
618
619 @Reflect
620 static String defaultCaseNotTheLast(String s) {
621 String r = "";
622 switch (s) {
623 default -> r += "else";
624 case "M" -> r += "Mow";
625 case "A" -> r += "Aow";
626 }
627 return r;
628 }
629
630 @Reflect
631 static String caseConstantPrimitiveWrapperSelector(Integer i) {
632 String r = "";
633 switch (i) {
634 case 1 -> r += "one";
635 case 2, 3 -> r += "two or three";
636 default -> r += "else";
637 };
638 return r;
639 }
640
641 @Test
642 void testCaseConstantPrimitiveWrapperSelector() {
643 CoreOp.FuncOp lf = lower("caseConstantPrimitiveWrapperSelector");
644 Integer[] args = {1, 2, 3, 4};
645 for (Integer a : args) {
646 Assertions.assertEquals(caseConstantPrimitiveWrapperSelector(a),
647 Interpreter.invoke(MethodHandles.lookup(), lf, a));
648 }
649 }
650
651 @Reflect
652 static String constantLabelCasted(int i) {
653 String r = "";
654 switch (i) {
655 case (byte) 1 -> r += "one";
656 default -> r += "not one";
657 };
658 return r;
659 }
660
661 @Test
662 void testConstantLabelCasted() {
663 CoreOp.FuncOp lf = lower("constantLabelCasted");
664 int[] args = {-1, 1};
665 for (int a : args) {
666 Assertions.assertEquals(constantLabelCasted(a), Interpreter.invoke(MethodHandles.lookup(), lf, a));
667 }
668 }
669
670 @Reflect
671 static String caseConstantStringLiteral(String s) {
672 String r = "";
673 switch (s) {
674 case "1" -> r += "one";
675 case "2", "3" -> r+= "two or three";
676 default -> r += "else";
677 };
678 return r;
679 }
680
681 @Test
682 void testCeaseConstantStringLiteral() {
683 CoreOp.FuncOp lf = lower("caseConstantStringLiteral");
684 String[] args = {"1", "2", "3", ""};
685 for (String a : args) {
686 Assertions.assertEquals(caseConstantStringLiteral(a), Interpreter.invoke(MethodHandles.lookup(), lf, a));
687 }
688 }
689
690 @Test
691 void testTryAndSwitch() {
692 CoreOp.FuncOp lmodel = lower("tryAndSwitch");
693 String[] args = {"A", "B"};
694 for (String arg : args) {
695 Assertions.assertEquals(tryAndSwitch(arg), Interpreter.invoke(MethodHandles.lookup(), lmodel, arg));
696 }
697 }
698
699 @Reflect
700 private static List<String> tryAndSwitch(String s) {
701 List<String> r = new ArrayList<>();
702 try {
703 switch (s) {
704 case "A":
705 r.add("A");
706 return r;
707 default:
708 r.add("B");
709 }
710 } finally {
711 r.add("finally");
712 }
713 return r;
714 }
715
716 @Reflect
717 private static int caseReassignVar(int sel) {
718 switch (sel) {
719 case 0:
720 int i = 1;
721 return i;
722 case 1:
723 i = 2;
724 return i;
725 default:
726 return -1;
727 }
728 }
729
730 @Reflect
731 private static int caseReassignVarFallThrough(int sel) {
732 switch (sel) {
733 case 0:
734 int i = 1;
735 case 1:
736 i = 2;
737 return i;
738 default:
739 return -1;
740 }
741 }
742
743 @Reflect
744 private static int caseReassignVarNested(int sel) {
745 switch (sel) {
746 case 0:
747 int i = 1;
748 return i;
749 case 1:
750 int j = (i = 2);
751 return i + j;
752 default:
753 return -1;
754 }
755 }
756
757 @Reflect
758 private static int caseReassignVarNestedBlock(int sel) {
759 switch (sel) {
760 case 0:
761 int i = 1;
762 return i;
763 case 1:
764 {
765 i = 2;
766 }
767 return i;
768 default:
769 return -1;
770 }
771 }
772
773 @Reflect
774 private static int caseReassignVarExpression(int sel) {
775 switch (sel) {
776 case 0:
777 int i = 1;
778 return i;
779 case 1:
780 return i = 2;
781 default:
782 return -1;
783 }
784 }
785
786 @Test
787 void testCaseReassignVar() {
788 CoreOp.FuncOp lfrv = lower("caseReassignVar");
789 CoreOp.FuncOp lfrvft = lower("caseReassignVarFallThrough");
790 CoreOp.FuncOp lfrvn = lower("caseReassignVarNested");
791 CoreOp.FuncOp lfrvnb = lower("caseReassignVarNestedBlock");
792 CoreOp.FuncOp lfrve = lower("caseReassignVarExpression");
793 int[] args = {0, 1, 2};
794 for (int a : args) {
795 Assertions.assertEquals(caseReassignVar(a), Interpreter.invoke(MethodHandles.lookup(), lfrv, a));
796 Assertions.assertEquals(caseReassignVarFallThrough(a), Interpreter.invoke(MethodHandles.lookup(), lfrvft, a));
797 Assertions.assertEquals(caseReassignVarNested(a), Interpreter.invoke(MethodHandles.lookup(), lfrvn, a));
798 Assertions.assertEquals(caseReassignVarNestedBlock(a), Interpreter.invoke(MethodHandles.lookup(), lfrvnb, a));
799 Assertions.assertEquals(caseReassignVarExpression(a), Interpreter.invoke(MethodHandles.lookup(), lfrve, a));
800 }
801 }
802
803 private static CoreOp.FuncOp lower(String methodName) {
804 return lower(getCodeModel(methodName));
805 }
806
807 private static CoreOp.FuncOp lower(CoreOp.FuncOp f) {
808 writeModel(f, System.out, OpWriter.LocationOption.DROP_LOCATION);
809
810 CoreOp.FuncOp lf = f.transform(CodeTransformer.LOWERING_TRANSFORMER);
811 writeModel(lf, System.out, OpWriter.LocationOption.DROP_LOCATION);
812
813 return lf;
814 }
815
816 private static void writeModel(CoreOp.FuncOp f, OutputStream os, OpWriter.Option... options) {
817 StringWriter sw = new StringWriter();
818 new OpWriter(sw, options).writeOp(f);
819 try {
820 os.write(sw.toString().getBytes());
821 } catch (IOException e) {
822 throw new RuntimeException(e);
823 }
824 }
825
826 private static CoreOp.FuncOp getCodeModel(String methodName) {
827 Optional<Method> om = Stream.of(TestSwitchStatementOp.class.getDeclaredMethods())
828 .filter(m -> m.getName().equals(methodName))
829 .findFirst();
830
831 return Op.ofMethod(om.get()).get();
832 }
833 }