You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/01/02 04:32:24 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-10890: STC: redesign resolved type parameter as type witness

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY_4_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 387ca25f77 GROOVY-10890: STC: redesign resolved type parameter as type witness
387ca25f77 is described below

commit 387ca25f77173fede387b25049cd7404ff20815a
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sun Jan 1 21:24:27 2023 -0600

    GROOVY-10890: STC: redesign resolved type parameter as type witness
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  57 +++-----
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 150 +++++++++++----------
 2 files changed, 98 insertions(+), 109 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 6f2ab5f9e7..b9c4b1c01d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -140,7 +140,6 @@ import java.util.function.Function;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
-import static java.util.stream.Collectors.toMap;
 import static org.apache.groovy.util.BeanUtils.capitalize;
 import static org.apache.groovy.util.BeanUtils.decapitalize;
 import static org.codehaus.groovy.ast.ClassHelper.AUTOCLOSEABLE_TYPE;
@@ -5406,10 +5405,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
 
-            // in case of "<T, U extends Type<T>>" we can learn about "T" from resolved "U"
-            Map<GenericsTypeName, GenericsType> connections = Arrays.stream(methodGenericTypes)
-                    .collect(toMap(gt -> new GenericsTypeName(gt.getName()), gt -> gt, (v,x) -> v));
-            extractGenericsConnectionsForSuperClassAndInterfaces(connections, resolvedPlaceholders);
+            // in case of "<T, U extends Type<T>>" we can learn about "T" from a resolved "U"
+            extractGenericsConnectionsForBoundTypes(methodGenericTypes, resolvedPlaceholders);
         }
 
         for (GenericsType gt : methodGenericTypes) {
@@ -5497,43 +5494,21 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    private static void extractGenericsConnectionsForSuperClassAndInterfaces(final Map<GenericsTypeName, GenericsType> resolvedPlaceholders, final Map<GenericsTypeName, GenericsType> connections) {
-        for (GenericsType value : new HashSet<>(connections.values())) {
-            if (!value.isPlaceholder() && !value.isWildcard()) {
-                ClassNode valueType = value.getType();
-                List<ClassNode> deepNodes = new LinkedList<>();
-                ClassNode unresolvedSuperClass = valueType.getUnresolvedSuperClass();
-                if (unresolvedSuperClass != null && unresolvedSuperClass.isUsingGenerics()) {
-                    deepNodes.add(unresolvedSuperClass);
-                }
-                for (ClassNode node : valueType.getUnresolvedInterfaces()) {
-                    if (node.isUsingGenerics()) {
-                        deepNodes.add(node);
-                    }
-                }
-                if (!deepNodes.isEmpty()) {
-                    for (GenericsType genericsType : resolvedPlaceholders.values()) {
-                        ClassNode lowerBound = genericsType.getLowerBound();
-                        if (lowerBound != null) {
-                            for (ClassNode deepNode : deepNodes) {
-                                if (lowerBound.equals(deepNode)) {
-                                    extractGenericsConnections(connections, deepNode, lowerBound);
-                                }
-                            }
-                        }
-                        ClassNode[] upperBounds = genericsType.getUpperBounds();
-                        if (upperBounds != null) {
-                            for (ClassNode upperBound : upperBounds) {
-                                for (ClassNode deepNode : deepNodes) {
-                                    if (upperBound.equals(deepNode)) {
-                                        extractGenericsConnections(connections, deepNode, upperBound);
-                                    }
-                                }
-                            }
-                        }
-                    }
-                }
+    private static void extractGenericsConnectionsForBoundTypes(final GenericsType[] spec, final Map<GenericsTypeName, GenericsType> target) {
+        if (spec.length < 2) return;
+        for (GenericsType tp : spec) {
+            ClassNode[] bounds = tp.getUpperBounds();
+            if (bounds == null || bounds.length == 0) continue;
+
+            GenericsTypeName key = new GenericsTypeName(tp.getName());
+            GenericsType value = target.get(key); // look for specific resolved type
+            if (value == null || value.isPlaceholder() || value.isWildcard()) continue;
+
+            Map<GenericsTypeName, GenericsType> inner = new HashMap<>();
+            for (ClassNode bound : bounds) {
+                extractGenericsConnections(inner,value.getType(),bound);
             }
+            inner.forEach(target::putIfAbsent); // GROOVY-10890
         }
     }
 
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 995a26b1d0..7aaa6d2e44 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -115,14 +115,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testListInferrenceWithNullElems() {
+    void testListInferenceWithNullElems() {
         assertScript '''
             List<String> strings = ['a', null]
             assert strings == ['a',null]
         '''
     }
 
-    void testListInferrenceWithAllNullElems() {
+    void testListInferenceWithAllNullElems() {
         assertScript '''
             List<String> strings = [null, null]
             assert strings == [null,null]
@@ -302,7 +302,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             assert result == [ 42 ]
         '''
 
-        ['t::cast', 'n -> t.cast(n)', 'n -> (N) n', '{ n -> (N) n }'].each { cast ->
+        for (cast in ['t::cast', 'n -> t.cast(n)', 'n -> (N) n', '{ n -> (N) n }']) {
             assertScript """
                 Set<Number> f() {
                     Collections.<Number>singleton(42)
@@ -342,16 +342,16 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-10051
     void testReturnTypeInferenceWithMethodGenerics10() {
         assertScript '''
-            abstract class State<H extends Handle> {
-                // Why not return HandleContainer<H>? I can't really say.
-                def <T extends Handle> HandleContainer<T> getHandleContainer(key) {
-                }
+            interface Handle {
+                Result getResult()
             }
             class HandleContainer<H extends Handle> {
                 H handle
             }
-            interface Handle {
-                Result getResult()
+            abstract class State<H extends Handle> {
+                // Why not return HandleContainer<H>? I can't really say.
+                def <T extends Handle> HandleContainer<T> getHandleContainer(key) {
+                }
             }
             class Result {
                 int itemCount
@@ -458,7 +458,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-8409
     void testReturnTypeInferenceWithMethodGenerics14() {
-        ['R', 'S', 'T', 'U'].each { t -> // BiFunction uses R, T and U
+        for (t in ['R', 'S', 'T', 'U']) { // BiFunction uses R, T and U
             assertScript """
                 def <$t> $t applyFunction(java.util.function.BiFunction<Date, URL, $t> action) {
                     $t result = action.apply(new Date(), new URL('https://www.example.com'))
@@ -824,7 +824,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor1() {
+    void testDiamondInferenceFromConstructor1() {
         assertScript '''
             class Foo<U> {
                 U method() { }
@@ -834,13 +834,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor2() {
+    void testDiamondInferenceFromConstructor2() {
         assertScript '''
             Set<Long> set = new HashSet<>()
         '''
     }
 
-    void testDiamondInferrenceFromConstructor3() {
+    void testDiamondInferenceFromConstructor3() {
         assertScript '''
             new HashSet<>(Arrays.asList(0L))
         '''
@@ -864,7 +864,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-7419
-    void testDiamondInferrenceFromConstructor4() {
+    void testDiamondInferenceFromConstructor4() {
         assertScript '''
             Map<Thread.State, Object> map = new EnumMap<>(Thread.State)
             assert map.size() == 0
@@ -873,8 +873,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-6232
-    void testDiamondInferrenceFromConstructor5() {
-        ['"a",new Object()', 'new Object(),"b"', '"a","b"'].each { args ->
+    void testDiamondInferenceFromConstructor5() {
+        for (args in ['"a",new Object()', 'new Object(),"b"', '"a","b"']) {
             assertScript """
                 class C<T> {
                     C(T x, T y) {
@@ -886,7 +886,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9948
-    void testDiamondInferrenceFromConstructor6() {
+    void testDiamondInferenceFromConstructor6() {
         assertScript '''
             class C<T> {
                 T p
@@ -901,7 +901,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9948
-    void testDiamondInferrenceFromConstructor7() {
+    void testDiamondInferenceFromConstructor7() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -914,7 +914,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9984
-    void testDiamondInferrenceFromConstructor7a() {
+    void testDiamondInferenceFromConstructor7a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -927,7 +927,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9956
-    void testDiamondInferrenceFromConstructor8() {
+    void testDiamondInferenceFromConstructor8() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -942,7 +942,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9996
-    void testDiamondInferrenceFromConstructor8a() {
+    void testDiamondInferenceFromConstructor8a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -959,7 +959,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10011
-    void testDiamondInferrenceFromConstructor8b() {
+    void testDiamondInferenceFromConstructor8b() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -977,7 +977,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor9() {
+    void testDiamondInferenceFromConstructor9() {
         assertScript '''
             abstract class A<X> { }
             @groovy.transform.TupleConstructor(defaults=false)
@@ -1010,7 +1010,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9972
-    void testDiamondInferrenceFromConstructor9a() {
+    void testDiamondInferenceFromConstructor9a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1069,7 +1069,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor9b() {
+    void testDiamondInferenceFromConstructor9b() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1100,7 +1100,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9963
-    void testDiamondInferrenceFromConstructor10() {
+    void testDiamondInferenceFromConstructor10() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1114,7 +1114,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10080
-    void testDiamondInferrenceFromConstructor11() {
+    void testDiamondInferenceFromConstructor11() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1134,7 +1134,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10086
-    void testDiamondInferrenceFromConstructor12() {
+    void testDiamondInferenceFromConstructor12() {
         shouldFailWithMessages '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1151,7 +1151,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9970
-    void testDiamondInferrenceFromConstructor13() {
+    void testDiamondInferenceFromConstructor13() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T extends B> {
@@ -1173,7 +1173,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9983
-    void testDiamondInferrenceFromConstructor14() {
+    void testDiamondInferenceFromConstructor14() {
         String types = '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -1220,7 +1220,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10114
-    void testDiamondInferrenceFromConstructor14a() {
+    void testDiamondInferenceFromConstructor14a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -1239,7 +1239,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9995
-    void testDiamondInferrenceFromConstructor15() {
+    void testDiamondInferenceFromConstructor15() {
         [
             ['Closure<A<Long>>', 'java.util.concurrent.Callable<A<Long>>'],
             ['new A<>(42L)', 'return new A<>(42L)']
@@ -1259,7 +1259,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10283
-    void testDiamondInferrenceFromConstructor16() {
+    void testDiamondInferenceFromConstructor16() {
         assertScript '''
             class A<T1, T2> {
             }
@@ -1277,7 +1277,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10291
-    void testDiamondInferrenceFromConstructor17() {
+    void testDiamondInferenceFromConstructor17() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<X> {
@@ -1298,7 +1298,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10228
-    void testDiamondInferrenceFromConstructor18() {
+    void testDiamondInferenceFromConstructor18() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -1314,7 +1314,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10323
-    void testDiamondInferrenceFromConstructor19() {
+    void testDiamondInferenceFromConstructor19() {
         assertScript '''
             class C<T> {
             }
@@ -1325,7 +1325,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10324
-    void testDiamondInferrenceFromConstructor20() {
+    void testDiamondInferenceFromConstructor20() {
         assertScript '''
             class C<T> {
             }
@@ -1336,7 +1336,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10310
-    void testDiamondInferrenceFromConstructor21() {
+    void testDiamondInferenceFromConstructor21() {
         assertScript '''
             @groovy.transform.TupleConstructor
             class A<T> {
@@ -1353,7 +1353,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10344
-    void testDiamondInferrenceFromConstructor22() {
+    void testDiamondInferenceFromConstructor22() {
         assertScript '''
             class C<X,Y> {
             }
@@ -1366,7 +1366,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10230
-    void testDiamondInferrenceFromConstructor23() {
+    void testDiamondInferenceFromConstructor23() {
         assertScript '''
             class A {
                 def <T extends C<Number,Number>> T m(T t) {
@@ -1387,7 +1387,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10351
-    void testDiamondInferrenceFromConstructor24() {
+    void testDiamondInferenceFromConstructor24() {
         assertScript '''
             class C<T> {
                 C(T one, D<T,? extends T> two) {
@@ -1401,10 +1401,10 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10368
-    void testDiamondInferrenceFromConstructor25() {
-        ['T', 'T extends Number', 'T extends Object'].each {
+    void testDiamondInferenceFromConstructor25() {
+        for (t in ['T', 'T extends Number', 'T extends Object']) {
             assertScript """
-                class C<$it> {
+                class C<$t> {
                     C(p) {
                     }
                 }
@@ -1416,7 +1416,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10367
-    void testDiamondInferrenceFromConstructor26() {
+    void testDiamondInferenceFromConstructor26() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<X, Y extends X> { // works without Y
@@ -1430,7 +1430,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10343
-    void testDiamondInferrenceFromConstructor27() {
+    void testDiamondInferenceFromConstructor27() {
         assertScript '''
             class C<T1, T2 extends T1> {
                 T1 p
@@ -1447,7 +1447,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10316
-    void testDiamondInferrenceFromConstructor28() {
+    void testDiamondInferenceFromConstructor28() {
         assertScript '''
             class A<T> {
                 A(T t) {
@@ -1463,7 +1463,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10624
-    void testDiamondInferrenceFromConstructor29() {
+    void testDiamondInferenceFromConstructor29() {
         assertScript '''
             class A<T> {
             }
@@ -1475,7 +1475,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10266
-    void testDiamondInferrenceFromConstructor30() {
+    void testDiamondInferenceFromConstructor30() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -1495,7 +1495,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10662
-    void testDiamondInferrenceFromConstructor31() {
+    void testDiamondInferenceFromConstructor31() {
         assertScript '''
             class A<X, T> {
                 A(T t, X x) {}
@@ -1514,7 +1514,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10633
-    void testDiamondInferrenceFromConstructor32() {
+    void testDiamondInferenceFromConstructor32() {
         assertScript '''
             class A<T, Y> {
                 public B<Y> f
@@ -1535,7 +1535,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10699
-    void testDiamondInferrenceFromConstructor33() {
+    void testDiamondInferenceFromConstructor33() {
         assertScript '''
             class A<T> {
                 A(B<T> b_of_t) {
@@ -1564,7 +1564,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 def type = node.getNodeMetaData(INFERRED_TYPE)
                 assert type.toString(false) == 'C<java.lang.String>'
             })
-            def y = new C<>((String s) -> { print(s); }) // error: Expected type Object for lambda parameter: s
+            def y = new C<>((String s) -> { print(s) }) // error: Expected type Object for lambda parameter: s
         '''
 
         assertScript '''import java.util.function.Supplier
@@ -1583,7 +1583,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10698
-    void testDiamondInferrenceFromConstructor34() {
+    void testDiamondInferenceFromConstructor34() {
         assertScript '''
             class A<T> {
                 A(T t, B<T> b_of_t) {
@@ -1601,7 +1601,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10847
-    void testDiamondInferrenceFromConstructor35() {
+    void testDiamondInferenceFromConstructor35() {
         assertScript '''
             class A<T, U> {
             }
@@ -1619,7 +1619,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10674
-    void testDiamondInferrenceFromConstructor36() {
+    void testDiamondInferenceFromConstructor36() {
         assertScript '''
             class Foo<BB extends Bar<Byte>, X extends BB> {
                 X x
@@ -1653,6 +1653,19 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10890
+    void testDiamondInferenceFromConstructor37() {
+        assertScript '''
+            enum A { X }
+            enum B { Y }
+            void m(Map<A,B> map) {}
+            void test(Map<A,B> map) {
+                m(new EnumMap<>(map))
+            }
+            test([(A.X): B.Y])
+        '''
+    }
+
     // GROOVY-10280
     void testTypeArgumentPropagation() {
         assertScript '''
@@ -2260,7 +2273,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-8961, GROOVY-9915
     void testShouldUseMethodGenericType3() {
-        ['', 'static'].each { mods ->
+        for (mods in ['', 'static']) {
             assertScript """
                 $mods void setX(List<String> strings) {
                 }
@@ -2299,7 +2312,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-9734, GROOVY-9915
     void testShouldUseMethodGenericType4() {
-        ['', 'static'].each { mods ->
+        for (mods in ['', 'static']) {
             assertScript """
                 $mods void m(List<String> strings) {
                 }
@@ -2387,7 +2400,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             assert opt.get() == 42
         '''
         // same as above but with separate type parameter name for each location
-        ['D.&wrap', 'Collections.&singleton', '{x -> [x].toSet()}', '{Collections.singleton(it)}'].each { toSet ->
+        for (toSet in ['D.&wrap', 'Collections.&singleton', '{x -> [x].toSet()}', '{Collections.singleton(it)}']) {
             assertScript """
                 abstract class A<I,O> {
                     abstract O apply(I input)
@@ -3153,7 +3166,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10482
     void testCompatibleArgumentsForPlaceholders6() {
-        ['', 'def', 'public', 'static', '@Deprecated'].each {
+        for (it in ['', 'def', 'public', 'static', '@Deprecated']) {
             assertScript """
                 class Foo<X> {
                     Foo(X x) {
@@ -3171,7 +3184,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10499
     void testCompatibleArgumentsForPlaceholders7() {
-        ['?', 'Y', '? extends Y'].each {
+        for (it in ['?', 'Y', '? extends Y']) {
             assertScript """
                 class Foo<X> {
                     Foo(X x) {
@@ -3242,14 +3255,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10153
     void testCompatibleArgumentsForPlaceholders11() {
-        ['A', 'B', 'C'].each { T ->
+        for (t in ['A', 'B', 'C']) {
             assertScript """
                 class A {}
                 class B extends A {}
                 class C extends B {}
                 class Foo<T extends A> {}
 
-                Foo<? super C> foo = new Foo<$T>()
+                Foo<? super C> foo = new Foo<$t>()
                 //  ^ lower bound is C (explicit); upper bound is A (implicit)
             """
         }
@@ -3263,7 +3276,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '#test(int, java.lang.String). Please check if the declared type is correct and if the method exists.'
     }
 
-    @NotYetImplemented // GROOVY-7720
+    // GROOVY-7720
+    @NotYetImplemented
     void testIncompatibleArgumentsForPlaceholders2() {
         shouldFailWithMessages '''
             class Consumer<T> {
@@ -3798,7 +3812,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-5893
     void testPlusInClosure() {
-        ['def', 'var', 'Object', 'Number', 'Integer', 'Comparable'].each { type ->
+        for (type in ['def', 'var', 'Object', 'Number', 'Integer', 'Comparable']) {
             assertScript """
                 List<Integer> list = [1, 2, 3]
 
@@ -4616,7 +4630,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     void testContravariantMethodResolutionWithImplicitCoercion2() {
-        ['public', 'static'].each { modifier ->
+        for (modifier in ['public', 'static']) {
             assertScript """
                 $modifier <I, O> void transform(java.util.function.Function<? super I, ? extends O> function) {
                     function.apply('')
@@ -4863,7 +4877,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
 
         // GROOVY-9821
-        ['.', '?.', '*.'].each { op ->
+        for (op in ['.', '?.', '*.']) {
             File parentDir = File.createTempDir()
             config.with {
                 targetDirectory = File.createTempDir()
@@ -5038,7 +5052,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10556
     void testSelfReferentialTypeParameter3() {
-        ['(B) this', 'this as B'].each { self ->
+        for (self in ['(B) this', 'this as B']) {
             assertScript """
                 abstract class A<B extends A<B,X>,X> {
                     B m() {