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 import java.io.PrintStream;
 25 import jdk.incubator.code.CodeReflection;
 26 import java.util.Spliterator;
 27 import java.util.Spliterator.OfInt;
 28 
 29 import static java.lang.System.out;
 30 import static java.util.Spliterator.OfInt.*;
 31 
 32 /*
 33  * @test
 34  * @summary Smoke test for code reflection with field access.
 35  * @modules jdk.incubator.code
 36  * @build FieldAccessTest
 37  * @build CodeReflectionTester
 38  * @run main CodeReflectionTester FieldAccessTest
 39  */
 40 
 41 public class FieldAccessTest {
 42     static int s_f;
 43     int f;
 44 
 45     @CodeReflection
 46     @IR("""
 47             func @"test1" (%0 : FieldAccessTest)void -> {
 48                 %1 : int = constant @"1";
 49                 field.store %1 @"FieldAccessTest::s_f()int";
 50                 %2 : int = constant @"1";
 51                 field.store %0 %2 @"FieldAccessTest::f()int";
 52                 return;
 53             };
 54             """)
 55     void test1() {
 56         s_f = 1;
 57         f = 1;
 58     }
 59 
 60     @CodeReflection
 61     @IR("""
 62             func @"test1_1" (%0 : FieldAccessTest)void -> {
 63                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
 64                 %2 : int = constant @"1";
 65                 %3 : int = add %1 %2;
 66                 field.store %0 %3 @"FieldAccessTest::f()int";
 67                 %4 : int = field.load @"FieldAccessTest::s_f()int";
 68                 %5 : int = constant @"1";
 69                 %6 : int = add %4 %5;
 70                 field.store %6 @"FieldAccessTest::s_f()int";
 71                 return;
 72             };
 73             """)
 74     void test1_1() {
 75         f += 1;
 76         s_f += 1;
 77     }
 78 
 79     @CodeReflection
 80     @IR("""
 81             func @"test2" (%0 : FieldAccessTest)void -> {
 82                 %1 : int = constant @"1";
 83                 field.store %0 %1 @"FieldAccessTest::f()int";
 84                 field.store %1 @"FieldAccessTest::s_f()int";
 85                 return;
 86             };
 87             """)
 88     void test2() {
 89         s_f = f = 1;
 90     }
 91 
 92     @CodeReflection
 93     @IR("""
 94             func @"test2_1" (%0 : FieldAccessTest)void -> {
 95                 %1 : int = constant @"1";
 96                 field.store %0 %1 @"FieldAccessTest::f()int";
 97                 return;
 98             };
 99             """)
100     void test2_1() {
101         this.f = 1;
102     }
103 
104     @CodeReflection
105     @IR("""
106             func @"test2_2" (%0 : FieldAccessTest)int -> {
107                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
108                 return %1;
109             };
110             """)
111     int test2_2() {
112         return this.f;
113     }
114 
115     @CodeReflection
116     @IR("""
117             func @"test2_3" (%0 : FieldAccessTest)void -> {
118                 %1 : int = constant @"1";
119                 field.store %0 %1 @"FieldAccessTest::f()int";
120                 return;
121             };
122             """)
123     void test2_3() {
124         FieldAccessTest.this.f = 1;
125     }
126 
127     @CodeReflection
128     @IR("""
129             func @"test2_4" (%0 : FieldAccessTest)int -> {
130                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
131                 return %1;
132             };
133             """)
134     int test2_4() {
135         return FieldAccessTest.this.f;
136     }
137 
138     @CodeReflection
139     @IR("""
140             func @"test3" (%0 : FieldAccessTest)int -> {
141                 %1 : int = field.load @"FieldAccessTest::s_f()int";
142                 %2 : int = field.load %0 @"FieldAccessTest::f()int";
143                 %3 : int = add %1 %2;
144                 return %3;
145             };
146             """)
147     int test3() {
148         return s_f + f;
149     }
150 
151     static class A {
152         B b;
153     }
154 
155     static class B {
156         C c;
157     }
158 
159     static class C {
160         int f;
161     }
162 
163     @CodeReflection
164     @IR("""
165             func @"test4" (%0 : FieldAccessTest, %1 : FieldAccessTest$A)void -> {
166                 %2 : Var<FieldAccessTest$A> = var %1 @"a";
167                 %3 : FieldAccessTest$A = var.load %2;
168                 %4 : FieldAccessTest$B = field.load %3 @"FieldAccessTest$A::b()FieldAccessTest$B";
169                 %5 : FieldAccessTest$C = field.load %4 @"FieldAccessTest$B::c()FieldAccessTest$C";
170                 %6 : int = constant @"1";
171                 field.store %5 %6 @"FieldAccessTest$C::f()int";
172                 return;
173             };
174             """)
175     void test4(A a) {
176         a.b.c.f = 1;
177     }
178 
179     static class X {
180         int f;
181         static int s_f;
182     }
183 
184     @CodeReflection
185     @IR("""
186             func @"test5" (%0 : FieldAccessTest)int -> {
187                 %1 : int = field.load @"FieldAccessTest$X::s_f()int";
188                 return %1;
189             };
190             """)
191     int test5() {
192         return X.s_f;
193     }
194 
195     @CodeReflection
196     @IR("""
197             func @"test6" (%0 : FieldAccessTest)void -> {
198                 %1 : int = constant @"1";
199                 field.store %1 @"FieldAccessTest$X::s_f()int";
200                 return;
201             };
202             """)
203     void test6() {
204         X.s_f = 1;
205     }
206 
207 
208     @CodeReflection
209     @IR("""
210             func @"test7" (%0 : FieldAccessTest)void -> {
211                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
212                 %2 : int = constant @"1";
213                 %3 : int = add %1 %2;
214                 field.store %0 %3 @"FieldAccessTest::f()int";
215                 %4 : int = field.load @"FieldAccessTest::s_f()int";
216                 %5 : int = constant @"1";
217                 %6 : int = add %4 %5;
218                 field.store %6 @"FieldAccessTest::s_f()int";
219                 return;
220             };
221             """)
222     void test7() {
223         f += 1;
224         s_f += 1;
225     }
226 
227     @CodeReflection
228     @IR("""
229             func @"test8" (%0 : FieldAccessTest)void -> {
230                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
231                 %2 : int = constant @"1";
232                 %3 : int = add %1 %2;
233                 field.store %0 %3 @"FieldAccessTest::f()int";
234                 %4 : int = field.load @"FieldAccessTest::s_f()int";
235                 %5 : int = constant @"1";
236                 %6 : int = add %4 %5;
237                 field.store %6 @"FieldAccessTest::s_f()int";
238                 return;
239             };
240             """)
241     void test8() {
242         this.f += 1;
243         this.s_f += 1;
244     }
245 
246     @CodeReflection
247     @IR("""
248             func @"test9" (%0 : FieldAccessTest)void -> {
249                 %1 : int = field.load @"FieldAccessTest$X::s_f()int";
250                 %2 : int = constant @"1";
251                 %3 : int = add %1 %2;
252                 field.store %3 @"FieldAccessTest$X::s_f()int";
253                 return;
254             };
255             """)
256     void test9() {
257         X.s_f += 1;
258     }
259 
260     @CodeReflection
261     @IR("""
262             func @"test10" (%0 : FieldAccessTest)void -> {
263                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
264                 %2 : int = constant @"1";
265                 %3 : int = add %1 %2;
266                 field.store %0 %3 @"FieldAccessTest::f()int";
267                 field.store %3 @"FieldAccessTest::s_f()int";
268                 return;
269             };
270             """)
271     void test10() {
272         s_f = f += 1;
273     }
274 
275     @CodeReflection
276     @IR("""
277             func @"test11" (%0 : FieldAccessTest, %1 : FieldAccessTest$A)void -> {
278                 %2 : Var<FieldAccessTest$A> = var %1 @"a";
279                 %3 : FieldAccessTest$A = var.load %2;
280                 %4 : FieldAccessTest$B = field.load %3 @"FieldAccessTest$A::b()FieldAccessTest$B";
281                 %5 : FieldAccessTest$C = field.load %4 @"FieldAccessTest$B::c()FieldAccessTest$C";
282                 %6 : int = field.load %5 @"FieldAccessTest$C::f()int";
283                 %7 : int = constant @"1";
284                 %8 : int = add %6 %7;
285                 field.store %5 %8 @"FieldAccessTest$C::f()int";
286                 return;
287             };
288             """)
289     void test11(A a) {
290         a.b.c.f += 1;
291     }
292 
293     @CodeReflection
294     @IR("""
295             func @"test12" (%0 : FieldAccessTest)void -> {
296                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
297                 %2 : int = constant @"1";
298                 %3 : int = add %1 %2;
299                 field.store %0 %3 @"FieldAccessTest::f()int";
300                 %4 : Var<int> = var %1 @"x";
301                 %5 : int = field.load %0 @"FieldAccessTest::f()int";
302                 %6 : int = constant @"1";
303                 %7 : int = sub %5 %6;
304                 field.store %0 %7 @"FieldAccessTest::f()int";
305                 %8 : Var<int> = var %5 @"y";
306                 return;
307             };
308             """)
309     void test12() {
310         int x = f++;
311         int y = f--;
312     }
313 
314     @CodeReflection
315     @IR("""
316             func @"test13" (%0 : FieldAccessTest)void -> {
317                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
318                 %2 : int = constant @"1";
319                 %3 : int = add %1 %2;
320                 field.store %0 %3 @"FieldAccessTest::f()int";
321                 %4 : Var<int> = var %1 @"x";
322                 %5 : int = field.load %0 @"FieldAccessTest::f()int";
323                 %6 : int = constant @"1";
324                 %7 : int = sub %5 %6;
325                 field.store %0 %7 @"FieldAccessTest::f()int";
326                 %8 : Var<int> = var %5 @"y";
327                 return;
328             };
329             """)
330     void test13() {
331         int x = this.f++;
332         int y = this.f--;
333     }
334 
335     @CodeReflection
336     @IR("""
337             func @"test14" (%0 : FieldAccessTest)void -> {
338                 %1 : int = field.load @"FieldAccessTest::s_f()int";
339                 %2 : int = constant @"1";
340                 %3 : int = add %1 %2;
341                 field.store %3 @"FieldAccessTest::s_f()int";
342                 %4 : Var<int> = var %1 @"x";
343                 %5 : int = field.load @"FieldAccessTest::s_f()int";
344                 %6 : int = constant @"1";
345                 %7 : int = sub %5 %6;
346                 field.store %7 @"FieldAccessTest::s_f()int";
347                 %8 : Var<int> = var %5 @"y";
348                 return;
349             };
350             """)
351     void test14() {
352         int x = s_f++;
353         int y = s_f--;
354     }
355 
356     @CodeReflection
357     @IR("""
358             func @"test15" (%0 : FieldAccessTest, %1 : FieldAccessTest$X)void -> {
359                 %2 : Var<FieldAccessTest$X> = var %1 @"h";
360                 %3 : FieldAccessTest$X = var.load %2;
361                 %4 : int = field.load %3 @"FieldAccessTest$X::f()int";
362                 %5 : int = constant @"1";
363                 %6 : int = add %4 %5;
364                 field.store %3 %6 @"FieldAccessTest$X::f()int";
365                 %7 : Var<int> = var %4 @"x";
366                 %8 : FieldAccessTest$X = var.load %2;
367                 %9 : int = field.load %8 @"FieldAccessTest$X::f()int";
368                 %10 : int = constant @"1";
369                 %11 : int = sub %9 %10;
370                 field.store %8 %11 @"FieldAccessTest$X::f()int";
371                 %12 : Var<int> = var %9 @"y";
372                 return;
373             };
374             """)
375     void test15(X h) {
376         int x = h.f++;
377         int y = h.f--;
378     }
379 
380 
381 
382 
383     @CodeReflection
384     @IR("""
385             func @"test16" (%0 : FieldAccessTest)void -> {
386                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
387                 %2 : int = constant @"1";
388                 %3 : int = add %1 %2;
389                 field.store %0 %3 @"FieldAccessTest::f()int";
390                 %4 : Var<int> = var %3 @"x";
391                 %5 : int = field.load %0 @"FieldAccessTest::f()int";
392                 %6 : int = constant @"1";
393                 %7 : int = sub %5 %6;
394                 field.store %0 %7 @"FieldAccessTest::f()int";
395                 %8 : Var<int> = var %7 @"y";
396                 return;
397             };
398             """)
399     void test16() {
400         int x = ++f;
401         int y = --f;
402     }
403 
404     @CodeReflection
405     @IR("""
406             func @"test17" (%0 : FieldAccessTest)void -> {
407                 %1 : int = field.load %0 @"FieldAccessTest::f()int";
408                 %2 : int = constant @"1";
409                 %3 : int = add %1 %2;
410                 field.store %0 %3 @"FieldAccessTest::f()int";
411                 %4 : Var<int> = var %3 @"x";
412                 %5 : int = field.load %0 @"FieldAccessTest::f()int";
413                 %6 : int = constant @"1";
414                 %7 : int = sub %5 %6;
415                 field.store %0 %7 @"FieldAccessTest::f()int";
416                 %8 : Var<int> = var %7 @"y";
417                 return;
418             };
419             """)
420     void test17() {
421         int x = ++this.f;
422         int y = --this.f;
423     }
424 
425     @CodeReflection
426     @IR("""
427             func @"test18" (%0 : FieldAccessTest)void -> {
428                 %1 : int = field.load @"FieldAccessTest::s_f()int";
429                 %2 : int = constant @"1";
430                 %3 : int = add %1 %2;
431                 field.store %3 @"FieldAccessTest::s_f()int";
432                 %4 : Var<int> = var %3 @"x";
433                 %5 : int = field.load @"FieldAccessTest::s_f()int";
434                 %6 : int = constant @"1";
435                 %7 : int = sub %5 %6;
436                 field.store %7 @"FieldAccessTest::s_f()int";
437                 %8 : Var<int> = var %7 @"y";
438                 return;
439             };
440             """)
441     void test18() {
442         int x = ++s_f;
443         int y = --s_f;
444     }
445 
446     @CodeReflection
447     @IR("""
448             func @"test19" (%0 : FieldAccessTest, %1 : FieldAccessTest$X)void -> {
449                 %2 : Var<FieldAccessTest$X> = var %1 @"h";
450                 %3 : FieldAccessTest$X = var.load %2;
451                 %4 : int = field.load %3 @"FieldAccessTest$X::f()int";
452                 %5 : int = constant @"1";
453                 %6 : int = add %4 %5;
454                 field.store %3 %6 @"FieldAccessTest$X::f()int";
455                 %7 : Var<int> = var %6 @"x";
456                 %8 : FieldAccessTest$X = var.load %2;
457                 %9 : int = field.load %8 @"FieldAccessTest$X::f()int";
458                 %10 : int = constant @"1";
459                 %11 : int = sub %9 %10;
460                 field.store %8 %11 @"FieldAccessTest$X::f()int";
461                 %12 : Var<int> = var %11 @"y";
462                 return;
463             };
464             """)
465     void test19(X h) {
466         int x = ++h.f;
467         int y = --h.f;
468     }
469 
470     static class Y extends X {
471         int yf;
472         static int s_yf;
473 
474         @CodeReflection
475         @IR("""
476                 func @"test" (%0 : FieldAccessTest$Y)void -> {
477                     %1 : int = field.load %0 @"FieldAccessTest$Y::f()int";
478                     %2 : Var<int> = var %1 @"x";
479                     %3 : int = field.load @"FieldAccessTest$Y::s_f()int";
480                     var.store %2 %3;
481                     return;
482                 };
483                 """)
484         void test() {
485             int x = f;
486             x = s_f;
487         }
488 
489         @CodeReflection
490         @IR("""
491                 func @"test2" (%0 : FieldAccessTest$Y)void -> {
492                     %1 : int = constant @"1";
493                     field.store %0 %1 @"FieldAccessTest$Y::f()int";
494                     %2 : int = constant @"1";
495                     field.store %2 @"FieldAccessTest$Y::s_f()int";
496                     return;
497                 };
498                 """)
499         void test2() {
500             f = 1;
501             s_f = 1;
502         }
503 
504         @CodeReflection
505         @IR("""
506                 func @"test3" (%0 : FieldAccessTest$Y)void -> {
507                     %1 : int = field.load %0 @"FieldAccessTest$Y::f()int";
508                     %2 : int = constant @"1";
509                     %3 : int = add %1 %2;
510                     field.store %0 %3 @"FieldAccessTest$Y::f()int";
511                     %4 : int = field.load @"FieldAccessTest$Y::s_f()int";
512                     %5 : int = constant @"1";
513                     %6 : int = add %4 %5;
514                     field.store %6 @"FieldAccessTest$Y::s_f()int";
515                     return;
516                 };
517                 """)
518         void test3() {
519             f++;
520             s_f++;
521         }
522     }
523 
524     @CodeReflection
525     @IR("""
526             func @"test20" (%0 : FieldAccessTest, %1 : FieldAccessTest$Y)void -> {
527                 %2 : Var<FieldAccessTest$Y> = var %1 @"y";
528                 %3 : FieldAccessTest$Y = var.load %2;
529                 %4 : int = field.load %3 @"FieldAccessTest$Y::f()int";
530                 %5 : Var<int> = var %4 @"x";
531                 %6 : FieldAccessTest$Y = var.load %2;
532                 %7 : int = field.load %6 @"FieldAccessTest$Y::yf()int";
533                 var.store %5 %7;
534                 %8 : FieldAccessTest$Y = var.load %2;
535                 %9 : int = field.load @"FieldAccessTest$Y::s_yf()int";
536                 var.store %5 %9;
537                 %10 : int = field.load @"FieldAccessTest$Y::s_yf()int";
538                 var.store %5 %10;
539                 %11 : FieldAccessTest$Y = var.load %2;
540                 %12 : int = field.load @"FieldAccessTest$Y::s_f()int";
541                 var.store %5 %12;
542                 %13 : int = field.load @"FieldAccessTest$Y::s_f()int";
543                 var.store %5 %13;
544                 return;
545             };
546             """)
547     void test20(Y y) {
548         int x = y.f;
549         x = y.yf;
550         x = y.s_yf;
551         x = Y.s_yf;
552         x = y.s_f;
553         x = Y.s_f;
554     }
555 
556     @CodeReflection
557     @IR("""
558             func @"test21" (%0 : FieldAccessTest, %1 : FieldAccessTest$Y)void -> {
559                 %2 : Var<FieldAccessTest$Y> = var %1 @"y";
560                 %3 : FieldAccessTest$Y = var.load %2;
561                 %4 : int = constant @"1";
562                 field.store %3 %4 @"FieldAccessTest$Y::f()int";
563                 %5 : FieldAccessTest$Y = var.load %2;
564                 %6 : int = constant @"1";
565                 field.store %5 %6 @"FieldAccessTest$Y::yf()int";
566                 %7 : FieldAccessTest$Y = var.load %2;
567                 %8 : int = constant @"1";
568                 field.store %8 @"FieldAccessTest$Y::s_yf()int";
569                 %9 : int = constant @"1";
570                 field.store %9 @"FieldAccessTest$Y::s_yf()int";
571                 %10 : FieldAccessTest$Y = var.load %2;
572                 %11 : int = constant @"1";
573                 field.store %11 @"FieldAccessTest$Y::s_f()int";
574                 %12 : int = constant @"1";
575                 field.store %12 @"FieldAccessTest$Y::s_f()int";
576                 return;
577             };
578             """)
579     void test21(Y y) {
580         y.f = 1;
581         y.yf = 1;
582         y.s_yf = 1;
583         Y.s_yf = 1;
584         y.s_f = 1;
585         Y.s_f = 1;
586     }
587 
588     @CodeReflection
589     @IR("""
590           func @"test22" (%0 : FieldAccessTest, %1 : FieldAccessTest$Y)void -> {
591                 %2 : Var<FieldAccessTest$Y> = var %1 @"y";
592                 %3 : FieldAccessTest$Y = var.load %2;
593                 %4 : int = field.load %3 @"FieldAccessTest$Y::f()int";
594                 %5 : int = constant @"1";
595                 %6 : int = add %4 %5;
596                 field.store %3 %6 @"FieldAccessTest$Y::f()int";
597                 %7 : FieldAccessTest$Y = var.load %2;
598                 %8 : int = field.load %7 @"FieldAccessTest$Y::yf()int";
599                 %9 : int = constant @"1";
600                 %10 : int = add %8 %9;
601                 field.store %7 %10 @"FieldAccessTest$Y::yf()int";
602                 %11 : FieldAccessTest$Y = var.load %2;
603                 %12 : int = field.load @"FieldAccessTest$Y::s_yf()int";
604                 %13 : int = constant @"1";
605                 %14 : int = add %12 %13;
606                 field.store %14 @"FieldAccessTest$Y::s_yf()int";
607                 %15 : int = field.load @"FieldAccessTest$Y::s_yf()int";
608                 %16 : int = constant @"1";
609                 %17 : int = add %15 %16;
610                 field.store %17 @"FieldAccessTest$Y::s_yf()int";
611                 %18 : FieldAccessTest$Y = var.load %2;
612                 %19 : int = field.load @"FieldAccessTest$Y::s_f()int";
613                 %20 : int = constant @"1";
614                 %21 : int = add %19 %20;
615                 field.store %21 @"FieldAccessTest$Y::s_f()int";
616                 %22 : int = field.load @"FieldAccessTest$Y::s_f()int";
617                 %23 : int = constant @"1";
618                 %24 : int = add %22 %23;
619                 field.store %24 @"FieldAccessTest$Y::s_f()int";
620                 return;
621             };
622             """)
623     void test22(Y y) {
624         y.f++;
625         y.yf++;
626         y.s_yf++;
627         Y.s_yf++;
628         y.s_f++;
629         Y.s_f++;
630     }
631 
632     // @@@ Should propagate as constant value?
633     @CodeReflection
634     @IR("""
635             func @"test23" (%0 : FieldAccessTest)void -> {
636                 %1 : int = field.load @"java.util.Spliterator$OfInt::CONCURRENT()int";
637                 %2 : Var<int> = var %1 @"x";
638                 %3 : int = field.load @"java.util.Spliterator$OfInt::CONCURRENT()int";
639                 var.store %2 %3;
640                 %4 : int = field.load @"java.util.Spliterator$OfInt::CONCURRENT()int";
641                 var.store %2 %4;
642                 return;
643             };
644             """)
645     void test23() {
646         int x = Spliterator.OfInt.CONCURRENT;
647         x = OfInt.CONCURRENT;
648         x = CONCURRENT;
649     }
650 
651     @CodeReflection
652     @IR("""
653             func @"test24" (%0 : FieldAccessTest)void -> {
654                 %1 : java.io.PrintStream = field.load @"java.lang.System::out()java.io.PrintStream";
655                 %2 : Var<java.io.PrintStream> = var %1 @"ps";
656                 return;
657             };
658             """)
659     void test24() {
660         PrintStream ps = out;
661     }
662 
663     static class Box<T> {
664         public T v;
665 
666         public Box(T v) {
667             this.v = v;
668         }
669     }
670 
671     @CodeReflection
672     @IR("""
673             func @"test25" ()void -> {
674                     %0 : java.lang.String = constant @"abc";
675                     %1 : FieldAccessTest$Box<java.lang.String> = new %0 @"func<FieldAccessTest$Box, java.lang.Object>";
676                     %2 : Var<FieldAccessTest$Box<java.lang.String>> = var %1 @"b";
677                     %3 : FieldAccessTest$Box<java.lang.String> = var.load %2;
678                     %4 : java.lang.String = field.load %3 @"FieldAccessTest$Box::v()java.lang.Object";
679                     %5 : Var<java.lang.String> = var %4 @"s";
680                     return;
681             };
682             """)
683     static void test25() {
684         Box<String> b = new Box<>("abc");
685         String s = b.v;
686     }
687 
688     //@@@ unqualified access to field of generic type needs to be tested
689     // waiting for a new way of modeling types, so that type variables are captured in the IR
690 }