1 /*
2 * Copyright (c) 2024, 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.CodeReflection;
25 import java.util.function.Consumer;
26 import java.util.function.Supplier;
27
28 /*
29 * @test
30 * @summary Smoke test for code reflection with switch expressions.
31 * @modules jdk.incubator.code
32 * @enablePreview
33 * @build SwitchExpressionTest
34 * @build CodeReflectionTester
35 * @run main CodeReflectionTester SwitchExpressionTest
36 */
37
38 public class SwitchExpressionTest {
39
40 @CodeReflection
41 @IR("""
42 func @"constantCaseLabelRule" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
43 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
44 %2 : java.type:"java.lang.String" = var.load %1;
45 %3 : java.type:"java.lang.Object" = java.switch.expression %2
46 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
47 %5 : java.type:"java.lang.String" = constant @"FOO";
48 %6 : java.type:"boolean" = invoke %4 %5 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
49 yield %6;
50 }
51 ()java.type:"java.lang.Object" -> {
52 %7 : java.type:"java.lang.String" = constant @"FOO";
53 yield %7;
54 }
55 (%8 : java.type:"java.lang.String")java.type:"boolean" -> {
56 %9 : java.type:"java.lang.String" = constant @"BAR";
57 %10 : java.type:"boolean" = invoke %8 %9 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
58 yield %10;
59 }
60 ()java.type:"java.lang.Object" -> {
61 %11 : java.type:"java.lang.String" = constant @"FOO";
62 yield %11;
63 }
64 (%12 : java.type:"java.lang.String")java.type:"boolean" -> {
65 %13 : java.type:"java.lang.String" = constant @"BAZ";
66 %14 : java.type:"boolean" = invoke %12 %13 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
67 yield %14;
68 }
69 ()java.type:"java.lang.Object" -> {
70 %15 : java.type:"java.lang.String" = constant @"FOO";
71 yield %15;
72 }
73 ()java.type:"boolean" -> {
74 %16 : java.type:"boolean" = constant @true;
75 yield %16;
76 }
77 ()java.type:"java.lang.Object" -> {
78 %17 : java.type:"java.lang.String" = constant @"";
79 yield %17;
80 };
81 return %3;
82 };
83 """)
84 public static Object constantCaseLabelRule(String r) {
85 return switch (r) {
86 case "FOO" -> "FOO";
87 case "BAR" -> "FOO";
88 case "BAZ" -> "FOO";
89 default -> "";
90 };
91 }
92
93 @CodeReflection
94 @IR("""
95 func @"constantCaseLabelsRule" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
96 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
97 %2 : java.type:"java.lang.String" = var.load %1;
98 %3 : java.type:"java.lang.Object" = java.switch.expression %2
99 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
100 %5 : java.type:"boolean" = java.cor
101 ()java.type:"boolean" -> {
102 %6 : java.type:"java.lang.String" = constant @"FOO";
103 %7 : java.type:"boolean" = invoke %4 %6 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
104 yield %7;
105 }
106 ()java.type:"boolean" -> {
107 %8 : java.type:"java.lang.String" = constant @"BAR";
108 %9 : java.type:"boolean" = invoke %4 %8 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
109 yield %9;
110 }
111 ()java.type:"boolean" -> {
112 %10 : java.type:"java.lang.String" = constant @"BAZ";
113 %11 : java.type:"boolean" = invoke %4 %10 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
114 yield %11;
115 };
116 yield %5;
117 }
118 ()java.type:"java.lang.Object" -> {
119 %12 : java.type:"java.lang.String" = constant @"FOO";
120 yield %12;
121 }
122 ()java.type:"boolean" -> {
123 %13 : java.type:"boolean" = constant @true;
124 yield %13;
125 }
126 ()java.type:"java.lang.Object" -> {
127 %14 : java.type:"java.lang.String" = constant @"";
128 java.yield %14;
129 };
130 return %3;
131 };
132 """)
133 public static Object constantCaseLabelsRule(String r) {
134 return switch (r) {
135 case "FOO", "BAR", "BAZ" -> "FOO";
136 default -> {
137 yield "";
138 }
139 };
140 }
141
142 @CodeReflection
143 @IR("""
144 func @"constantCaseLabelStatement" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
145 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
146 %2 : java.type:"java.lang.String" = var.load %1;
147 %3 : java.type:"java.lang.Object" = java.switch.expression %2
148 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
149 %5 : java.type:"java.lang.String" = constant @"FOO";
150 %6 : java.type:"boolean" = invoke %4 %5 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
151 yield %6;
152 }
153 ()java.type:"java.lang.Object" -> {
154 %7 : java.type:"java.lang.String" = constant @"FOO";
155 java.yield %7;
156 }
157 (%8 : java.type:"java.lang.String")java.type:"boolean" -> {
158 %9 : java.type:"java.lang.String" = constant @"BAR";
159 %10 : java.type:"boolean" = invoke %8 %9 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
160 yield %10;
161 }
162 ()java.type:"java.lang.Object" -> {
163 %11 : java.type:"java.lang.String" = constant @"FOO";
164 java.yield %11;
165 }
166 (%12 : java.type:"java.lang.String")java.type:"boolean" -> {
167 %13 : java.type:"java.lang.String" = constant @"BAZ";
168 %14 : java.type:"boolean" = invoke %12 %13 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
169 yield %14;
170 }
171 ()java.type:"java.lang.Object" -> {
172 %15 : java.type:"java.lang.String" = constant @"FOO";
173 java.yield %15;
174 }
175 ()java.type:"boolean" -> {
176 %16 : java.type:"boolean" = constant @true;
177 yield %16;
178 }
179 ()java.type:"java.lang.Object" -> {
180 %17 : java.type:"java.lang.String" = constant @"";
181 java.yield %17;
182 };
183 return %3;
184 };
185 """)
186 public static Object constantCaseLabelStatement(String r) {
187 return switch (r) {
188 case "FOO" : yield "FOO";
189 case "BAR" : yield "FOO";
190 case "BAZ" : yield "FOO";
191 default : yield "";
192 };
193 }
194
195 @CodeReflection
196 @IR("""
197 func @"constantCaseLabelsStatement" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
198 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
199 %2 : java.type:"java.lang.String" = var.load %1;
200 %3 : java.type:"java.lang.Object" = java.switch.expression %2
201 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
202 %5 : java.type:"boolean" = java.cor
203 ()java.type:"boolean" -> {
204 %6 : java.type:"java.lang.String" = constant @"FOO";
205 %7 : java.type:"boolean" = invoke %4 %6 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
206 yield %7;
207 }
208 ()java.type:"boolean" -> {
209 %8 : java.type:"java.lang.String" = constant @"BAR";
210 %9 : java.type:"boolean" = invoke %4 %8 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
211 yield %9;
212 }
213 ()java.type:"boolean" -> {
214 %10 : java.type:"java.lang.String" = constant @"BAZ";
215 %11 : java.type:"boolean" = invoke %4 %10 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
216 yield %11;
217 };
218 yield %5;
219 }
220 ()java.type:"java.lang.Object" -> {
221 %12 : java.type:"java.lang.String" = constant @"FOO";
222 java.yield %12;
223 }
224 ()java.type:"boolean" -> {
225 %13 : java.type:"boolean" = constant @true;
226 yield %13;
227 }
228 ()java.type:"java.lang.Object" -> {
229 java.block ()java.type:"void" -> {
230 %14 : java.type:"java.lang.String" = constant @"";
231 java.yield %14;
232 };
233 unreachable;
234 };
235 return %3;
236 };
237 """)
238 public static Object constantCaseLabelsStatement(String r) {
239 return switch (r) {
240 case "FOO", "BAR", "BAZ" : yield "FOO";
241 default : { yield ""; }
242 };
243 }
244
245 @CodeReflection
246 @IR("""
247 func @"constantCaseLabelStatements" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
248 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
249 %2 : java.type:"java.lang.String" = var.load %1;
250 %3 : java.type:"java.lang.Object" = java.switch.expression %2
251 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
252 %5 : java.type:"java.lang.String" = constant @"FOO";
253 %6 : java.type:"boolean" = invoke %4 %5 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
254 yield %6;
255 }
256 ()java.type:"java.lang.Object" -> {
257 java.block ()java.type:"void" -> {
258 %7 : java.type:"java.io.PrintStream" = field.load @java.ref:"java.lang.System::out:java.io.PrintStream";
259 %8 : java.type:"java.lang.String" = constant @"FOO";
260 invoke %7 %8 @java.ref:"java.io.PrintStream::println(java.lang.String):void";
261 yield;
262 };
263 java.block ()java.type:"void" -> {
264 %9 : java.type:"java.lang.String" = constant @"FOO";
265 java.yield %9;
266 };
267 unreachable;
268 }
269 ()java.type:"boolean" -> {
270 %10 : java.type:"boolean" = constant @true;
271 yield %10;
272 }
273 ()java.type:"java.lang.Object" -> {
274 %11 : java.type:"java.lang.String" = constant @"";
275 java.yield %11;
276 };
277 return %3;
278 };
279 """)
280 public static Object constantCaseLabelStatements(String r) {
281 return switch (r) {
282 case "FOO" : {
283 System.out.println("FOO");
284 }
285 {
286 yield "FOO";
287 }
288 default : yield "";
289 };
290 }
291
292 @CodeReflection
293 @IR("""
294 func @"constantCaseLabelFallthrough" (%0 : java.type:"java.lang.String")java.type:"java.lang.Object" -> {
295 %1 : Var<java.type:"java.lang.String"> = var %0 @"r";
296 %2 : java.type:"java.lang.String" = var.load %1;
297 %3 : java.type:"java.lang.Object" = java.switch.expression %2
298 (%4 : java.type:"java.lang.String")java.type:"boolean" -> {
299 %5 : java.type:"java.lang.String" = constant @"FOO";
300 %6 : java.type:"boolean" = invoke %4 %5 @java.ref:"java.util.Objects::equals(java.lang.Object, java.lang.Object):boolean";
301 yield %6;
302 }
303 ()java.type:"java.lang.Object" -> {
304 java.block ()java.type:"void" -> {
305 %7 : java.type:"java.io.PrintStream" = field.load @java.ref:"java.lang.System::out:java.io.PrintStream";
306 %8 : java.type:"java.lang.String" = constant @"FOO";
307 invoke %7 %8 @java.ref:"java.io.PrintStream::println(java.lang.String):void";
308 yield;
309 };
310 java.switch.fallthrough;
311 }
312 ()java.type:"boolean" -> {
313 %9 : java.type:"boolean" = constant @true;
314 yield %9;
315 }
316 ()java.type:"java.lang.Object" -> {
317 %10 : java.type:"java.lang.String" = constant @"";
318 java.yield %10;
319 };
320 return %3;
321 };
322 """)
323 public static Object constantCaseLabelFallthrough(String r) {
324 return switch (r) {
325 case "FOO" : {
326 System.out.println("FOO");
327 }
328 default : yield "";
329 };
330 }
331
332 record A(Number n) {
333 }
334
335 @CodeReflection
336 @IR("""
337 func @"patternCaseLabel" (%0 : java.type:"java.lang.Object")java.type:"java.lang.Object" -> {
338 %1 : Var<java.type:"java.lang.Object"> = var %0 @"r";
339 %2 : java.type:"java.lang.Object" = var.load %1;
340 %3 : java.type:"java.lang.Number" = constant @null;
341 %4 : Var<java.type:"java.lang.Number"> = var %3 @"n";
342 %5 : java.type:"java.lang.String" = constant @null;
343 %6 : Var<java.type:"java.lang.String"> = var %5 @"s";
344 %7 : java.type:"java.lang.Object" = java.switch.expression %2
345 (%8 : java.type:"java.lang.Object")java.type:"boolean" -> {
346 %9 : java.type:"boolean" = pattern.match %8
347 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Record<SwitchExpressionTest$A>" -> {
348 %10 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.Number>" = pattern.type @"n";
349 %11 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Record<SwitchExpressionTest$A>" = pattern.record %10 @java.ref:"(java.lang.Number n)SwitchExpressionTest$A";
350 yield %11;
351 }
352 (%12 : java.type:"java.lang.Number")java.type:"void" -> {
353 var.store %4 %12;
354 yield;
355 };
356 yield %9;
357 }
358 ()java.type:"java.lang.Object" -> {
359 %13 : java.type:"java.lang.Number" = var.load %4;
360 java.yield %13;
361 }
362 (%14 : java.type:"java.lang.Object")java.type:"boolean" -> {
363 %15 : java.type:"boolean" = pattern.match %14
364 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" -> {
365 %16 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" = pattern.type @"s";
366 yield %16;
367 }
368 (%17 : java.type:"java.lang.String")java.type:"void" -> {
369 var.store %6 %17;
370 yield;
371 };
372 yield %15;
373 }
374 ()java.type:"java.lang.Object" -> {
375 %18 : java.type:"java.lang.String" = var.load %6;
376 java.yield %18;
377 }
378 ()java.type:"boolean" -> {
379 %19 : java.type:"boolean" = constant @true;
380 yield %19;
381 }
382 ()java.type:"java.lang.Object" -> {
383 %20 : java.type:"java.lang.String" = constant @"";
384 java.yield %20;
385 };
386 return %7;
387 };
388 """)
389 public static Object patternCaseLabel(Object r) {
390 return switch (r) {
391 case A(Number n) -> {
392 yield n;
393 }
394 case String s -> {
395 yield s;
396 }
397 default -> {
398 yield "";
399 }
400 };
401 }
402
403 @CodeReflection
404 @IR("""
405 func @"patternCaseLabelGuard" (%0 : java.type:"java.lang.Object")java.type:"java.lang.Object" -> {
406 %1 : Var<java.type:"java.lang.Object"> = var %0 @"r";
407 %2 : java.type:"java.lang.Object" = var.load %1;
408 %3 : java.type:"java.lang.Number" = constant @null;
409 %4 : Var<java.type:"java.lang.Number"> = var %3 @"n";
410 %5 : java.type:"java.lang.String" = constant @null;
411 %6 : Var<java.type:"java.lang.String"> = var %5 @"s";
412 %7 : java.type:"java.lang.String" = constant @null;
413 %8 : Var<java.type:"java.lang.String"> = var %7 @"s";
414 %9 : java.type:"java.lang.Object" = java.switch.expression %2
415 (%10 : java.type:"java.lang.Object")java.type:"boolean" -> {
416 %11 : java.type:"boolean" = pattern.match %10
417 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Record<SwitchExpressionTest$A>" -> {
418 %12 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.Number>" = pattern.type @"n";
419 %13 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Record<SwitchExpressionTest$A>" = pattern.record %12 @java.ref:"(java.lang.Number n)SwitchExpressionTest$A";
420 yield %13;
421 }
422 (%14 : java.type:"java.lang.Number")java.type:"void" -> {
423 var.store %4 %14;
424 yield;
425 };
426 yield %11;
427 }
428 ()java.type:"java.lang.Object" -> {
429 %15 : java.type:"java.lang.Number" = var.load %4;
430 java.yield %15;
431 }
432 (%16 : java.type:"java.lang.Object")java.type:"boolean" -> {
433 %17 : java.type:"boolean" = java.cand
434 ()java.type:"boolean" -> {
435 %18 : java.type:"boolean" = pattern.match %16
436 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" -> {
437 %19 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" = pattern.type @"s";
438 yield %19;
439 }
440 (%20 : java.type:"java.lang.String")java.type:"void" -> {
441 var.store %6 %20;
442 yield;
443 };
444 yield %18;
445 }
446 ()java.type:"boolean" -> {
447 %21 : java.type:"java.lang.String" = var.load %6;
448 %22 : java.type:"int" = invoke %21 @java.ref:"java.lang.String::length():int";
449 %23 : java.type:"int" = constant @5;
450 %24 : java.type:"boolean" = lt %22 %23;
451 yield %24;
452 };
453 yield %17;
454 }
455 ()java.type:"java.lang.Object" -> {
456 %25 : java.type:"java.lang.String" = var.load %6;
457 java.yield %25;
458 }
459 (%26 : java.type:"java.lang.Object")java.type:"boolean" -> {
460 %27 : java.type:"boolean" = java.cand
461 ()java.type:"boolean" -> {
462 %28 : java.type:"boolean" = pattern.match %26
463 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" -> {
464 %29 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" = pattern.type @"s";
465 yield %29;
466 }
467 (%30 : java.type:"java.lang.String")java.type:"void" -> {
468 var.store %8 %30;
469 yield;
470 };
471 yield %28;
472 }
473 ()java.type:"boolean" -> {
474 %31 : java.type:"java.lang.String" = var.load %8;
475 %32 : java.type:"int" = invoke %31 @java.ref:"java.lang.String::length():int";
476 %33 : java.type:"int" = constant @10;
477 %34 : java.type:"boolean" = lt %32 %33;
478 yield %34;
479 };
480 yield %27;
481 }
482 ()java.type:"java.lang.Object" -> {
483 %35 : java.type:"java.lang.String" = var.load %8;
484 java.yield %35;
485 }
486 ()java.type:"boolean" -> {
487 %36 : java.type:"boolean" = constant @true;
488 yield %36;
489 }
490 ()java.type:"java.lang.Object" -> {
491 %37 : java.type:"java.lang.String" = constant @"";
492 java.yield %37;
493 };
494 return %9;
495 };
496 """)
497 public static Object patternCaseLabelGuard(Object r) {
498 return switch (r) {
499 case A(Number n) -> {
500 yield n;
501 }
502 case String s when s.length() < 5 -> {
503 yield s;
504 }
505 case String s when s.length() < 10 -> {
506 yield s;
507 }
508 default -> {
509 yield "";
510 }
511 };
512 }
513 }