/* * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /* * @test * @bug 8304246 * @summary Compiler Implementation for Unnamed patterns and variables * @compile Unnamed.java * @run main Unnamed */ import java.util.Objects; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class Unnamed { public static void main(String[] args) throws Throwable { new Unnamed().run(); } public void run() { assertEquals(1, testMultiValuesTopLevel(new R1())); assertEquals(2, testMultiValuesTopLevel(new R3())); assertEquals(1, testMultiValuesTopLevel2(new R1())); assertEquals(2, testMultiValuesTopLevel2(new R2())); assertEquals(2, testMultiValuesTopLevel2(new R4())); assertEquals(1, testMultiValuesNested(new Box<>(new R1()))); assertEquals(1, testMultiValuesNested(new Box<>(new R2()))); assertEquals(2, testMultiValuesNested(new Box<>(new R3()))); assertEquals(3, testMultiValuesNested(new Box<>(new R4()))); assertEquals(1, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R1()))); assertEquals(2, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R4()))); assertEquals(1, testMultiValuesNestedMix(new Box<>(new R1()))); assertEquals(1, testMultiValuesNestedMix(new Box2<>(new R1()))); assertEquals(1, testMultiValuesNestedMix2(new Box<>(new R1()))); assertEquals(1, testMultiValuesNestedMix2("BOX")); assertEquals(2, testMultiValuesNestedMix2(new Box2<>(new R1()))); assertEquals(1, testMultiValuesStatementBlock(42)); assertEquals(1, testMultiValuesStatementBlock(42.0f)); assertEquals(2, testMultiValuesStatementBlock("BOX")); assertEquals(1, testMultiValuesStatementBlock2(new Box<>(new R1()))); assertEquals(1, testMultiValuesStatementBlock2("BOX")); assertEquals(2, testMultiValuesStatementBlock2(new Box2<>(new R1()))); assertEquals(2, testMultiValuesGuards(new R3(), 1)); assertEquals(3, testMultiValuesGuards(new R4(), 42)); assertEquals(3, testMultiValuesGuards(new R3(), 42)); assertEquals(1, testMultiValuesNestedGuards(new Box(new R2()), 42)); assertEquals(2, testMultiValuesNestedGuards(new Box(new R3()), 1)); assertEquals(1, testMixUnconditionalAndConditional(new R1())); assertEquals(2, testMixUnconditionalAndConditional(new R2())); assertEquals(2, testMixUnconditionalAndConditional(new R3())); assertEquals(1, testMultipleExpr(new Box<>(new R1()))); assertEquals(1, testUnrolledExpr(new Box<>(new R1()))); assertEquals(1, testMultipleStat(new Box<>(new R1()))); assertEquals(1, testUnrolledStat(new Box<>(new R1()))); assertEquals(2, testMixVarWithExplicit(new Box<>(new R2()))); assertEquals("binding", unnamedGuardAddsBindings("match1", "binding")); assertEquals("any", unnamedGuardAddsBindings(42, 42)); assertEquals(true, testUnnamedPrimitiveAndExhaustiveness(new Prim1(4))); assertEquals(false, testUnnamedPrimitiveAndExhaustiveness(new Prim2(5))); unnamedTest(); } private void unnamedTest() { int _ = 0; int _ = 1; try (Lock _ = null) { try (Lock _ = null) { } catch (Exception _) { try { } catch (Exception _) {} } } try (final Lock _ = null) { } try (@Foo Lock _ = null) { } try (Lock _ = null) { } catch (Exception | Error _) { } String[] strs = new String[] { "str1", "str2" }; for (var _ : strs) { for (var _ : strs) { } } TwoParams p1 = (_, _) -> {}; TwoParams p2 = (var _, var _) -> {}; TwoIntParams p3 = (int _, int b) -> {}; TwoIntParams p4 = (int _, int _) -> {}; TwoIntParamsIntRet p5 = (int _, int _) -> { return 1; }; p1.run(1, 2); p2.run(1, 2); p3.run(1, 2); p4.run(1, 2); p5.run(1, 2); R r = new R(null); if (r instanceof R _) {} if (r instanceof R(_)) {} for (int _ = 0, _ = 1, x = 1; x <= 1 ; x++) {} } int testMultiValuesTopLevel(Object o) { return switch (o) { case R1 _, R2 _ -> 1; default -> 2; }; } int testMultiValuesTopLevel2(Base o) { return switch (o) { case R1 r -> 1; case R2 _, R3 _, R4 _ -> 2; }; } int testMultiValuesNested(Box b) { return switch (b) { case Box(R1 _), Box(R2 _) -> 1; case Box(R3 _) -> 2; case Box(_) -> 3; }; } int testMultiValuesNestedUnnamedVarAndPattern(Box b) { return switch (b) { case Box(R1 _), Box(R2 _) -> 1; case Box(R3 _), Box(_) -> 2; }; } int testMultiValuesNestedMix(Object b) { return switch (b) { case Box(_), Box2(_) -> 1; default -> 2; }; } int testMultiValuesNestedMix2(Object b) { return switch (b) { case Box(_), String _ -> 1; default -> 2; }; } int testMultiValuesStatementBlock(Object o) { switch (o) { case Integer _: case Number _: return 1; default: return 2; } } int testMultiValuesStatementBlock2(Object o) { switch (o) { case Box(_): case String _: return 1; default: return 2; } } int testMultiValuesGuards(Base b, int x) { return switch (b) { case R1 r -> 1; case R2 _, R3 _, R4 _ when x == 1 -> 2; case R2 _, R3 _, R4 _ -> 3; }; } int testMultiValuesNestedGuards(Box b, int x) { return switch (b) { case Box(R1 _), Box(R2 _) -> 1; case Box(R3 _), Box(_) when x == 1 -> 2; case Box(_) -> 3; }; } int testMixUnconditionalAndConditional(Base t) { return switch(t) { case R1 _ -> 1; case R2 _, Base _-> 2; }; } int testMultipleExpr(Box t) { return switch(t) { case Box(R1 _), Box(R2 _) -> 1; default -> -2; }; } int testUnrolledExpr(Box t) { return switch(t) { case Box(R1 _) -> 1; case Box(R2 _) -> 0; default -> -2; }; } int testMultipleStat(Box t) { int ret = -1; switch(t) { case Box(R1 _), Box(R2 _): ret = 1; break; default: ret = -2; } return ret; } int testUnrolledStat(Box t) { int ret = -1; switch(t) { case Box(R1 _): ret = 1; break; case Box(R2 _): ret = 0; break; default: ret = -2; } return ret; } int testMixVarWithExplicit(Box t) { int success = -1; success = switch(t) { case Box(R1 _) : { yield 1; } case Box(R2 _), Box(var _) : { yield 2; } default : { yield -2; } }; return success; } String unnamedGuardAddsBindings(Object o1, Object o2) { return switch (o1) { case String _, Object _ when o2 instanceof String s: yield s; case Object _: yield "any"; }; } boolean testUnnamedPrimitiveAndExhaustiveness(RecordWithPrimitive a) { boolean r1 = switch (a) { case Prim1(var _) -> true; case Prim2(_) -> false; }; boolean r2 = switch (a) { case Prim1(var _) -> true; case Prim2(var _) -> false; }; boolean r3 = switch (a) { case Prim1(_) -> true; case Prim2(_) -> false; }; return r1 && r2 && r3; } sealed interface RecordWithPrimitive permits Prim1, Prim2 {}; record Prim1(int n1) implements RecordWithPrimitive {}; record Prim2(int n2) implements RecordWithPrimitive {}; // JEP 443 examples record Point(int x, int y) { } enum Color { RED, GREEN, BLUE } record ColoredPoint(Point p, Color c) { } void jep443examples(ColoredPoint r) { if (r instanceof ColoredPoint(Point(int x, int y), _)) { } if (r instanceof ColoredPoint(_, Color c)) { } if (r instanceof ColoredPoint(Point(int x, _), _)) { } if (r instanceof ColoredPoint(Point(int x, int _), Color _)) { } if (r instanceof ColoredPoint _) { } } class Lock implements AutoCloseable { @Override public void close() {} } interface TwoParams { public void run(Object o1, Object o2); } interface TwoIntParams { public void run(int o1, int o2); } interface TwoIntParamsIntRet { public int run(int a, int b); } record R(Object o) {} @Target(ElementType.LOCAL_VARIABLE) @Retention(RetentionPolicy.RUNTIME) public @interface Foo { } sealed abstract class Base permits R1, R2, R3, R4 { } final class R1 extends Base { } final class R2 extends Base { } final class R3 extends Base { } final class R4 extends Base { } record Box(T content) { } record Box2(T content) { } void assertEquals(Object expected, Object actual) { if (!Objects.equals(expected, actual)) { throw new AssertionError("Expected: " + expected + ", but got: " + actual); } } }