| /* |
| * 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 |
| * @enablePreview |
| * @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) { } |
| |
| 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 extends Base>(T content) { } |
| record Box2<T extends Base>(T content) { } |
| void assertEquals(Object expected, Object actual) { |
| if (!Objects.equals(expected, actual)) { |
| throw new AssertionError("Expected: " + expected + ", but got: " + actual); |
| } |
| } |
| } |