1 /*
  2  * Copyright (c) 2024, 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  * @summary Smoke test for code reflection with quotable lambdas.
 27  * @modules jdk.incubator.code
 28  * @build ReflectableLambdaTest
 29  * @build CodeReflectionTester
 30  * @run main CodeReflectionTester ReflectableLambdaTest
 31  */
 32 
 33 import jdk.incubator.code.Reflect;
 34 import java.util.function.IntBinaryOperator;
 35 import java.util.function.IntFunction;
 36 import java.util.function.IntSupplier;
 37 import java.util.function.IntUnaryOperator;
 38 
 39 public class ReflectableLambdaTest {
 40     @IR("""
 41             func @"f" ()java.type:"void" -> {
 42                 %0 : java.type:"java.lang.Runnable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
 43                     return;
 44                 };
 45                 return;
 46             };
 47             """)
 48     static final Runnable QUOTED_NO_PARAM_VOID = (@Reflect Runnable) () -> {
 49     };
 50 
 51     @IR("""
 52             func @"f" ()java.type:"void" -> {
 53                 %0 : java.type:"java.util.function.IntSupplier" = lambda @lambda.isQuotable=true ()java.type:"int" -> {
 54                     %1 : java.type:"int" = constant @1;
 55                     return %1;
 56                 };
 57                 return;
 58             };
 59             """)
 60     static final IntSupplier QUOTED_NO_PARAM_CONST = (@Reflect IntSupplier) () -> 1;
 61 
 62     @IR("""
 63             func @"f" ()java.type:"void" -> {
 64                 %0 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int" -> {
 65                     %2 : Var<java.type:"int"> = var %1 @"x";
 66                     %3 : java.type:"int" = var.load %2;
 67                     return %3;
 68                 };
 69                 return;
 70             };
 71             """)
 72     static final IntUnaryOperator QUOTED_ID = (@Reflect IntUnaryOperator) x -> x;
 73 
 74     @IR("""
 75             func @"f" ()java.type:"void" -> {
 76                 %0 : java.type:"java.util.function.IntBinaryOperator" = lambda @lambda.isQuotable=true (%1 : java.type:"int", %2 : java.type:"int")java.type:"int" -> {
 77                     %3 : Var<java.type:"int"> = var %1 @"x";
 78                     %4 : Var<java.type:"int"> = var %2 @"y";
 79                     %5 : java.type:"int" = var.load %3;
 80                     %6 : java.type:"int" = var.load %4;
 81                     %7 : java.type:"int" = add %5 %6;
 82                     return %7;
 83                 };
 84                 return;
 85             };
 86             """)
 87     static final IntBinaryOperator QUOTED_PLUS = (@Reflect IntBinaryOperator) (x, y) -> x + y;
 88 
 89     @IR("""
 90             func @"f" ()java.type:"void" -> {
 91                 %0 : java.type:"java.lang.Runnable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
 92                     %1 : java.type:"java.lang.AssertionError" = new @java.ref:"java.lang.AssertionError::()";
 93                     throw %1;
 94                 };
 95                 return;
 96             };
 97             """)
 98     static final Runnable QUOTED_THROW_NO_PARAM = (@Reflect Runnable) () -> {
 99         throw new AssertionError();
100     };
101 
102     @IR("""
103             func @"f" (%0 : Var<java.type:"int">)java.type:"void" -> {
104                 %1 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
105                     %3 : Var<java.type:"int"> = var %2 @"y";
106                     %4 : java.type:"int" = var.load %0;
107                     %5 : java.type:"int" = var.load %3;
108                     %6 : java.type:"int" = add %4 %5;
109                     return %6;
110                 };
111                 return;
112             };
113             """)
114     static final IntUnaryOperator QUOTED_CAPTURE_PARAM = new Object() {
115         IntUnaryOperator captureContext(int x) {
116             return (@Reflect IntUnaryOperator) y -> x + y;
117         }
118     }.captureContext(42);
119 
120     static class Context {
121         int x, y;
122 
123         IntUnaryOperator capture() {
124             return (@Reflect IntUnaryOperator) z -> x + y + z;
125         }
126     }
127 
128     @IR("""
129             func @"f" (%0 : java.type:"ReflectableLambdaTest$Context")java.type:"void" -> {
130                 %1 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
131                     %3 : Var<java.type:"int"> = var %2 @"z";
132                     %4 : java.type:"int" = field.load %0 @java.ref:"ReflectableLambdaTest$Context::x:int";
133                     %5 : java.type:"int" = field.load %0 @java.ref:"ReflectableLambdaTest$Context::y:int";
134                     %6 : java.type:"int" = add %4 %5;
135                     %7 : java.type:"int" = var.load %3;
136                     %8 : java.type:"int" = add %6 %7;
137                     return %8;
138                 };
139                 return;
140             };
141             """)
142     static final IntUnaryOperator QUOTED_CAPTURE_FIELD = new Context().capture();
143 
144     @Reflect
145     @IR("""
146             func @"captureParam" (%0 : java.type:"int")java.type:"void" -> {
147                 %1 : Var<java.type:"int"> = var %0 @"x";
148                 %2 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%3 : java.type:"int")java.type:"int" -> {
149                     %4 : Var<java.type:"int"> = var %3 @"y";
150                     %5 : java.type:"int" = var.load %1;
151                     %6 : java.type:"int" = var.load %4;
152                     %7 : java.type:"int" = add %5 %6;
153                     return %7;
154                 };
155                 %8 : Var<java.type:"java.util.function.IntUnaryOperator"> = var %2 @"op";
156                 return;
157             };
158             """)
159     static void captureParam(int x) {
160         IntUnaryOperator op = (@Reflect IntUnaryOperator) y -> x + y;
161     }
162 
163     int x, y;
164 
165     @Reflect
166     @IR("""
167             func @"captureField" (%0 : java.type:"ReflectableLambdaTest")java.type:"void" -> {
168                 %1 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
169                     %3 : Var<java.type:"int"> = var %2 @"z";
170                     %4 : java.type:"int" = field.load %0 @java.ref:"ReflectableLambdaTest::x:int";
171                     %5 : java.type:"int" = field.load %0 @java.ref:"ReflectableLambdaTest::y:int";
172                     %6 : java.type:"int" = add %4 %5;
173                     %7 : java.type:"int" = var.load %3;
174                     %8 : java.type:"int" = add %6 %7;
175                     return %8;
176                 };
177                 %9 : Var<java.type:"java.util.function.IntUnaryOperator"> = var %1 @"op";
178                 return;
179             };
180             """)
181     void captureField() {
182         IntUnaryOperator op = (@Reflect IntUnaryOperator) z -> x + y + z;
183     }
184 
185     static void m() {
186     }
187 
188     @IR("""
189             func @"f" ()java.type:"void" -> {
190                 %0 : java.type:"java.lang.Runnable" = lambda @lambda.isQuotable=true ()java.type:"void" -> {
191                     invoke @java.ref:"ReflectableLambdaTest::m():void";
192                     return;
193                 };
194                 return;
195             };
196             """)
197     static final Runnable QUOTED_NO_PARAM_VOID_REF = (@Reflect Runnable) ReflectableLambdaTest::m;
198 
199     static int g(int i) {
200         return i;
201     }
202 
203     @IR("""
204             func @"f" ()java.type:"void" -> {
205                 %0 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int" -> {
206                     %2 : Var<java.type:"int"> = var %1 @"x$0";
207                     %3 : java.type:"int" = var.load %2;
208                     %4 : java.type:"int" = invoke %3 @java.ref:"ReflectableLambdaTest::g(int):int";
209                     return %4;
210                 };
211                 return;
212             };
213             """)
214     static final IntUnaryOperator QUOTED_INT_PARAM_INT_RET_REF = (@Reflect IntUnaryOperator) ReflectableLambdaTest::g;
215 
216     @IR("""
217             func @"f" ()java.type:"void" -> {
218                 %0 : java.type:"java.util.function.IntFunction<int[]>" = lambda @lambda.isQuotable=true (%1 : java.type:"int")java.type:"int[]" -> {
219                     %2 : Var<java.type:"int"> = var %1 @"x$0";
220                     %3 : java.type:"int" = var.load %2;
221                     %4 : java.type:"int[]" = new %3 @java.ref:"int[]::(int)";
222                     return %4;
223                 };
224                 return;
225             };
226             """)
227     static final IntFunction<int[]> QUOTED_INT_PARAM_ARR_RET_REF = (@Reflect IntFunction<int[]>) int[]::new;
228 
229     static class ContextRef {
230         int g(int i) {
231             return i;
232         }
233 
234         IntUnaryOperator capture() {
235             return (@Reflect IntUnaryOperator) this::g;
236         }
237     }
238 
239     @IR("""
240             func @"f" (%0 : java.type:"ReflectableLambdaTest$ContextRef")java.type:"void" -> {
241                 %1 : java.type:"java.util.function.IntUnaryOperator" = lambda @lambda.isQuotable=true (%2 : java.type:"int")java.type:"int" -> {
242                     %3 : Var<java.type:"int"> = var %2 @"x$0";
243                     %4 : java.type:"int" = var.load %3;
244                     %5 : java.type:"int" = invoke %0 %4 @java.ref:"ReflectableLambdaTest$ContextRef::g(int):int";
245                     return %5;
246                 };
247                 return;
248             };
249             """)
250     static final IntUnaryOperator QUOTED_CAPTURE_THIS_REF = new ContextRef().capture();
251 }