1 /*
  2  * Copyright (c) 2024, 2026, 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.Reflect;
 25 import java.util.function.Consumer;
 26 import java.util.function.Function;
 27 import java.util.function.IntSupplier;
 28 import java.util.function.Predicate;
 29 import java.util.function.Supplier;
 30 import java.io.Serializable;
 31 
 32 /*
 33  * @test
 34  * @summary Smoke test for code reflection with lambda expressions.
 35  * @modules jdk.incubator.code
 36  * @build LambdaTest
 37  * @build CodeReflectionTester
 38  * @run main CodeReflectionTester LambdaTest
 39  */
 40 
 41 public class LambdaTest {
 42 
 43     @Reflect
 44     @IR("""
 45             func @"test1" (%0 : java.type:"LambdaTest")java.type:"void" -> {
 46                 %1 : java.type:"java.util.function.Consumer<java.lang.String>" = lambda @lambda.isReflectable=true (%2 : java.type:"java.lang.String")java.type:"void" -> {
 47                     %3 : Var<java.type:"java.lang.String"> = var %2 @"s";
 48                     %4 : java.type:"java.io.PrintStream" = field.load @java.ref:"java.lang.System::out:java.io.PrintStream";
 49                     %5 : java.type:"java.lang.String" = var.load %3;
 50                     invoke %4 %5 @java.ref:"java.io.PrintStream::println(java.lang.String):void";
 51                     return;
 52                 };
 53                 %6 : Var<java.type:"java.util.function.Consumer<java.lang.String>"> = var %1 @"c";
 54                 %7 : java.type:"java.util.function.Consumer<java.lang.String>" = var.load %6;
 55                 %8 : java.type:"java.lang.String" = constant @"Hello World";
 56                 invoke %7 %8 @java.ref:"java.util.function.Consumer::accept(java.lang.Object):void";
 57                 return;
 58             };
 59             """)
 60     void test1() {
 61         Consumer<String> c = s -> {
 62             System.out.println(s);
 63         };
 64         c.accept("Hello World");
 65     }
 66 
 67     @Reflect
 68     @IR("""
 69             func @"test2" (%0 : java.type:"LambdaTest")java.type:"void" -> {
 70                 %1 : java.type:"java.util.function.Supplier<java.lang.String>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.String" -> {
 71                     %2 : java.type:"java.lang.String" = constant @"Hello World";
 72                     return %2;
 73                 };
 74                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.String>"> = var %1 @"c";
 75                 %4 : java.type:"java.util.function.Supplier<java.lang.String>" = var.load %3;
 76                 %5 : java.type:"java.lang.String" = invoke %4 @java.ref:"java.util.function.Supplier::get():java.lang.Object";
 77                 %6 : Var<java.type:"java.lang.String"> = var %5 @"s";
 78                 return;
 79             };
 80             """)
 81     void test2() {
 82         Supplier<String> c = () -> {
 83             return "Hello World";
 84         };
 85         String s = c.get();
 86     }
 87 
 88     @Reflect
 89     @IR("""
 90             func @"test3" (%0 : java.type:"LambdaTest")java.type:"void" -> {
 91                 %1 : java.type:"java.util.function.Supplier<java.lang.String>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.String" -> {
 92                     %2 : java.type:"java.lang.String" = constant @"Hello World";
 93                     return %2;
 94                 };
 95                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.String>"> = var %1 @"c";
 96                 return;
 97             };
 98             """)
 99     void test3() {
100         Supplier<String> c = () -> "Hello World";
101     }
102 
103     String s_f;
104 
105     @Reflect
106     @IR("""
107             func @"test4" (%0 : java.type:"LambdaTest")java.type:"void" -> {
108                 %1 : java.type:"java.util.function.Supplier<java.lang.String>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.String" -> {
109                     %2 : java.type:"java.lang.String" = field.load %0 @java.ref:"LambdaTest::s_f:java.lang.String";
110                     return %2;
111                 };
112                 %3 : Var<java.type:"java.util.function.Supplier<java.lang.String>"> = var %1 @"c";
113                 return;
114             };
115             """)
116     void test4() {
117         Supplier<String> c = () -> {
118             return s_f;
119         };
120     }
121 
122     @Reflect
123     @IR("""
124             func @"test5" (%0 : java.type:"LambdaTest", %1 : java.type:"int", %2 : java.type:"int")java.type:"void" -> {
125                 %3 : Var<java.type:"int"> = var %1 @"i";
126                 %4 : Var<java.type:"int"> = var %2 @"j";
127                 %5 : java.type:"int" = constant @3;
128                 %6 : Var<java.type:"int"> = var %5 @"k";
129                 %7 : java.type:"java.util.function.Supplier<java.lang.Integer>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Integer" -> {
130                     %8 : java.type:"int" = constant @4;
131                     %9 : Var<java.type:"int"> = var %8 @"l";
132                     %10 : java.type:"java.util.function.Supplier<java.lang.Integer>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Integer" -> {
133                         %11 : java.type:"int" = var.load %4;
134                         %12 : java.type:"int" = var.load %6;
135                         %13 : java.type:"int" = add %11 %12;
136                         %14 : java.type:"int" = var.load %9;
137                         %15 : java.type:"int" = add %13 %14;
138                         %16 : Var<java.type:"int"> = var %15 @"r";
139                         %17 : java.type:"int" = var.load %16;
140                         %18 : java.type:"java.lang.Integer" = invoke %17 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
141                         return %18;
142                     };
143                     %19 : Var<java.type:"java.util.function.Supplier<java.lang.Integer>"> = var %10 @"sInner";
144                     %20 : java.type:"int" = var.load %3;
145                     %21 : java.type:"java.util.function.Supplier<java.lang.Integer>" = var.load %19;
146                     %22 : java.type:"java.lang.Integer" = invoke %21 @java.ref:"java.util.function.Supplier::get():java.lang.Object";
147                     %23 : java.type:"int" = invoke %22 @java.ref:"java.lang.Integer::intValue():int";
148                     %24 : java.type:"int" = add %20 %23;
149                     %25 : Var<java.type:"int"> = var %24 @"r";
150                     %26 : java.type:"int" = var.load %25;
151                     %27 : java.type:"java.lang.Integer" = invoke %26 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
152                     return %27;
153                 };
154                 %28 : Var<java.type:"java.util.function.Supplier<java.lang.Integer>"> = var %7 @"sOuter";
155                 return;
156             };
157             """)
158     void test5(int i, int j) {
159         int k = 3;
160         Supplier<Integer> sOuter = () -> {
161             int l = 4;
162             Supplier<Integer> sInner = () -> {
163                 int r = j + k + l;
164                 return r;
165             };
166 
167             int r = i + sInner.get();
168             return r;
169         };
170     }
171 
172     int f;
173 
174     @Reflect
175     @IR("""
176             func @"test6" (%0 : java.type:"LambdaTest")java.type:"void" -> {
177                 %1 : java.type:"java.util.function.Supplier<java.lang.Integer>" = lambda @lambda.isReflectable=true ()java.type:"java.lang.Integer" -> {
178                     %2 : java.type:"int" = field.load %0 @java.ref:"LambdaTest::f:int";
179                     %3 : java.type:"java.lang.Integer" = invoke %2 @java.ref:"java.lang.Integer::valueOf(int):java.lang.Integer";
180                     return %3;
181                 };
182                 %4 : Var<java.type:"java.util.function.Supplier<java.lang.Integer>"> = var %1 @"s";
183                 return;
184             };
185             """)
186     void test6() {
187         Supplier<Integer> s = () -> f;
188     }
189 
190     @Reflect
191     @IR("""
192             func @"test7" (%0 : java.type:"LambdaTest")java.type:"java.util.function.Predicate<java.lang.Object>" -> {
193                 %1 : java.type:"java.util.function.Predicate<java.lang.Object>" = lambda @lambda.isReflectable=true (%2 : java.type:"java.lang.Object")java.type:"boolean" -> {
194                     %3 : Var<java.type:"java.lang.Object"> = var %2 @"v";
195                     %4 : Var<java.type:"java.lang.String"> = var @"s";
196                     %5 : java.type:"boolean" = java.cand
197                         ()java.type:"boolean" -> {
198                             %6 : java.type:"java.lang.Object" = var.load %3;
199                             %7 : java.type:"boolean" = pattern.match %6
200                                 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" -> {
201                                     %8 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" = pattern.type @"s";
202                                     yield %8;
203                                 }
204                                 (%9 : java.type:"java.lang.String")java.type:"void" -> {
205                                     var.store %4 %9;
206                                     yield;
207                                 };
208                             yield %7;
209                         }
210                         ()java.type:"boolean" -> {
211                             %10 : java.type:"java.lang.String" = var.load %4;
212                             %11 : java.type:"boolean" = invoke %10 @java.ref:"java.lang.String::isEmpty():boolean";
213                             %12 : java.type:"boolean" = not %11;
214                             yield %12;
215                         };
216                     return %5;
217                 };
218                 return %1;
219             };
220             """)
221     Predicate<Object> test7() {
222         return v -> v instanceof String s && !s.isEmpty();
223     }
224 
225     @Reflect
226     @IR("""
227             func @"f" ()java.type:"void" -> {
228                 %0 : java.type:"java.util.function.Predicate<java.lang.Object>" = lambda @lambda.isReflectable=true (%1 : java.type:"java.lang.Object")java.type:"boolean" -> {
229                     %2 : Var<java.type:"java.lang.Object"> = var %1 @"v";
230                     %3 : Var<java.type:"java.lang.String"> = var @"s";
231                     %4 : java.type:"boolean" = java.cand
232                         ()java.type:"boolean" -> {
233                             %5 : java.type:"java.lang.Object" = var.load %2;
234                             %6 : java.type:"boolean" = pattern.match %5
235                                 ()java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" -> {
236                                     %7 : java.type:"jdk.incubator.code.dialect.java.JavaOp$Pattern$Type<java.lang.String>" = pattern.type @"s";
237                                     yield %7;
238                                 }
239                                 (%8 : java.type:"java.lang.String")java.type:"void" -> {
240                                     var.store %3 %8;
241                                     yield;
242                                 };
243                             yield %6;
244                         }
245                         ()java.type:"boolean" -> {
246                             %9 : java.type:"java.lang.String" = var.load %3;
247                             %10 : java.type:"boolean" = invoke %9 @java.ref:"java.lang.String::isEmpty():boolean";
248                             %11 : java.type:"boolean" = not %10;
249                             yield %11;
250                         };
251                     return %4;
252                 };
253                 return;
254             };
255             """)
256     static Predicate<Object> test8 = v -> v instanceof String s && !s.isEmpty();
257 
258     @Reflect
259     @IR("""
260             func @"constantCapture" ()java.type:"java.util.function.IntSupplier" -> {
261                 %0 : java.type:"int" = constant @1;
262                 %1 : java.type:"int" = constant @2;
263                 %2 : java.type:"int" = add %0 %1;
264                 %3 : java.type:"java.util.function.IntSupplier" = lambda @lambda.isReflectable=true ()java.type:"int" -> {
265                     return %2;
266                 };
267                 return %3;
268             };
269             """)
270     static IntSupplier constantCapture() {
271         final int i = 1 + 2;
272         return () -> i;
273     }
274 
275     @Reflect
276     @IR("""
277             func @"constantAndRuntimeCapture" (%0 : java.type:"int")java.type:"java.util.function.IntSupplier" -> {
278                 %1 : Var<java.type:"int"> = var %0 @"arg";
279                 %2 : java.type:"int" = constant @1;
280                 %3 : java.type:"int" = constant @2;
281                 %4 : java.type:"int" = add %2 %3;
282                 %5 : java.type:"java.util.function.IntSupplier" = lambda @lambda.isReflectable=true ()java.type:"int" -> {
283                     %6 : java.type:"int" = var.load %1;
284                     %7 : java.type:"int" = add %4 %6;
285                     return %7;
286                 };
287                 return %5;
288             };
289             """)
290     static IntSupplier constantAndRuntimeCapture(int arg) {
291         final int i = 1 + 2;
292         return () -> i + arg;
293     }
294 
295     @Reflect
296     @IR("""
297             func @"nestedCaptures" ()java.type:"java.util.function.Supplier<java.util.function.IntSupplier>" -> {
298                 %0 : java.type:"int" = constant @1;
299                 %1 : java.type:"int" = constant @2;
300                 %2 : java.type:"int" = add %0 %1;
301                 %3 : java.type:"java.util.function.Supplier<java.util.function.IntSupplier>" = lambda @lambda.isReflectable=true ()java.type:"java.util.function.IntSupplier" -> {
302                     %4 : java.type:"int" = constant @4;
303                     %5 : java.type:"int" = mul %2 %4;
304                     %6 : java.type:"java.util.function.IntSupplier" = lambda @lambda.isReflectable=true ()java.type:"int" -> {
305                         %7 : java.type:"int" = add %2 %5;
306                         %8 : java.type:"int" = add %7 %2;
307                         %9 : java.type:"int" = add %8 %5;
308                         return %9;
309                     };
310                     return %6;
311                 };
312                 return %3;
313             };
314             """)
315     static Supplier<IntSupplier> nestedCaptures() {
316         final int methodConstant = 1 + 2;
317         return () -> {
318             final int outerConstant = methodConstant * 4;
319             return () -> {
320                 final int innerConstant = methodConstant + outerConstant;
321                 return innerConstant + methodConstant + outerConstant;
322             };
323         };
324     }
325 
326     @Reflect
327     @IR("""
328         func @"intersectionTarget" ()java.type:"java.lang.String" -> {
329             %0 : java.type:"java.util.function.Function<java.lang.String, java.lang.String>" = lambda @lambda.isReflectable=true @lambda.additionalInterfaces=Tuple<java.type:"java.lang.Cloneable"> (%1 : java.type:"java.lang.String")java.type:"java.lang.String" -> {
330                 %2 : Var<java.type:"java.lang.String"> = var %1 @"x";
331                 %3 : java.type:"java.lang.String" = var.load %2;
332                 return %3;
333             };
334             %4 : java.type:"java.lang.Cloneable" = cast %0 @java.type:"java.lang.Cloneable";
335             %5 : Var<java.type:"java.util.function.Function<java.lang.String, java.lang.String>"> = var %4 @"f";
336             %6 : java.type:"java.util.function.Function<java.lang.String, java.lang.String>" = var.load %5;
337             %7 : java.type:"java.lang.String" = constant @"Hello World";
338             %8 : java.type:"java.lang.String" = invoke %6 %7 @java.ref:"java.util.function.Function::apply(java.lang.Object):java.lang.Object";
339             return %8;
340         };
341         """)
342     static String intersectionTarget() {
343         var f = (Function<String, String> & Cloneable) x -> x;
344         return f.apply("Hello World");
345     }
346 }