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/12 19:03:54 UTC

[groovy] branch GROOVY_2_5_X updated: GROOVY-10339, GROOVY-10633, GROOVY-10890: STC: type parameter resolution

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

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


The following commit(s) were added to refs/heads/GROOVY_2_5_X by this push:
     new 64fda29773 GROOVY-10339, GROOVY-10633, GROOVY-10890: STC: type parameter resolution
64fda29773 is described below

commit 64fda29773041298656cd8e8fa737a7576864c87
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Jan 3 09:09:05 2023 -0600

    GROOVY-10339, GROOVY-10633, GROOVY-10890: STC: type parameter resolution
    
    2_5_X backport
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  84 +++---
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    |  39 ++-
 .../groovy/transform/stc/DelegatesToSTCTest.groovy |   1 +
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 312 ++++++++++++++++-----
 4 files changed, 305 insertions(+), 131 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 5a9df23787..2824cd95a9 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5294,8 +5294,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         if (methodGenericTypes != null) {
             Map<GenericsTypeName, GenericsType> resolvedPlaceholders = new HashMap<>();
-            for (GenericsType gt : methodGenericTypes) resolvedPlaceholders.put(new GenericsTypeName(gt.getName()), gt);
-
             Parameter[] parameters = method.getParameters();
             final int  nParameters = parameters.length;
 
@@ -5332,16 +5330,33 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                             if (isVargs && lastArg && paramType.isArray() && !argumentType.isArray()) {
                                 paramType = paramType.getComponentType();
                             }
-
                             Map<GenericsTypeName, GenericsType> connections = new HashMap<>();
                             extractGenericsConnections(connections, wrapTypeIfNecessary(argumentType), paramType);
-                            extractGenericsConnectionsForSuperClassAndInterfaces(resolvedPlaceholders, connections);
-
-                            applyGenericsConnections(connections, resolvedPlaceholders);
+                            for (Map.Entry<GenericsTypeName, GenericsType> connection : connections.entrySet()) {
+                                GenericsTypeName name = connection.getKey();
+                                GenericsType   type = connection.getValue();
+                                type = resolvedPlaceholders.put(name, type);
+                                if (type != null) // keep original value!
+                                    resolvedPlaceholders.put(name, type);
+                            }
                         }
                     }
                 }
+                // in case of "<T, U extends Type<T>>", we can learn about "T" from a resolved "U"
+                extractGenericsConnectionsForBoundTypes(methodGenericTypes, resolvedPlaceholders);
+            }
+
+            for (GenericsType tp : methodGenericTypes) {
+                GenericsTypeName name = new GenericsTypeName(tp.getName());
+                if (!resolvedPlaceholders.containsKey(name)) {
+                    // GROOVY-8409, GROOVY-10343, et al.: provide "no type witness" mapping for parameter
+                    ClassNode[] bounds = applyGenericsContext(resolvedPlaceholders, tp.getUpperBounds());
+                    GenericsType gt = new GenericsType(tp.getType(), bounds, null);
+                    gt.putNodeMetaData(GenericsType.class, tp); // record origin
+                    resolvedPlaceholders.put(name, gt);
+                }
             }
+
             returnType = applyGenericsContext(resolvedPlaceholders, returnType);
         }
 
