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