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.lang.String)java.lang.Object -> { 43 %1 : Var<java.lang.String> = var %0 @"r"; 44 %2 : java.lang.String = var.load %1; 45 %3 : java.lang.Object = java.switch.expression %2 46 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 47 %5 : java.lang.String = constant @"FOO"; 48 %6 : boolean = invoke %4 %5 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 49 yield %6; 50 } 51 ()java.lang.Object -> { 52 %7 : java.lang.String = constant @"FOO"; 53 yield %7; 54 } 55 ^constantCaseLabel(%8 : java.lang.String)boolean -> { 56 %9 : java.lang.String = constant @"BAR"; 57 %10 : boolean = invoke %8 %9 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 58 yield %10; 59 } 60 ()java.lang.Object -> { 61 %11 : java.lang.String = constant @"FOO"; 62 yield %11; 63 } 64 ^constantCaseLabel(%12 : java.lang.String)boolean -> { 65 %13 : java.lang.String = constant @"BAZ"; 66 %14 : boolean = invoke %12 %13 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 67 yield %14; 68 } 69 ()java.lang.Object -> { 70 %15 : java.lang.String = constant @"FOO"; 71 yield %15; 72 } 73 ^defaultCaseLabel()boolean -> { 74 %17 : boolean = constant @"true"; 75 yield %17; 76 } 77 ()java.lang.Object -> { 78 %16 : java.lang.String = constant @""; 79 yield %16; 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.lang.String)java.lang.Object -> { 96 %1 : Var<java.lang.String> = var %0 @"r"; 97 %2 : java.lang.String = var.load %1; 98 %3 : java.lang.Object = java.switch.expression %2 99 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 100 %5 : boolean = java.cor 101 ()boolean -> { 102 %6 : java.lang.String = constant @"FOO"; 103 %7 : boolean = invoke %4 %6 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 104 yield %7; 105 } 106 ()boolean -> { 107 %8 : java.lang.String = constant @"BAR"; 108 %9 : boolean = invoke %4 %8 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 109 yield %9; 110 } 111 ()boolean -> { 112 %10 : java.lang.String = constant @"BAZ"; 113 %11 : boolean = invoke %4 %10 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 114 yield %11; 115 }; 116 yield %5; 117 } 118 ()java.lang.Object -> { 119 %12 : java.lang.String = constant @"FOO"; 120 yield %12; 121 } 122 ^defaultCaseLabel()boolean -> { 123 %14 : boolean = constant @"true"; 124 yield %14; 125 } 126 ()java.lang.Object -> { 127 %13 : java.lang.String = constant @""; 128 java.yield %13; 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.lang.String)java.lang.Object -> { 145 %1 : Var<java.lang.String> = var %0 @"r"; 146 %2 : java.lang.String = var.load %1; 147 %3 : java.lang.Object = java.switch.expression %2 148 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 149 %5 : java.lang.String = constant @"FOO"; 150 %6 : boolean = invoke %4 %5 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 151 yield %6; 152 } 153 ()java.lang.Object -> { 154 %7 : java.lang.String = constant @"FOO"; 155 java.yield %7; 156 } 157 ^constantCaseLabel(%8 : java.lang.String)boolean -> { 158 %9 : java.lang.String = constant @"BAR"; 159 %10 : boolean = invoke %8 %9 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 160 yield %10; 161 } 162 ()java.lang.Object -> { 163 %11 : java.lang.String = constant @"FOO"; 164 java.yield %11; 165 } 166 ^constantCaseLabel(%12 : java.lang.String)boolean -> { 167 %13 : java.lang.String = constant @"BAZ"; 168 %14 : boolean = invoke %12 %13 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 169 yield %14; 170 } 171 ()java.lang.Object -> { 172 %15 : java.lang.String = constant @"FOO"; 173 java.yield %15; 174 } 175 ^defaultCaseLabel()boolean -> { 176 %17 : boolean = constant @"true"; 177 yield %17; 178 } 179 ()java.lang.Object -> { 180 %16 : java.lang.String = constant @""; 181 java.yield %16; 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.lang.String)java.lang.Object -> { 198 %1 : Var<java.lang.String> = var %0 @"r"; 199 %2 : java.lang.String = var.load %1; 200 %3 : java.lang.Object = java.switch.expression %2 201 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 202 %5 : boolean = java.cor 203 ()boolean -> { 204 %6 : java.lang.String = constant @"FOO"; 205 %7 : boolean = invoke %4 %6 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 206 yield %7; 207 } 208 ()boolean -> { 209 %8 : java.lang.String = constant @"BAR"; 210 %9 : boolean = invoke %4 %8 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 211 yield %9; 212 } 213 ()boolean -> { 214 %10 : java.lang.String = constant @"BAZ"; 215 %11 : boolean = invoke %4 %10 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 216 yield %11; 217 }; 218 yield %5; 219 } 220 ()java.lang.Object -> { 221 %12 : java.lang.String = constant @"FOO"; 222 java.yield %12; 223 } 224 ^defaultCaseLabel()boolean -> { 225 %17 : boolean = constant @"true"; 226 yield %17; 227 } 228 ()java.lang.Object -> { 229 java.block ()void -> { 230 %13 : java.lang.String = constant @""; 231 java.yield %13; 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.lang.String)java.lang.Object -> { 248 %1 : Var<java.lang.String> = var %0 @"r"; 249 %2 : java.lang.String = var.load %1; 250 %3 : java.lang.Object = java.switch.expression %2 251 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 252 %5 : java.lang.String = constant @"FOO"; 253 %6 : boolean = invoke %4 %5 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 254 yield %6; 255 } 256 ()java.lang.Object -> { 257 java.block ()void -> { 258 %7 : java.io.PrintStream = field.load @"java.lang.System::out()java.io.PrintStream"; 259 %8 : java.lang.String = constant @"FOO"; 260 invoke %7 %8 @"java.io.PrintStream::println(java.lang.String)void"; 261 yield; 262 }; 263 java.block ()void -> { 264 %9 : java.lang.String = constant @"FOO"; 265 java.yield %9; 266 }; 267 unreachable; 268 } 269 ^defaultCaseLabel()boolean -> { 270 %11 : boolean = constant @"true"; 271 yield %11; 272 } 273 ()java.lang.Object -> { 274 %10 : java.lang.String = constant @""; 275 java.yield %10; 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.lang.String)java.lang.Object -> { 295 %1 : Var<java.lang.String> = var %0 @"r"; 296 %2 : java.lang.String = var.load %1; 297 %3 : java.lang.Object = java.switch.expression %2 298 ^constantCaseLabel(%4 : java.lang.String)boolean -> { 299 %5 : java.lang.String = constant @"FOO"; 300 %6 : boolean = invoke %4 %5 @"java.util.Objects::equals(java.lang.Object, java.lang.Object)boolean"; 301 yield %6; 302 } 303 ()java.lang.Object -> { 304 java.block ()void -> { 305 %7 : java.io.PrintStream = field.load @"java.lang.System::out()java.io.PrintStream"; 306 %8 : java.lang.String = constant @"FOO"; 307 invoke %7 %8 @"java.io.PrintStream::println(java.lang.String)void"; 308 yield; 309 }; 310 java.switch.fallthrough; 311 } 312 ^defaultCaseLabel()boolean -> { 313 %10 : boolean = constant @"true"; 314 yield %10; 315 } 316 ()java.lang.Object -> { 317 %9 : java.lang.String = constant @""; 318 java.yield %9; 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.lang.Object)java.lang.Object -> { 338 %1 : Var<java.lang.Object> = var %0 @"r"; 339 %2 : java.lang.Object = var.load %1; 340 %3 : java.lang.Number = constant @null; 341 %4 : Var<java.lang.Number> = var %3 @"n"; 342 %5 : java.lang.String = constant @null; 343 %6 : Var<java.lang.String> = var %5 @"s"; 344 %7 : java.lang.Object = java.switch.expression %2 345 ^patternCaseLabel(%8 : java.lang.Object)boolean -> { 346 %9 : boolean = pattern.match %8 347 ^pattern()jdk.incubator.code.op.ExtendedOp$Pattern$Record<SwitchExpressionTest$A> -> { 348 %10 : jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.Number> = pattern.type @"n"; 349 %11 : jdk.incubator.code.op.ExtendedOp$Pattern$Record<SwitchExpressionTest$A> = pattern.record %10 @"(java.lang.Number n)SwitchExpressionTest$A"; 350 yield %11; 351 } 352 ^match(%12 : java.lang.Number)void -> { 353 var.store %4 %12; 354 yield; 355 }; 356 yield %9; 357 } 358 ()java.lang.Object -> { 359 %13 : java.lang.Number = var.load %4; 360 java.yield %13; 361 } 362 ^patternCaseLabel(%14 : java.lang.Object)boolean -> { 363 %15 : boolean = pattern.match %14 364 ^pattern()jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> -> { 365 %16 : jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> = pattern.type @"s"; 366 yield %16; 367 } 368 ^match(%17 : java.lang.String)void -> { 369 var.store %6 %17; 370 yield; 371 }; 372 yield %15; 373 } 374 ()java.lang.Object -> { 375 %18 : java.lang.String = var.load %6; 376 java.yield %18; 377 } 378 ^defaultCaseLabel()boolean -> { 379 %10 : boolean = constant @"true"; 380 yield %10; 381 } 382 ()java.lang.Object -> { 383 %19 : java.lang.String = constant @""; 384 java.yield %19; 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.lang.Object)java.lang.Object -> { 406 %1 : Var<java.lang.Object> = var %0 @"r"; 407 %2 : java.lang.Object = var.load %1; 408 %3 : java.lang.Number = constant @null; 409 %4 : Var<java.lang.Number> = var %3 @"n"; 410 %5 : java.lang.String = constant @null; 411 %6 : Var<java.lang.String> = var %5 @"s"; 412 %7 : java.lang.String = constant @null; 413 %8 : Var<java.lang.String> = var %7 @"s"; 414 %9 : java.lang.Object = java.switch.expression %2 415 ^patternCaseLabel(%10 : java.lang.Object)boolean -> { 416 %11 : boolean = pattern.match %10 417 ^pattern()jdk.incubator.code.op.ExtendedOp$Pattern$Record<SwitchExpressionTest$A> -> { 418 %12 : jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.Number> = pattern.type @"n"; 419 %13 : jdk.incubator.code.op.ExtendedOp$Pattern$Record<SwitchExpressionTest$A> = pattern.record %12 @"(java.lang.Number n)SwitchExpressionTest$A"; 420 yield %13; 421 } 422 ^match(%14 : java.lang.Number)void -> { 423 var.store %4 %14; 424 yield; 425 }; 426 yield %11; 427 } 428 ()java.lang.Object -> { 429 %15 : java.lang.Number = var.load %4; 430 java.yield %15; 431 } 432 ^patternCaseLabel(%16 : java.lang.Object)boolean -> { 433 %17 : boolean = java.cand 434 ()boolean -> { 435 %18 : boolean = pattern.match %16 436 ^pattern()jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> -> { 437 %19 : jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> = pattern.type @"s"; 438 yield %19; 439 } 440 ^match(%20 : java.lang.String)void -> { 441 var.store %6 %20; 442 yield; 443 }; 444 yield %18; 445 } 446 ()boolean -> { 447 %21 : java.lang.String = var.load %6; 448 %22 : int = invoke %21 @"java.lang.String::length()int"; 449 %23 : int = constant @"5"; 450 %24 : boolean = lt %22 %23; 451 yield %24; 452 }; 453 yield %17; 454 } 455 ()java.lang.Object -> { 456 %25 : java.lang.String = var.load %6; 457 java.yield %25; 458 } 459 ^patternCaseLabel(%26 : java.lang.Object)boolean -> { 460 %27 : boolean = java.cand 461 ()boolean -> { 462 %28 : boolean = pattern.match %26 463 ^pattern()jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> -> { 464 %29 : jdk.incubator.code.op.ExtendedOp$Pattern$Type<java.lang.String> = pattern.type @"s"; 465 yield %29; 466 } 467 ^match(%30 : java.lang.String)void -> { 468 var.store %8 %30; 469 yield; 470 }; 471 yield %28; 472 } 473 ()boolean -> { 474 %31 : java.lang.String = var.load %8; 475 %32 : int = invoke %31 @"java.lang.String::length()int"; 476 %33 : int = constant @"10"; 477 %34 : boolean = lt %32 %33; 478 yield %34; 479 }; 480 yield %27; 481 } 482 ()java.lang.Object -> { 483 %35 : java.lang.String = var.load %8; 484 java.yield %35; 485 } 486 ^defaultCaseLabel()boolean -> { 487 %37 : boolean = constant @"true"; 488 yield %37; 489 } 490 ()java.lang.Object -> { 491 %36 : java.lang.String = constant @""; 492 java.yield %36; 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 }