1 /*
  2  * Copyright (c) 2023, 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 /*
 25  * @test
 26  * @bug 8304246
 27  * @summary Compiler Implementation for Unnamed patterns and variables
 28  * @compile Unnamed.java
 29  * @run main Unnamed
 30  * @ignore Verifier error
 31  */
 32 
 33 import java.util.Objects;
 34 import java.lang.annotation.ElementType;
 35 import java.lang.annotation.Retention;
 36 import java.lang.annotation.RetentionPolicy;
 37 import java.lang.annotation.Target;
 38 
 39 public class Unnamed {
 40     public static void main(String[] args) throws Throwable {
 41         new Unnamed().run();
 42     }
 43 
 44     public void run() {
 45         assertEquals(1, testMultiValuesTopLevel(new R1()));
 46         assertEquals(2, testMultiValuesTopLevel(new R3()));
 47         assertEquals(1, testMultiValuesTopLevel2(new R1()));
 48         assertEquals(2, testMultiValuesTopLevel2(new R2()));
 49         assertEquals(2, testMultiValuesTopLevel2(new R4()));
 50         assertEquals(1, testMultiValuesNested(new Box<>(new R1())));
 51         assertEquals(1, testMultiValuesNested(new Box<>(new R2())));
 52         assertEquals(2, testMultiValuesNested(new Box<>(new R3())));
 53         assertEquals(3, testMultiValuesNested(new Box<>(new R4())));
 54         assertEquals(1, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R1())));
 55         assertEquals(2, testMultiValuesNestedUnnamedVarAndPattern(new Box<>(new R4())));
 56         assertEquals(1, testMultiValuesNestedMix(new Box<>(new R1())));
 57         assertEquals(1, testMultiValuesNestedMix(new Box2<>(new R1())));
 58         assertEquals(1, testMultiValuesNestedMix2(new Box<>(new R1())));
 59         assertEquals(1, testMultiValuesNestedMix2("BOX"));
 60         assertEquals(2, testMultiValuesNestedMix2(new Box2<>(new R1())));
 61         assertEquals(1, testMultiValuesStatementBlock(42));
 62         assertEquals(1, testMultiValuesStatementBlock(42.0f));
 63         assertEquals(2, testMultiValuesStatementBlock("BOX"));
 64         assertEquals(1, testMultiValuesStatementBlock2(new Box<>(new R1())));
 65         assertEquals(1, testMultiValuesStatementBlock2("BOX"));
 66         assertEquals(2, testMultiValuesStatementBlock2(new Box2<>(new R1())));
 67         assertEquals(2, testMultiValuesGuards(new R3(), 1));
 68         assertEquals(3, testMultiValuesGuards(new R4(), 42));
 69         assertEquals(3, testMultiValuesGuards(new R3(), 42));
 70         assertEquals(1, testMultiValuesNestedGuards(new Box(new R2()), 42));
 71         assertEquals(2, testMultiValuesNestedGuards(new Box(new R3()), 1));
 72         assertEquals(1, testMixUnconditionalAndConditional(new R1()));
 73         assertEquals(2, testMixUnconditionalAndConditional(new R2()));
 74         assertEquals(2, testMixUnconditionalAndConditional(new R3()));
 75         assertEquals(1, testMultipleExpr(new Box<>(new R1())));
 76         assertEquals(1, testUnrolledExpr(new Box<>(new R1())));
 77         assertEquals(1, testMultipleStat(new Box<>(new R1())));
 78         assertEquals(1, testUnrolledStat(new Box<>(new R1())));
 79         assertEquals(2, testMixVarWithExplicit(new Box<>(new R2())));
 80         assertEquals("binding", unnamedGuardAddsBindings("match1", "binding"));
 81         assertEquals("any", unnamedGuardAddsBindings(42, 42));
 82         assertEquals(true, testUnnamedPrimitiveAndExhaustiveness(new Prim1(4)));
 83         assertEquals(false, testUnnamedPrimitiveAndExhaustiveness(new Prim2(5)));
 84 
 85         unnamedTest();
 86     }
 87 
 88     private void unnamedTest() {
 89         int _ = 0;
 90         int _ = 1;
 91         try (Lock _ = null) {
 92             try (Lock _ = null) {
 93             } catch (Exception _) {
 94                 try {
 95                 } catch (Exception _) {}
 96             }
 97         }
 98         try (final Lock _ = null) { }
 99         try (@Foo Lock _ = null) { }
100 
101         try (Lock _ = null) { }
102         catch (Exception | Error _) { }
103 
104         String[] strs = new String[] { "str1", "str2" };
105         for (var _ : strs) {
106             for (var _ : strs) {
107             }
108         }
109         TwoParams p1 = (_, _) -> {};
110         TwoParams p2 = (var _, var _) -> {};
111         TwoIntParams p3 = (int _, int b) -> {};
112         TwoIntParams p4 = (int _, int _) -> {};
113         TwoIntParamsIntRet p5 = (int _, int _) -> { return 1; };
114 
115         p1.run(1, 2);
116         p2.run(1, 2);
117         p3.run(1, 2);
118         p4.run(1, 2);
119         p5.run(1, 2);
120 
121         R r = new R(null);
122         if (r instanceof R _) {}
123         if (r instanceof R(_)) {}
124         for (int _ = 0, _ = 1, x = 1; x <= 1 ; x++) {}
125     }
126 
127     int testMultiValuesTopLevel(Object o) {
128         return switch (o) {
129             case R1 _, R2 _ -> 1;
130             default -> 2;
131         };
132     }
133 
134     int testMultiValuesTopLevel2(Base o) {
135         return switch (o) {
136             case R1 r -> 1;
137             case R2 _, R3 _, R4 _ -> 2;
138         };
139     }
140 
141     int testMultiValuesNested(Box<?> b) {
142         return switch (b) {
143             case Box(R1 _), Box(R2 _) -> 1;
144             case Box(R3 _) -> 2;
145             case Box(_)  -> 3;
146         };
147     }
148 
149     int testMultiValuesNestedUnnamedVarAndPattern(Box<?> b) {
150         return switch (b) {
151             case Box(R1 _), Box(R2 _) -> 1;
152             case Box(R3 _), Box(_) -> 2;
153         };
154     }
155 
156     int testMultiValuesNestedMix(Object b) {
157         return switch (b) {
158             case Box(_), Box2(_) -> 1;
159             default -> 2;
160         };
161     }
162 
163     int testMultiValuesNestedMix2(Object b) {
164         return switch (b) {
165             case Box(_), String _ -> 1;
166             default -> 2;
167         };
168     }
169 
170     int testMultiValuesStatementBlock(Object o) {
171         switch (o) {
172             case Integer _:
173             case Number _:
174                 return 1;
175             default:
176                 return 2;
177         }
178     }
179 
180     int testMultiValuesStatementBlock2(Object o) {
181         switch (o) {
182             case Box(_):
183             case String _:
184                 return 1;
185             default:
186                 return 2;
187         }
188     }
189 
190     int testMultiValuesGuards(Base b, int x) {
191         return switch (b) {
192             case R1 r -> 1;
193             case R2 _, R3 _, R4 _ when x == 1 -> 2;
194             case R2 _, R3 _, R4 _ -> 3;
195         };
196     }
197 
198     int testMultiValuesNestedGuards(Box<?> b, int x) {
199         return switch (b) {
200             case Box(R1 _), Box(R2 _) -> 1;
201             case Box(R3 _), Box(_) when x == 1 -> 2;
202             case Box(_) -> 3;
203         };
204     }
205 
206     int testMixUnconditionalAndConditional(Base t) {
207         return switch(t) {
208             case R1 _ -> 1;
209             case R2 _, Base _-> 2;
210         };
211     }
212 
213     int testMultipleExpr(Box<?> t) {
214         return switch(t) {
215             case Box(R1 _), Box(R2 _) -> 1;
216             default -> -2;
217         };
218     }
219 
220     int testUnrolledExpr(Box<?> t) {
221         return switch(t) {
222             case Box(R1 _) -> 1;
223             case Box(R2 _) -> 0;
224             default -> -2;
225         };
226     }
227 
228     int testMultipleStat(Box<?> t) {
229         int ret = -1;
230         switch(t) {
231             case Box(R1 _), Box(R2 _):
232                 ret = 1;
233                 break;
234             default:
235                 ret = -2;
236         }
237         return ret;
238     }
239 
240     int testUnrolledStat(Box<?> t) {
241         int ret = -1;
242         switch(t) {
243             case Box(R1 _):
244                 ret = 1;
245                 break;
246             case Box(R2 _):
247                 ret = 0;
248                 break;
249             default:
250                 ret = -2;
251         }
252         return ret;
253     }
254 
255     int testMixVarWithExplicit(Box<?> t) {
256         int success = -1;
257         success = switch(t) {
258             case Box(R1 _) : {
259                 yield 1;
260             }
261             case Box(R2 _), Box(var _) : {
262                 yield 2;
263             }
264             default : {
265                 yield -2;
266             }
267         };
268         return success;
269     }
270 
271     String unnamedGuardAddsBindings(Object o1, Object o2) {
272         return switch (o1) {
273             case String _, Object _ when o2 instanceof String s: yield s;
274             case Object _: yield "any";
275         };
276     }
277 
278     boolean testUnnamedPrimitiveAndExhaustiveness(RecordWithPrimitive a) {
279         boolean r1 = switch (a) {
280             case Prim1(var _) -> true;
281             case Prim2(_) -> false;
282         };
283 
284         boolean r2 = switch (a) {
285             case Prim1(var _) -> true;
286             case Prim2(var _) -> false;
287         };
288 
289         boolean r3 = switch (a) {
290             case Prim1(_) -> true;
291             case Prim2(_) -> false;
292         };
293 
294         return r1 && r2 && r3;
295     }
296 
297     sealed interface RecordWithPrimitive permits Prim1, Prim2 {};
298     record Prim1(int n1) implements RecordWithPrimitive {};
299     record Prim2(int n2) implements RecordWithPrimitive {};
300 
301     // JEP 443 examples
302     record Point(int x, int y) { }
303     enum Color { RED, GREEN, BLUE }
304     record ColoredPoint(Point p, Color c) { }
305 
306     void jep443examples(ColoredPoint r) {
307         if (r instanceof ColoredPoint(Point(int x, int y), _)) { }
308         if (r instanceof ColoredPoint(_, Color c)) { }
309         if (r instanceof ColoredPoint(Point(int x, _), _)) { }
310         if (r instanceof ColoredPoint(Point(int x, int _), Color _)) { }
311         if (r instanceof ColoredPoint _) { }
312     }
313 
314     class Lock implements AutoCloseable {
315         @Override
316         public void close() {}
317     }
318     interface TwoParams {
319         public void run(Object o1, Object o2);
320     }
321     interface TwoIntParams {
322         public void run(int o1, int o2);
323     }
324     interface TwoIntParamsIntRet {
325         public int run(int a, int b);
326     }
327     record R(Object o) {}
328     @Target(ElementType.LOCAL_VARIABLE)
329     @Retention(RetentionPolicy.RUNTIME)
330     public @interface Foo { }
331 
332     sealed abstract class Base permits R1, R2, R3, R4 { }
333     final  class R1  extends Base { }
334     final  class R2  extends Base { }
335     final  class R3  extends Base { }
336     final  class R4  extends Base { }
337     record Box<T extends Base>(T content) { }
338     record Box2<T extends Base>(T content) { }
339     void assertEquals(Object expected, Object actual) {
340         if (!Objects.equals(expected, actual)) {
341             throw new AssertionError("Expected: " + expected + ", but got: " + actual);
342         }
343     }
344 }