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 
 26 /*
 27  * @test
 28  * @summary Smoke test for code reflection with intersection type conversions.
 29  * @modules jdk.incubator.code
 30  * @build IntersectionTypeTest
 31  * @build CodeReflectionTester
 32  * @run main CodeReflectionTester IntersectionTypeTest
 33  */
 34 
 35 class IntersectionTypeTest {
 36     interface A {
 37         Object f_A = 5;
 38         void m_A();
 39     }
 40 
 41     interface B {
 42         Object f_B = 5;
 43         void m_B();
 44     }
 45 
 46     interface C {
 47         Object f_C = 5;
 48         void m_C();
 49     }
 50 
 51     @Reflect
 52     @IR("""
 53             func @"test1" (%0 : java.type:"&IntersectionTypeTest::test1(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)")java.type:"void" -> {
 54                 %1 : Var<java.type:"&IntersectionTypeTest::test1(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>"> = var %0 @"x";
 55                 %2 : java.type:"&IntersectionTypeTest::test1(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 56                 invoke %2 @java.ref:"IntersectionTypeTest$A::m_A():void";
 57                 %3 : java.type:"&IntersectionTypeTest::test1(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 58                 %4 : java.type:"IntersectionTypeTest$B" = cast %3 @java.type:"IntersectionTypeTest$B";
 59                 invoke %4 @java.ref:"IntersectionTypeTest$B::m_B():void";
 60                 %5 : java.type:"&IntersectionTypeTest::test1(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 61                 %6 : java.type:"IntersectionTypeTest$C" = cast %5 @java.type:"IntersectionTypeTest$C";
 62                 invoke %6 @java.ref:"IntersectionTypeTest$C::m_C():void";
 63                 return;
 64             };
 65             """)
 66     static <X extends A & B & C> void test1(X x) {
 67         x.m_A();
 68         x.m_B();
 69         x.m_C();
 70     }
 71 
 72     // #X<&m<IntersectionTypeTest, test2, func<void, IntersectionTypeTest$A>>, IntersectionTypeTest$A>
 73     // #X<&m<IntersectionTypeTest, test2, func<void, IntersectionTypeTest$A>, IntersectionTypeTest$A>
 74     @Reflect
 75     @IR("""
 76             func @"test2" (%0 : java.type:"&IntersectionTypeTest::test2(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>")java.type:"void" -> {
 77                 %1 : Var<java.type:"&IntersectionTypeTest::test2(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>"> = var %0 @"x";
 78                 %2 : java.type:"&IntersectionTypeTest::test2(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 79                 %3 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$A::f_A:java.lang.Object";
 80                 %4 : Var<java.type:"java.lang.Object"> = var %3 @"oA";
 81                 %5 : java.type:"&IntersectionTypeTest::test2(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 82                 %6 : java.type:"IntersectionTypeTest$B" = cast %5 @java.type:"IntersectionTypeTest$B";
 83                 %7 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$B::f_B:java.lang.Object";
 84                 %8 : Var<java.type:"java.lang.Object"> = var %7 @"oB";
 85                 %9 : java.type:"&IntersectionTypeTest::test2(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>" = var.load %1;
 86                 %10 : java.type:"IntersectionTypeTest$C" = cast %9 @java.type:"IntersectionTypeTest$C";
 87                 %11 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$C::f_C:java.lang.Object";
 88                 %12 : Var<java.type:"java.lang.Object"> = var %11 @"oC";
 89                 return;
 90             };
 91             """)
 92     static <X extends A & B & C> void test2(X x) {
 93         Object oA = x.f_A;
 94         Object oB = x.f_B;
 95         Object oC = x.f_C;
 96     }
 97 
 98     @Reflect
 99     @IR("""
100             func @"test3" (%0 : java.type:"&IntersectionTypeTest::test3(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)")java.type:"void" -> {
101                 %1 : Var<java.type:"&IntersectionTypeTest::test3(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)"> = var %0 @"x";
102                 %2 : java.type:"&IntersectionTypeTest::test3(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
103                 %3 : Var<java.type:"IntersectionTypeTest$A"> = var %2 @"rec$";
104                 %4 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
105                     %5 : java.type:"IntersectionTypeTest$A" = var.load %3;
106                     invoke %5 @java.ref:"IntersectionTypeTest$A::m_A():void";
107                     return;
108                 };
109                 %6 : Var<java.type:"java.lang.Runnable"> = var %4 @"rA";
110                 %7 : java.type:"&IntersectionTypeTest::test3(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
111                 %8 : java.type:"IntersectionTypeTest$B" = cast %7 @java.type:"IntersectionTypeTest$B";
112                 %9 : Var<java.type:"IntersectionTypeTest$B"> = var %8 @"rec$";
113                 %10 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
114                     %11 : java.type:"IntersectionTypeTest$B" = var.load %9;
115                     invoke %11 @java.ref:"IntersectionTypeTest$B::m_B():void";
116                     return;
117                 };
118                 %12 : Var<java.type:"java.lang.Runnable"> = var %10 @"rB";
119                 %13 : java.type:"&IntersectionTypeTest::test3(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
120                 %14 : java.type:"IntersectionTypeTest$C" = cast %13 @java.type:"IntersectionTypeTest$C";
121                 %15 : Var<java.type:"IntersectionTypeTest$C"> = var %14 @"rec$";
122                 %16 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
123                     %17 : java.type:"IntersectionTypeTest$C" = var.load %15;
124                     invoke %17 @java.ref:"IntersectionTypeTest$C::m_C():void";
125                     return;
126                 };
127                 %18 : Var<java.type:"java.lang.Runnable"> = var %16 @"rC";
128                 return;
129             };
130             """)
131     static <X extends A & B & C> void test3(X x) {
132         Runnable rA = x::m_A;
133         Runnable rB = x::m_B;
134         Runnable rC = x::m_C;
135     }
136 
137     static void g_A(A a) { }
138     static void g_B(B a) { }
139     static void g_C(C a) { }
140 
141     @Reflect
142     @IR("""
143             func @"test4" (%0 : java.type:"&IntersectionTypeTest::test4(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)")java.type:"void" -> {
144                 %1 : Var<java.type:"&IntersectionTypeTest::test4(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)"> = var %0 @"x";
145                 %2 : java.type:"&IntersectionTypeTest::test4(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
146                 invoke %2 @java.ref:"IntersectionTypeTest::g_A(IntersectionTypeTest$A):void";
147                 %3 : java.type:"&IntersectionTypeTest::test4(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
148                 %4 : java.type:"IntersectionTypeTest$B" = cast %3 @java.type:"IntersectionTypeTest$B";
149                 invoke %4 @java.ref:"IntersectionTypeTest::g_B(IntersectionTypeTest$B):void";
150                 %5 : java.type:"&IntersectionTypeTest::test4(IntersectionTypeTest$A):void::<X extends IntersectionTypeTest$A>)" = var.load %1;
151                 %6 : java.type:"IntersectionTypeTest$C" = cast %5 @java.type:"IntersectionTypeTest$C";
152                 invoke %6 @java.ref:"IntersectionTypeTest::g_C(IntersectionTypeTest$C):void";
153                 return;
154             };
155             """)
156     static <X extends A & B & C> void test4(X x) {
157         g_A(x);
158         g_B(x);
159         g_C(x);
160     }
161 
162     static <X extends A & B & C> X makeIntersection(X x1, X x2) {
163         return null;
164     }
165 
166     static class E1 implements A, B, C {
167         @Override
168         public void m_A() { }
169         @Override
170         public void m_B() { }
171         @Override
172         public void m_C() { }
173     }
174 
175     static class E2 implements A, B, C {
176         @Override
177         public void m_A() { }
178         @Override
179         public void m_B() { }
180         @Override
181         public void m_C() { }
182     }
183 
184     @Reflect
185     @IR("""
186             func @"test5" (%0 : java.type:"IntersectionTypeTest$E1", %1 : java.type:"IntersectionTypeTest$E2")java.type:"void" -> {
187                 %2 : Var<java.type:"IntersectionTypeTest$E1"> = var %0 @"e1";
188                 %3 : Var<java.type:"IntersectionTypeTest$E2"> = var %1 @"e2";
189                 %4 : java.type:"IntersectionTypeTest$E1" = var.load %2;
190                 %5 : java.type:"IntersectionTypeTest$E2" = var.load %3;
191                 %6 : java.type:"IntersectionTypeTest$A" = invoke %4 %5 @java.ref:"IntersectionTypeTest::makeIntersection(IntersectionTypeTest$A, IntersectionTypeTest$A):IntersectionTypeTest$A";
192                 %7 : Var<java.type:"IntersectionTypeTest$A"> = var %6 @"x";
193                 %8 : java.type:"IntersectionTypeTest$A" = var.load %7;
194                 invoke %8 @java.ref:"IntersectionTypeTest$A::m_A():void";
195                 %9 : java.type:"IntersectionTypeTest$A" = var.load %7;
196                 %10 : java.type:"IntersectionTypeTest$B" = cast %9 @java.type:"IntersectionTypeTest$B";
197                 invoke %10 @java.ref:"IntersectionTypeTest$B::m_B():void";
198                 %11 : java.type:"IntersectionTypeTest$A" = var.load %7;
199                 %12 : java.type:"IntersectionTypeTest$C" = cast %11 @java.type:"IntersectionTypeTest$C";
200                 invoke %12 @java.ref:"IntersectionTypeTest$C::m_C():void";
201                 return;
202             };
203             """)
204     static void test5(E1 e1, E2 e2) {
205         var x = makeIntersection(e1, e2);
206         x.m_A();
207         x.m_B();
208         x.m_C();
209     }
210 
211     @Reflect
212     @IR("""
213             func @"test6" (%0 : java.type:"IntersectionTypeTest$E1", %1 : java.type:"IntersectionTypeTest$E2")java.type:"void" -> {
214                 %2 : Var<java.type:"IntersectionTypeTest$E1"> = var %0 @"e1";
215                 %3 : Var<java.type:"IntersectionTypeTest$E2"> = var %1 @"e2";
216                 %4 : java.type:"IntersectionTypeTest$E1" = var.load %2;
217                 %5 : java.type:"IntersectionTypeTest$E2" = var.load %3;
218                 %6 : java.type:"IntersectionTypeTest$A" = invoke %4 %5 @java.ref:"IntersectionTypeTest::makeIntersection(IntersectionTypeTest$A, IntersectionTypeTest$A):IntersectionTypeTest$A";
219                 %7 : Var<java.type:"IntersectionTypeTest$A"> = var %6 @"x";
220                 %8 : java.type:"IntersectionTypeTest$A" = var.load %7;
221                 %9 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$A::f_A:java.lang.Object";
222                 %10 : Var<java.type:"java.lang.Object"> = var %9 @"oA";
223                 %11 : java.type:"IntersectionTypeTest$A" = var.load %7;
224                 %12 : java.type:"IntersectionTypeTest$B" = cast %11 @java.type:"IntersectionTypeTest$B";
225                 %13 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$B::f_B:java.lang.Object";
226                 %14 : Var<java.type:"java.lang.Object"> = var %13 @"oB";
227                 %15 : java.type:"IntersectionTypeTest$A" = var.load %7;
228                 %16 : java.type:"IntersectionTypeTest$C" = cast %15 @java.type:"IntersectionTypeTest$C";
229                 %17 : java.type:"java.lang.Object" = field.load @java.ref:"IntersectionTypeTest$C::f_C:java.lang.Object";
230                 %18 : Var<java.type:"java.lang.Object"> = var %17 @"oC";
231                 return;
232             };
233             """)
234     static void test6(E1 e1, E2 e2) {
235         var x = makeIntersection(e1, e2);
236         Object oA = x.f_A;
237         Object oB = x.f_B;
238         Object oC = x.f_C;
239     }
240 
241     @Reflect
242     @IR("""
243             func @"test7" (%0 : java.type:"IntersectionTypeTest$E1", %1 : java.type:"IntersectionTypeTest$E2")java.type:"void" -> {
244                 %2 : Var<java.type:"IntersectionTypeTest$E1"> = var %0 @"e1";
245                 %3 : Var<java.type:"IntersectionTypeTest$E2"> = var %1 @"e2";
246                 %4 : java.type:"IntersectionTypeTest$E1" = var.load %2;
247                 %5 : java.type:"IntersectionTypeTest$E2" = var.load %3;
248                 %6 : java.type:"IntersectionTypeTest$A" = invoke %4 %5 @java.ref:"IntersectionTypeTest::makeIntersection(IntersectionTypeTest$A, IntersectionTypeTest$A):IntersectionTypeTest$A";
249                 %7 : Var<java.type:"IntersectionTypeTest$A"> = var %6 @"x";
250                 %8 : java.type:"IntersectionTypeTest$A" = var.load %7;
251                 %9 : Var<java.type:"IntersectionTypeTest$A"> = var %8 @"rec$";
252                 %10 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
253                     %11 : java.type:"IntersectionTypeTest$A" = var.load %9;
254                     invoke %11 @java.ref:"IntersectionTypeTest$A::m_A():void";
255                     return;
256                 };
257                 %12 : Var<java.type:"java.lang.Runnable"> = var %10 @"rA";
258                 %13 : java.type:"IntersectionTypeTest$A" = var.load %7;
259                 %14 : java.type:"IntersectionTypeTest$B" = cast %13 @java.type:"IntersectionTypeTest$B";
260                 %15 : Var<java.type:"IntersectionTypeTest$B"> = var %14 @"rec$";
261                 %16 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
262                     %17 : java.type:"IntersectionTypeTest$B" = var.load %15;
263                     invoke %17 @java.ref:"IntersectionTypeTest$B::m_B():void";
264                     return;
265                 };
266                 %18 : Var<java.type:"java.lang.Runnable"> = var %16 @"rB";
267                 %19 : java.type:"IntersectionTypeTest$A" = var.load %7;
268                 %20 : java.type:"IntersectionTypeTest$C" = cast %19 @java.type:"IntersectionTypeTest$C";
269                 %21 : Var<java.type:"IntersectionTypeTest$C"> = var %20 @"rec$";
270                 %22 : java.type:"java.lang.Runnable" = lambda @lambda.isReflectable=true ()java.type:"void" -> {
271                     %23 : java.type:"IntersectionTypeTest$C" = var.load %21;
272                     invoke %23 @java.ref:"IntersectionTypeTest$C::m_C():void";
273                     return;
274                 };
275                 %24 : Var<java.type:"java.lang.Runnable"> = var %22 @"rC";
276                 return;
277             };
278             """)
279     static void test7(E1 e1, E2 e2) {
280         var x = makeIntersection(e1, e2);
281         Runnable rA = x::m_A;
282         Runnable rB = x::m_B;
283         Runnable rC = x::m_C;
284     }
285 
286     @Reflect
287     @IR("""
288             func @"test8" (%0 : java.type:"IntersectionTypeTest$E1", %1 : java.type:"IntersectionTypeTest$E2")java.type:"void" -> {
289                 %2 : Var<java.type:"IntersectionTypeTest$E1"> = var %0 @"e1";
290                 %3 : Var<java.type:"IntersectionTypeTest$E2"> = var %1 @"e2";
291                 %4 : java.type:"IntersectionTypeTest$E1" = var.load %2;
292                 %5 : java.type:"IntersectionTypeTest$E2" = var.load %3;
293                 %6 : java.type:"IntersectionTypeTest$A" = invoke %4 %5 @java.ref:"IntersectionTypeTest::makeIntersection(IntersectionTypeTest$A, IntersectionTypeTest$A):IntersectionTypeTest$A";
294                 %7 : Var<java.type:"IntersectionTypeTest$A"> = var %6 @"x";
295                 %8 : java.type:"IntersectionTypeTest$A" = var.load %7;
296                 invoke %8 @java.ref:"IntersectionTypeTest::g_A(IntersectionTypeTest$A):void";
297                 %9 : java.type:"IntersectionTypeTest$A" = var.load %7;
298                 %10 : java.type:"IntersectionTypeTest$B" = cast %9 @java.type:"IntersectionTypeTest$B";
299                 invoke %10 @java.ref:"IntersectionTypeTest::g_B(IntersectionTypeTest$B):void";
300                 %11 : java.type:"IntersectionTypeTest$A" = var.load %7;
301                 %12 : java.type:"IntersectionTypeTest$C" = cast %11 @java.type:"IntersectionTypeTest$C";
302                 invoke %12 @java.ref:"IntersectionTypeTest::g_C(IntersectionTypeTest$C):void";
303                 return;
304             };
305             """)
306     static void test8(E1 e1, E2 e2) {
307         var x = makeIntersection(e1, e2);
308         g_A(x);
309         g_B(x);
310         g_C(x);
311     }
312 }