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