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