@@ -5404,7 +5419,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             // connect E:T from source to E:Type from target
             for (GenericsType placeholder : aNode.getGenericsTypes()) {
                 for (Map.Entry<GenericsTypeName, GenericsType> e : source.entrySet()) {
-                    if (e.getValue() == placeholder) {
+                    if (e.getValue().getNodeMetaData(GenericsType.class) == placeholder) {
                         GenericsType gt = target.get(e.getKey());
                         // skip "f(g())" for "f(T<String>)" and "<U extends Number> U g()"
                         if (gt != null && isAssignableTo(gt.getType(), placeholder.getType())) {
@@ -5419,43 +5434,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    private static void extractGenericsConnectionsForSuperClassAndInterfaces(final Map<GenericsTypeName, GenericsType> resolvedPlaceholders, final Map<GenericsTypeName, GenericsType> connections) {
-        for (GenericsType value : new HashSet<GenericsType>(connections.values())) {
-            if (!value.isPlaceholder() && !value.isWildcard()) {
-                ClassNode valueType = value.getType();
-                List<ClassNode> deepNodes = new LinkedList<ClassNode>();
-                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);
+            }
+
+            // GROOVY-10890: target putAllIfAbsent inner
+            for (GenericsTypeName k : target.keySet()) {
+                inner.remove(k);
             }
+            target.putAll(inner);
         }
     }
 
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index f65b2f19e4..9aa83ec2dc 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -878,54 +878,47 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
      '''
     }
 
-    void testInferenceForDGM_injectOnCollectionWithInitialValue() {
+    void testInferenceForDGM_injectOnMap() {
         assertScript '''
-            assert ['a','bb','ccc'].inject(0) { acc, str -> acc += str.length(); acc } == 6
+            assert [a:1,b:2].inject(0) { acc, entry -> acc += entry.value; acc} == 3
+            assert [a:1,b:2].inject(0) { acc, k, v -> acc += v; acc} == 3
+        '''
+    }
+    void testInferenceForDGM_injectOnArray() {
+        assertScript '''
+            String[] array = ['a','bb','ccc']
+            assert array.inject { acc, str -> acc += str.toUpperCase(); acc } == 'aBBCCC'
         '''
     }
-
     void testInferenceForDGM_injectOnArrayWithInitialValue() {
         assertScript '''
             String[] array = ['a','bb','ccc']
             assert array.inject(0) { acc, str -> acc += str.length(); acc } == 6
         '''
     }
-
     void testInferenceForDGM_injectOnIteratorWithInitialValue() {
         assertScript '''
             assert ['a','bb','ccc'].iterator().inject(0) { acc, str -> acc += str.length(); acc } == 6
         '''
     }
-
     void testInferenceForDGM_injectOnCollection() {
         assertScript '''
             assert ['a','bb','ccc'].inject { acc, str -> acc += str.toUpperCase(); acc } == 'aBBCCC'
         '''
     }
-
-    void testInferenceForDGM_injectOnArray() {
-        assertScript '''
-            String[] array = ['a','bb','ccc']
-            assert array.inject { acc, str -> acc += str.toUpperCase(); acc } == 'aBBCCC'
-        '''
-    }
-
-    void testInferenceForDGM_injectOnCollectionWithInitialValueDirect() {
-        assertScript '''import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
-            assert DGM.inject(['a','bb','ccc'],0) { acc, str -> acc += str.length(); acc } == 6
-        '''
-    }
-
     void testInferenceForDGM_injectOnCollectionDirect() {
         assertScript '''import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
             assert DGM.inject(['a','bb','ccc']) { acc, str -> acc += str.toUpperCase(); acc } == 'aBBCCC'
         '''
     }
-
-    void testDGM_injectOnMap() {
+    void testInferenceForDGM_injectOnCollectionWithInitialValue() {
         assertScript '''
-            assert [a:1,b:2].inject(0) { acc, entry -> acc += entry.value; acc} == 3
-            assert [a:1,b:2].inject(0) { acc, k, v -> acc += v; acc} == 3
+            assert ['a','bb','ccc'].inject(0) { acc, str -> acc += str.length(); acc } == 6
+        '''
+    }
+    void testInferenceForDGM_injectOnCollectionWithInitialValueDirect() {
+        assertScript '''import org.codehaus.groovy.runtime.DefaultGroovyMethods as DGM
+            assert DGM.inject(['a','bb','ccc'], 0) { acc, str -> acc += str.length(); acc } == 6
         '''
     }
 
diff --git a/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy b/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
index dab315d1bc..a4f3de8010 100644
--- a/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
@@ -748,6 +748,7 @@ class DelegatesToSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-6956
     void testDelegatesToNestedGenericType() {
         assertScript '''
             trait Configurable<ConfigObject> {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 6aebed4dda..288a74857b 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -116,14 +116,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]
@@ -296,6 +296,19 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9064
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenerics13() {
+        assertScript '''
+            List getSomeRows() { [new String[]{'x'}] }
+            List<String[]> rows = getSomeRows()
+            rows.each { row ->
+                def col = row[0].toUpperCase()
+                assert col == 'X'
+            }
+        '''
+    }
+
     // GROOVY-7316, GROOVY-10256
     void testReturnTypeInferenceWithMethodGenerics16() {
         shouldFailWithMessages '''
@@ -395,8 +408,106 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
-    // GROOVY-10637
+    // GROOVY-10347
+    void testReturnTypeInferenceWithMethodGenerics23() {
+        assertScript '''
+            String[] one = ['foo','bar'], two = ['baz']
+            Map<String,Integer> map = one.collectEntries{[it,1]} + two.collectEntries{[it,2]}
+            assert map == [foo:1, bar:1, baz:2]
+        '''
+    }
+
+    // GROOVY-10347
+    void testReturnTypeInferenceWithMethodGenerics24() {
+        assertScript '''
+            class Pogo {
+                String s
+            }
+            class Sorter implements Comparator<Pogo>, Serializable {
+                int compare(Pogo p1, Pogo p2) { p1.s <=> p2.s }
+            }
+
+            Pogo[] pogos = [new Pogo(s:'foo'), new Pogo(s:'bar')]
+            List<String> strings = pogos.sort(true, new Sorter())*.s // sort(T[],boolean,Comparator<? super T>)
+            assert strings == ['bar', 'foo']
+        '''
+    }
+
+    // GROOVY-10589
+    void testReturnTypeInferenceWithMethodGenerics25() {
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+        String pogo = '''
+            @groovy.transform.TupleConstructor
+            class Pogo {
+                final java.time.Instant timestamp
+            }
+            List<Pogo> pogos = []
+        '''
+        assertScript pogo + '''
+            Comparator<Pogo> cmp = { Pogo a, Pogo b -> a.timestamp <=> b.timestamp }
+            pogos = pogos.sort(false, cmp)
+        '''
+        assertScript pogo + '''
+            pogos = pogos.sort(false) { Pogo a, Pogo b ->
+                a.timestamp <=> b.timestamp
+            }
+        '''
+        assertScript pogo + '''
+            pogos = pogos.sort(false) { it.timestamp }
+        '''
+    }
+
+    // GROOVY-7992
+    @NotYetImplemented
+    void testReturnTypeInferenceWithMethodGenerics26() {
+        assertScript '''
+            List<String> strings = ['foo','bar','baz']
+            Comparator<Object> cmp = { o1, o2 -> o1.toString() <=> o2.toString() }
+
+            @groovy.transform.ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.getNodeMetaData(INFERRED_TYPE)
+                assert type.toString(false) == 'java.util.List<java.lang.String>'
+            })
+            def result = strings.sort(false, cmp) // List<T> sort(Iterable<T>,boolean,Comparator<? super T>)
+            assert result == ['bar', 'baz', 'foo']
+        '''
+    }
+
+    // GROOVY-10622
     void testReturnTypeInferenceWithMethodGenerics27() {
+        String types = '''
+            @groovy.transform.TupleConstructor(defaults=false)
+            class A<X> {
+                X x
+            }
+            @groovy.transform.TupleConstructor(defaults=false)
+            class B<Y> {
+                Y y
+            }
+            class C {
+                C(byte b) { }
+            }
+        '''
+        assertScript types + '''
+            def <T extends A<Byte>> void test(B<T> b_of_t) {
+                def t = b_of_t.getY()
+                def x = t.getX()
+                new C(x)
+            }
+            test(new B<>(new A<>((byte)1)))
+        '''
+        assertScript types + '''
+            def <T extends A<Byte>> void test(B<T> b_of_t) {
+                def t = b_of_t.y
+                def x = t.x
+                new C(x)
+            }
+            test(new B<>(new A<>((byte)1)))
+        '''
+    }
+
+    // GROOVY-10637
+    void testReturnTypeInferenceWithMethodGenerics28() {
         assertScript '''
             class Outer extends groovy.transform.stc.MyBean<Inner> {
                 static class Inner {
@@ -412,8 +523,53 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-10749
+    // GROOVY-10646
+    @NotYetImplemented
     void testReturnTypeInferenceWithMethodGenerics29() {
+        String types = '''
+            class Model {
+            }
+            interface Output<T> {
+                T getT()
+            }
+            abstract class WhereDSL<Type> {
+                abstract Type where()
+            }
+            abstract class Input<T> extends WhereDSL<ReferencesOuterClassTP> {
+                class ReferencesOuterClassTP implements Output<T> {
+                    @Override T getT() { return null }
+                }
+            }
+        '''
+        assertScript types + '''
+            void m(Input<Model> input) {
+                def output = input.where()
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    assert node.getNodeMetaData(INFERRED_TYPE).toString(false) == 'Model'
+                })
+                def result = output.getT()
+            }
+        '''
+
+        if (!GroovyAssert.isAtLeastJdk('1.8')) return
+
+        assertScript types + '''
+            @FunctionalInterface
+            interface Xform extends java.util.function.Function<Input<Model>, Output<Model>> {
+            }
+
+            void select(Xform xform) {
+            }
+
+            select { input ->
+                def result = input.where()
+                return result // Cannot return value of type Input$ReferencesOuterClassTP for closure expecting Output<Model>
+            }
+        '''
+    }
+
+    // GROOVY-10749
+    void testReturnTypeInferenceWithMethodGenerics30() {
         if (!GroovyAssert.isAtLeastJdk('1.8')) return
 
         assertScript '''
@@ -426,7 +582,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor1() {
+    void testDiamondInferenceFromConstructor1() {
         assertScript '''
             class Foo<U> {
                 U method() { }
@@ -436,13 +592,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))
         '''
@@ -466,7 +622,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
@@ -475,8 +631,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) {
@@ -488,7 +644,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9948
-    void testDiamondInferrenceFromConstructor6() {
+    void testDiamondInferenceFromConstructor6() {
         assertScript '''
             class C<T> {
                 T p
@@ -503,7 +659,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9948
-    void testDiamondInferrenceFromConstructor7() {
+    void testDiamondInferenceFromConstructor7() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -517,7 +673,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-9984
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor7a() {
+    void testDiamondInferenceFromConstructor7a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -530,7 +686,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9956
-    void testDiamondInferrenceFromConstructor8() {
+    void testDiamondInferenceFromConstructor8() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -545,7 +701,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9996
-    void testDiamondInferrenceFromConstructor8a() {
+    void testDiamondInferenceFromConstructor8a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -562,7 +718,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10011
-    void testDiamondInferrenceFromConstructor8b() {
+    void testDiamondInferenceFromConstructor8b() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -580,7 +736,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testDiamondInferrenceFromConstructor9() {
+    void testDiamondInferenceFromConstructor9() {
         assertScript '''
             abstract class A<X> { }
             @groovy.transform.TupleConstructor(defaults=false)
@@ -613,7 +769,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9972
-    void testDiamondInferrenceFromConstructor9a() {
+    void testDiamondInferenceFromConstructor9a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -673,7 +829,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor9b() {
+    void testDiamondInferenceFromConstructor9b() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -704,7 +860,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9963
-    void testDiamondInferrenceFromConstructor10() {
+    void testDiamondInferenceFromConstructor10() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -719,7 +875,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10080
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor11() {
+    void testDiamondInferenceFromConstructor11() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -739,7 +895,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10086
-    void testDiamondInferrenceFromConstructor12() {
+    void testDiamondInferenceFromConstructor12() {
         shouldFailWithMessages '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -756,7 +912,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9970
-    void testDiamondInferrenceFromConstructor13() {
+    void testDiamondInferenceFromConstructor13() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T extends B> {
@@ -778,7 +934,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-9983
-    void testDiamondInferrenceFromConstructor14() {
+    void testDiamondInferenceFromConstructor14() {
         String types = '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -825,7 +981,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10114
-    void testDiamondInferrenceFromConstructor14a() {
+    void testDiamondInferenceFromConstructor14a() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -844,7 +1000,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)']
@@ -864,7 +1020,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10283
-    void testDiamondInferrenceFromConstructor16() {
+    void testDiamondInferenceFromConstructor16() {
         assertScript '''
             class A<T1, T2> {
             }
@@ -882,7 +1038,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10291
-    void testDiamondInferrenceFromConstructor17() {
+    void testDiamondInferenceFromConstructor17() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<X> {
@@ -904,7 +1060,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10228
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor18() {
+    void testDiamondInferenceFromConstructor18() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class C<T> {
@@ -920,7 +1076,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10323
-    void testDiamondInferrenceFromConstructor19() {
+    void testDiamondInferenceFromConstructor19() {
         assertScript '''
             class C<T> {
             }
@@ -931,7 +1087,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10324
-    void testDiamondInferrenceFromConstructor20() {
+    void testDiamondInferenceFromConstructor20() {
         assertScript '''
             class C<T> {
             }
@@ -942,7 +1098,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10310
-    void testDiamondInferrenceFromConstructor21() {
+    void testDiamondInferenceFromConstructor21() {
         assertScript '''
             @groovy.transform.TupleConstructor
             class A<T> {
@@ -959,7 +1115,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10344
-    void testDiamondInferrenceFromConstructor22() {
+    void testDiamondInferenceFromConstructor22() {
         assertScript '''
             class C<X,Y> {
             }
@@ -972,7 +1128,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10230
-    void testDiamondInferrenceFromConstructor23() {
+    void testDiamondInferenceFromConstructor23() {
         assertScript '''
             class A {
                 def <T extends C<Number,Number>> T m(T t) {
@@ -993,7 +1149,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10351
-    void testDiamondInferrenceFromConstructor24() {
+    void testDiamondInferenceFromConstructor24() {
         assertScript '''
             class C<T> {
                 C(T one, D<T,? extends T> two) {
@@ -1007,10 +1163,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) {
                     }
                 }
@@ -1022,7 +1178,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
@@ -1037,7 +1193,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10343
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor27() {
+    void testDiamondInferenceFromConstructor27() {
         assertScript '''
             class C<T1, T2 extends T1> {
                 T1 p
@@ -1054,7 +1210,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10316
-    void testDiamondInferrenceFromConstructor28() {
+    void testDiamondInferenceFromConstructor28() {
         assertScript '''
             class A<T> {
                 A(T t) {
@@ -1070,7 +1226,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10624
-    void testDiamondInferrenceFromConstructor29() {
+    void testDiamondInferenceFromConstructor29() {
         assertScript '''
             class A<T> {
             }
@@ -1082,7 +1238,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10266
-    void testDiamondInferrenceFromConstructor30() {
+    void testDiamondInferenceFromConstructor30() {
         assertScript '''
             @groovy.transform.TupleConstructor(defaults=false)
             class A<T> {
@@ -1102,7 +1258,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10662
-    void testDiamondInferrenceFromConstructor31() {
+    void testDiamondInferenceFromConstructor31() {
         assertScript '''
             class A<X, T> {
                 A(T t, X x) {}
@@ -1121,8 +1277,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10633
-    @NotYetImplemented
-    void testDiamondInferrenceFromConstructor32() {
+    void testDiamondInferenceFromConstructor32() {
         assertScript '''
             class A<T, Y> {
                 public B<Y> f
@@ -1134,7 +1289,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 void m(T t) {
                 }
             }
-            <T extends Number> void test() {
+            def <T extends Number> void test() {
                 def x = new B<T>()
                 new A<>(x, '').f.m((T) null)
             }
@@ -1144,7 +1299,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10699
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor33() {
+    void testDiamondInferenceFromConstructor33() {
         assertScript '''
             class A<T> {
                 A(B<T> b_of_t) {
@@ -1173,7 +1328,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 closure parameter: s
         '''
 
         assertScript '''import java.util.function.Supplier
@@ -1193,7 +1348,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10698
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor34() {
+    void testDiamondInferenceFromConstructor34() {
         assertScript '''
             class A<T> {
                 A(T t, B<T> b_of_t) {
@@ -1211,7 +1366,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10847
-    void testDiamondInferrenceFromConstructor35() {
+    void testDiamondInferenceFromConstructor35() {
         assertScript '''
             class A<T, U> {
             }
@@ -1230,7 +1385,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     // GROOVY-10674
     @NotYetImplemented
-    void testDiamondInferrenceFromConstructor36() {
+    void testDiamondInferenceFromConstructor36() {
         assertScript '''
             class Foo<BB extends Bar<Byte>, X extends BB> {
                 X x
@@ -1264,6 +1419,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 '''
@@ -2637,7 +2805,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) {
@@ -2655,7 +2823,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) {
@@ -2727,14 +2895,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-10153
     @NotYetImplemented
     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)
             """
         }
@@ -3240,7 +3408,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-5893
-    @NotYetImplemented
     void testPlusInClosure() {
         assertScript '''
         def list = [1, 2, 3]
@@ -3444,12 +3611,13 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-6233
     void testConstructorArgumentsAgainstGenerics() {
         shouldFailWithMessages '''
-            class Foo<T>{  Foo(T a, T b){} }
-            def bar() {
-                Foo<Map> f = new Foo<Map>("a",1)
+            class C<T> {
+                C(T a, T b) {
+                }
             }
-            bar()
-        ''', '[Static type checking] - Cannot find matching method Foo#<init>(java.lang.String, int)'
+            def c_of_map = new C<Map>("a", 1)
+        ''',
+        'Cannot find matching method C#<init>(java.lang.String, int)'
     }
 
     // GROOVY-5742
@@ -3993,7 +4161,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testGROOVY5981() {
+    // GROOVY-5981
+    void testCovariantAssignment() {
         assertScript '''
             import javax.swing.*
             import java.awt.*
@@ -4337,7 +4506,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-10556
     @NotYetImplemented
     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() {
@@ -4391,8 +4560,21 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-6956
+    void testMockito1() {
+        assertScript '''
+            class ArgumentCaptor<T> {
+                T value() {}
+                static <U, S extends U> ArgumentCaptor<U> forClass(Class<S> clazz) {}
+            }
+
+            def captor = ArgumentCaptor.forClass(String.class)
+            captor?.value()?.toUpperCase()
+        '''
+    }
+
     // GROOVY-10673
-    void testMockito() {
+    void testMockito2() {
         assertScript '''
             @Grab('org.mockito:mockito-all:1.10.19')
             import static org.mockito.Mockito.*