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