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 2022/03/30 22:22:18 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-10282: `GenericsUtils`: do not mix type parameter contexts

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

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


The following commit(s) were added to refs/heads/GROOVY_3_0_X by this push:
     new 2ab6c68  GROOVY-10282: `GenericsUtils`: do not mix type parameter contexts
2ab6c68 is described below

commit 2ab6c6852002031bf2a9939d4f3cc32e7232a407
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Oct 5 11:59:35 2021 -0500

    GROOVY-10282: `GenericsUtils`: do not mix type parameter contexts
    
    collect for BiFunction<U, ? super T, U> yields [T:U, U:? super T, R:U]
      not [T:? super T, U:? super T, R:? super T]
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 170 ++---
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 567 +++++++++------
 src/test/groovy/transform/stc/LambdaTest.groovy    | 805 ++++++++++-----------
 3 files changed, 799 insertions(+), 743 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 3142345..ff571ac 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -40,7 +40,6 @@ import org.codehaus.groovy.runtime.memoize.ConcurrentSoftCache;
 import org.codehaus.groovy.runtime.memoize.EvictableCache;
 
 import java.lang.ref.SoftReference;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashMap;
@@ -142,50 +141,48 @@ public class GenericsUtils {
         return gt;
     }
 
-    public static Map<GenericsType.GenericsTypeName, GenericsType> extractPlaceholders(ClassNode cn) {
-        Map<GenericsType.GenericsTypeName, GenericsType> ret = new HashMap<>();
-        extractPlaceholders(cn, ret);
-        return ret;
+    public static Map<GenericsType.GenericsTypeName, GenericsType> extractPlaceholders(final ClassNode type) {
+        Map<GenericsType.GenericsTypeName, GenericsType> placeholders = new HashMap<>();
+        extractPlaceholders(type, placeholders);
+        return placeholders;
     }
 
     /**
      * For a given classnode, fills in the supplied map with the parameterized
      * types it defines.
      *
-     * @param node the class node to check
-     * @param map the generics type information collector
+     * @param type the class node to check
+     * @param placeholders the generics type information collector
      */
-    public static void extractPlaceholders(ClassNode node, Map<GenericsType.GenericsTypeName, GenericsType> map) {
-        if (node == null) return;
+    public static void extractPlaceholders(final ClassNode type, final Map<GenericsType.GenericsTypeName, GenericsType> placeholders) {
+        if (type == null) return;
 
-        if (node.isArray()) {
-            extractPlaceholders(node.getComponentType(), map);
+        if (type.isArray()) {
+            extractPlaceholders(type.getComponentType(), placeholders);
             return;
         }
 
-        if (!node.isUsingGenerics() || !node.isRedirectNode()) return;
-        GenericsType[] parameterized = node.getGenericsTypes();
+        if (!type.isUsingGenerics() || !type.isRedirectNode()) return;
+        GenericsType[] parameterized = type.getGenericsTypes();
         if (parameterized == null || parameterized.length == 0) return;
-        GenericsType[] redirectGenericsTypes = node.redirect().getGenericsTypes();
-        if (redirectGenericsTypes == null || (node.isGenericsPlaceHolder() // GROOVY-8609
+        GenericsType[] redirectGenericsTypes = type.redirect().getGenericsTypes();
+        if (redirectGenericsTypes == null || (type.isGenericsPlaceHolder() // GROOVY-8609
                                               && redirectGenericsTypes.length != parameterized.length)) {
             redirectGenericsTypes = parameterized;
-        }
-        if (redirectGenericsTypes.length != parameterized.length) {
+        } else if (redirectGenericsTypes.length != parameterized.length) {
             throw new GroovyBugError("Expected earlier checking to detect generics parameter arity mismatch" +
-                    "\nExpected: " + node.getName() + toGenericTypesString(redirectGenericsTypes) +
-                    "\nSupplied: " + node.getName() + toGenericTypesString(parameterized));
+                    "\nExpected: " + type.getName() + toGenericTypesString(redirectGenericsTypes) +
+                    "\nSupplied: " + type.getName() + toGenericTypesString(parameterized));
         }
 
         List<GenericsType> valueList = new LinkedList<>();
-        for (int i = 0; i < redirectGenericsTypes.length; i++) {
-            GenericsType redirectType = redirectGenericsTypes[i];
-            if (redirectType.isPlaceholder()) {
-                GenericsType.GenericsTypeName name = new GenericsType.GenericsTypeName(redirectType.getName());
-                if (!map.containsKey(name)) {
+        for (int i = 0, n = redirectGenericsTypes.length; i < n; i += 1) {
+            GenericsType rgt = redirectGenericsTypes[i];
+            if (rgt.isPlaceholder()) {
+                GenericsType.GenericsTypeName name = new GenericsType.GenericsTypeName(rgt.getName());
+                if (!placeholders.containsKey(name)) {
                     GenericsType value = parameterized[i];
-                    map.put(name, value);
-
+                    placeholders.put(name, value);
                     valueList.add(value);
                 }
             }
@@ -195,16 +192,16 @@ public class GenericsUtils {
             if (value.isWildcard()) {
                 ClassNode lowerBound = value.getLowerBound();
                 if (lowerBound != null) {
-                    extractPlaceholders(lowerBound, map);
+                    extractPlaceholders(lowerBound, placeholders);
                 }
                 ClassNode[] upperBounds = value.getUpperBounds();
                 if (upperBounds != null) {
                     for (ClassNode upperBound : upperBounds) {
-                        extractPlaceholders(upperBound, map);
+                        extractPlaceholders(upperBound, placeholders);
                     }
                 }
             } else if (!value.isPlaceholder()) {
-                extractPlaceholders(value.getType(), map);
+                extractPlaceholders(value.getType(), placeholders);
             }
         }
     }
@@ -318,12 +315,15 @@ public class GenericsUtils {
         if (type.isArray()) {
             return makeClassSafeWithGenerics(type.getComponentType(), genericTypes).makeArray();
         }
-        GenericsType[] gtypes = EMPTY_GENERICS_ARRAY;
-        if (genericTypes != null) {
-            gtypes = new GenericsType[genericTypes.length];
-            System.arraycopy(genericTypes, 0, gtypes, 0, gtypes.length);
+        int nTypes = (genericTypes == null ? 0 : genericTypes.length);
+        GenericsType[] gTypes;
+        if (nTypes == 0) {
+            gTypes = EMPTY_GENERICS_ARRAY;
+        } else {
+            gTypes = new GenericsType[nTypes];
+            System.arraycopy(genericTypes, 0, gTypes, 0, nTypes);
         }
-        return makeClassSafe0(type, gtypes);
+        return makeClassSafe0(type, gTypes);
     }
 
     public static MethodNode correctToGenericsSpec(Map<String, ClassNode> genericsSpec, MethodNode mn) {
@@ -342,7 +342,7 @@ public class GenericsUtils {
     }
 
     public static ClassNode correctToGenericsSpecRecurse(Map<String, ClassNode> genericsSpec, ClassNode type) {
-        return correctToGenericsSpecRecurse(genericsSpec, type, new ArrayList<String>());
+        return correctToGenericsSpecRecurse(genericsSpec, type, Collections.emptyList());
     }
 
     /**
@@ -353,7 +353,7 @@ public class GenericsUtils {
         ClassNode[] newTypes = new ClassNode[types.length];
         boolean modified = false;
         for (int i = 0; i < types.length; i++) {
-            newTypes[i] = correctToGenericsSpecRecurse(genericsSpec, types[i], new ArrayList<String>());
+            newTypes[i] = correctToGenericsSpecRecurse(genericsSpec, types[i], Collections.emptyList());
             modified = modified || (types[i] != newTypes[i]);
         }
         if (!modified) return types;
@@ -364,8 +364,8 @@ public class GenericsUtils {
         if (type.isArray()) {
             return correctToGenericsSpecRecurse(genericsSpec, type.getComponentType(), exclusions).makeArray();
         }
-        if (type.isGenericsPlaceHolder() && !exclusions.contains(type.getUnresolvedName())) {
-            String name = type.getGenericsTypes()[0].getName();
+        String name = type.getUnresolvedName();
+        if (type.isGenericsPlaceHolder() && !exclusions.contains(name)) {
             exclusions = plus(exclusions, name); // GROOVY-7722
             type = genericsSpec.get(name);
             if (type != null && type.isGenericsPlaceHolder()) {
@@ -538,16 +538,8 @@ public class GenericsUtils {
         }
     }
 
-    public static ClassNode getSuperClass(ClassNode type, ClassNode target) {
-        ClassNode superClass = ClassHelper.getNextSuperClass(type, target);
-
-        if (superClass == null) {
-            if (ClassHelper.isPrimitiveType(type)) {
-                superClass = ClassHelper.getNextSuperClass(ClassHelper.getWrapper(type), target);
-            }
-        }
-
-        return superClass;
+    public static ClassNode getSuperClass(final ClassNode type, final ClassNode target) {
+        return ClassHelper.getNextSuperClass(ClassHelper.isPrimitiveType(type) ? ClassHelper.getWrapper(type) : type, target);
     }
 
     private static void extractSuperClassGenerics(final GenericsType[] usage, final GenericsType[] declaration, final Map<String, ClassNode> spec) {
@@ -806,7 +798,7 @@ public class GenericsUtils {
      * so we need actual types:  T: String, S: Long
      */
     public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver) {
-        return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, false).getV1();
+        return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, false);
     }
 
     /**
@@ -821,79 +813,25 @@ public class GenericsUtils {
      * @since 3.0.0
      */
     public static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(final ClassNode declaringClass, final ClassNode actualReceiver) {
-        return makeDeclaringAndActualGenericsTypeMapOfExactType(declaringClass, actualReceiver, new HashSet<>());
+        return doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, true);
     }
 
-    private static Map<GenericsType, GenericsType> makeDeclaringAndActualGenericsTypeMapOfExactType(final ClassNode declaringClass, final ClassNode actualReceiver, final Set<ClassNode> parameterizedTypes) {
-        Tuple2<Map<GenericsType, GenericsType>, ClassNode> tuple = doMakeDeclaringAndActualGenericsTypeMap(declaringClass, actualReceiver, true);
-        Map<GenericsType, GenericsType> result = tuple.getV1();
-        ClassNode parameterizedType = tuple.getV2();
-
-        if (parameterizedTypes.add(parameterizedType) && hasPlaceHolders(parameterizedType)) {
-            result.putAll(makeDeclaringAndActualGenericsTypeMapOfExactType(parameterizedType, actualReceiver, parameterizedTypes));
-            result = connectGenericsTypes(result);
-        }
-
-        return result;
-    }
-
-    private static Tuple2<Map<GenericsType, GenericsType>, ClassNode> doMakeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver, final boolean tryToFindExactType) {
+    private static Map<GenericsType, GenericsType> doMakeDeclaringAndActualGenericsTypeMap(final ClassNode declaringClass, final ClassNode actualReceiver, final boolean tryToFindExactType) {
+        Map<GenericsType, GenericsType> map = Collections.emptyMap();
         ClassNode parameterizedType = findParameterizedTypeFromCache(declaringClass, actualReceiver, tryToFindExactType);
-        if (parameterizedType == null) {
-            return tuple(Collections.emptyMap(), parameterizedType);
-        }
-
-        Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
-        result.putAll(makePlaceholderAndParameterizedTypeMap(declaringClass));
-        result.putAll(makePlaceholderAndParameterizedTypeMap(parameterizedType));
-
-        result = connectGenericsTypes(result);
-
-        return tuple(result, parameterizedType);
-    }
-
-    private static Map<GenericsType, GenericsType> makePlaceholderAndParameterizedTypeMap(final ClassNode declaringClass) {
-        if (null == declaringClass) {
-            return Collections.emptyMap();
-        }
-
-        Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
-
-        ClassNode redirectDeclaringClass = declaringClass.redirect();
-        GenericsType[] declaringGenericsTypes = declaringClass.getGenericsTypes();
-        GenericsType[] redirectDeclaringGenericsTypes = redirectDeclaringClass.getGenericsTypes();
-
-        if (null != declaringGenericsTypes && null != redirectDeclaringGenericsTypes) {
-            for (int i = 0, n = declaringGenericsTypes.length; i < n; i++) {
-                result.put(redirectDeclaringGenericsTypes[i], declaringGenericsTypes[i]);
-            }
-        }
-
-        return result;
-    }
-
-    private static Map<GenericsType, GenericsType> connectGenericsTypes(final Map<GenericsType, GenericsType> genericsTypeMap) {
-        Map<GenericsType, GenericsType> result = new LinkedHashMap<>();
-
-        outer:
-        for (Map.Entry<GenericsType, GenericsType> entry : genericsTypeMap.entrySet()) {
-            GenericsType key = entry.getKey();
-            GenericsType value = entry.getValue();
-
-            if (value.isPlaceholder()) {
-                for (Map.Entry<GenericsType, GenericsType> genericsTypeMapEntry : genericsTypeMap.entrySet()) {
-                    GenericsType genericsTypeMapEntryValue = genericsTypeMapEntry.getValue();
-                    if (!genericsTypeMapEntryValue.isPlaceholder() && (genericsTypeMapEntry.getKey().getName().equals(value.getName()))) {
-                        result.put(key, genericsTypeMapEntryValue); // connected to actual type
-                        continue outer;
-                    }
+        if (parameterizedType != null && parameterizedType.isRedirectNode() && !parameterizedType.isGenericsPlaceHolder()) { // GROOVY-10166
+            // declaringClass may be "List<T> -> List<E>" and parameterizedType may be "List<String> -> List<E>" or "List<> -> List<E>"
+            GenericsType[] targetGenericsTypes = parameterizedType.redirect().getGenericsTypes();
+            if (targetGenericsTypes != null) {
+                GenericsType[] sourceGenericsTypes = parameterizedType.getGenericsTypes();
+                if (sourceGenericsTypes == null) sourceGenericsTypes = EMPTY_GENERICS_ARRAY;
+                map = new LinkedHashMap<>();
+                for (int i = 0, m = sourceGenericsTypes.length, n = targetGenericsTypes.length; i < n; i += 1) {
+                    map.put(targetGenericsTypes[i], i < m ? sourceGenericsTypes[i] : targetGenericsTypes[i]);
                 }
             }
-
-            result.put(key, value);
         }
-
-        return result;
+        return map;
     }
 
     /**
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 545c892..2ad5bfb 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1000,10 +1000,11 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             C.m(new A<>(new B()))
             C.m(new A<>(new E()))
             C.m(flag ? new A<>(new B()) : new A<>(new B()))
-            C.m(flag ? new A<>(new B()) : new A<>(new E())) // Cannot call m(A<B>) with arguments [A<? extends B>]
+            C.m(flag ? new A<>(new B()) : new A<>((B)null))
+            C.m(flag ? new A<>(new B()) : new A<>((B)new E())) // Cannot call m(A<B>) with arguments [A<? extends B>]
         '''
-
-        /*shouldFailWithMessages types + '''
+/*
+        shouldFailWithMessages types + '''
             A<B> x = new A<>(new Object())
             A<B> y = true ? new A<>(new B()) : new A<>(new Object())
 
@@ -1013,7 +1014,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot assign A<java.lang.Object> to: A<B>',
         'Cannot assign A<? extends java.lang.Object> to: A<B>',
         'Cannot call C#m(A<B>) with arguments [A<java.lang.Object>]',
-        'Cannot call C#m(A<B>) with arguments [A<? extends java.lang.Object>]'*/
+        'Cannot call C#m(A<B>) with arguments [A<? extends java.lang.Object>]'
+*/
     }
 
     @NotYetImplemented // GROOVY-10114
@@ -1286,7 +1288,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         shouldFailWithMessages '''
             List<String> elements = ['a','b', 1]
         ''',
-        'Incompatible generic argument types. Cannot assign java.util.List <java.io.Serializable> to: java.util.List <String>'
+        'Cannot assign java.util.List <java.io.Serializable> to: java.util.List <String>'
     }
 
     void testGenericAssignmentWithSubClass() {
@@ -1400,7 +1402,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             class FooBound {
             }
             new Foo()
-        ''', 'Cannot find matching method FooWithGenerics#say(java.lang.Object)'
+        ''',
+        'Cannot find matching method FooWithGenerics#say(java.lang.Object)'
     }
 
     // GROOVY-5237
@@ -1522,7 +1525,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             A<String, Integer> a = new B()
             a.test()
-        ''', 'Cannot call A <String, Integer>#<init>(java.lang.Class <String>, java.lang.Class <Integer>) with arguments [java.lang.Class <java.lang.Integer>, java.lang.Class <java.lang.String>]'
+        ''',
+        'Cannot call A <String, Integer>#<init>(java.lang.Class <String>, java.lang.Class <Integer>) with arguments [java.lang.Class <java.lang.Integer>, java.lang.Class <java.lang.String>]'
     }
 
     void testMethodCallWithMapParameterUnbounded() {
@@ -1589,14 +1593,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testPutMethodWithPrimitiveValue1() {
+    void testPutMethodWithPrimitiveValue() {
         assertScript '''
             def map = new HashMap<String, Integer>()
             map.put('hello', 1)
         '''
     }
 
-    void testPutMethodWithPrimitiveValue2() {
+    void testPutAtMethodWithPrimitiveValue() {
         assertScript '''
             def map = new HashMap<String, Integer>()
             map['hello'] = 1
@@ -1607,7 +1611,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         shouldFailWithMessages '''
             def map = new HashMap<String, Integer>()
             map.put('hello', new Object())
-        ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object). Please check if the declared type is correct and if the method exists.'
+        ''',
+        'Cannot find matching method java.util.HashMap#put(java.lang.String, java.lang.Object). Please check if the declared type is correct and if the method exists.'
     }
 
     void testShouldComplainAboutToInteger() {
@@ -1635,11 +1640,12 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
 
         if (config.pluginFactory instanceof AntlrParserPluginFactory) {
-            shouldFailWithMessages code, 'Cannot find matching method java.lang.Object#getAt(int)'
+            shouldFailWithMessages code,
+                'Cannot find matching method java.lang.Object#getAt(int)'
         } else {
             shouldFailWithMessages code,
-                    'Cannot find matching method java.lang.Object#getAt(int)',
-                    'Cannot find matching method java.lang.Object#toInteger()'
+                'Cannot find matching method java.lang.Object#getAt(int)',
+                'Cannot find matching method java.lang.Object#toInteger()'
         }
     }
 
@@ -1680,44 +1686,46 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             }
         }
         new ClassB()
-        ''', 'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA <Long>#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends java.lang.Object>]'
+        ''',
+        'Cannot call <X> groovy.transform.stc.GenericsSTCTest$ClassA <Long>#bar(java.lang.Class <Long>) with arguments [java.lang.Class <? extends java.lang.Object>]'
     }
 
     // GROOVY-8961, GROOVY-9915
     void testShouldUseMethodGenericType3() {
         ['', 'static'].each { mods ->
             assertScript """
-                $mods void setM(List<String> strings) {
+                $mods void setX(List<String> strings) {
                 }
                 void test() {
-                  m = Collections.emptyList() // Cannot assign value of type List<T> to variable of List<String>
+                    x = Collections.emptyList()
                 }
                 test()
             """
             assertScript """
-                $mods void setM(Collection<String> strings) {
+                $mods void setX(Collection<String> strings) {
                 }
                 void test() {
-                  m = Collections.emptyList()
+                    x = Collections.emptyList()
                 }
                 test()
             """
             assertScript """
-                $mods void setM(Iterable<String> strings) {
+                $mods void setX(Iterable<String> strings) {
                 }
                 void test() {
-                  m = Collections.emptyList()
+                    x = Collections.emptyList()
                 }
                 test()
             """
 
             shouldFailWithMessages """
-                $mods void setM(List<String> strings) {
+                $mods void setX(List<String> strings) {
                 }
                 void test() {
-                  m = Collections.<Integer>emptyList()
+                    x = Collections.<Integer>emptyList()
                 }
-            """, '[Static type checking] - Cannot assign value of type java.util.List <Integer> to variable of type java.util.List <String>'
+            """,
+            'Cannot assign value of type java.util.List <Integer> to variable of type java.util.List <String>'
         }
     }
 
@@ -1728,7 +1736,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 $mods void m(List<String> strings) {
                 }
                 void test() {
-                  m(Collections.emptyList()) // Cannot call m(List<String>) with arguments [List<T>]
+                    m(Collections.emptyList())
                 }
                 test()
             """
@@ -1736,7 +1744,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 $mods void m(Collection<String> strings) {
                 }
                 void test() {
-                  m(Collections.emptyList())
+                    m(Collections.emptyList())
                 }
                 test()
             """
@@ -1744,7 +1752,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 $mods void m(Iterable<String> strings) {
                 }
                 void test() {
-                  m(Collections.emptyList())
+                    m(Collections.emptyList())
                 }
                 test()
             """
@@ -1811,31 +1819,33 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             assert opt.get() == 42
         '''
         // same as above but with separate type parameter name for each location
-        assertScript '''
-            abstract class A<I,O> {
-                abstract O apply(I input)
-            }
-            class C<T> {
-                static <U> C<U> of(U item) {
-                    new C<U>()
+        ['D.&wrap', 'Collections.&singleton', '{x -> [x].toSet()}', '{Collections.singleton(it)}'].each { toSet ->
+            assertScript """
+                abstract class A<I,O> {
+                    abstract O apply(I input)
                 }
-                def <V> C<V> map(A<? super T, ? super V> func) {
-                    new C<V>()
+                class C<T> {
+                    static <U> C<U> of(U item) {
+                        new C<U>()
+                    }
+                    def <V> C<V> map(A<? super T, ? super V> func) {
+                        new C<V>()
+                    }
                 }
-            }
-            class D {
-                static <W> Set<W> wrap(W o) {
+                class D {
+                    static <W> Set<W> wrap(W o) {
+                    }
                 }
-            }
 
-            void test() {
-                def c = C.of(42)
-                def d = c.map(D.&wrap)
-                def e = d.map(x -> x.first().intValue())
-            }
+                void test() {
+                    def c = C.of(42)
+                    def d = c.map($toSet)
+                    def e = d.map(x -> x.first().intValue())
+                }
 
-            test()
-        '''
+                test()
+            """
+        }
     }
 
     // GROOVY-9945
@@ -1875,7 +1885,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             List<String> list = ['a','b','c']
             Collection<Integer> e = (Collection<Integer>) [1,2,3]
             boolean r = list.addAll(e)
-        ''', 'Cannot call java.util.List <java.lang.String>#addAll(java.util.Collection <? extends java.lang.String>) with arguments [java.util.Collection <Integer>]'
+        ''',
+        'Cannot call java.util.List <java.lang.String>#addAll(java.util.Collection <? extends java.lang.String>) with arguments [java.util.Collection <Integer>]'
     }
 
     // GROOVY-5528
@@ -1906,7 +1917,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type instanceof LUB
             })
             List<String> list = ["foo", "$bar"]
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
 
         shouldFailWithMessages base + '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
@@ -1914,12 +1926,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 assert node.getNodeMetaData(INFERRED_TYPE).genericsTypes[0].type == GSTRING_TYPE // single element means no LUB
             })
             List<String> list = ["$bar"]
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
 
         shouldFailWithMessages base + '''
             void m(List<String> list) {}
             m(["foo", "$bar"])
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
     }
 
     // GROOVY-5559, GROOVY-10010
@@ -1928,17 +1942,20 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
         shouldFailWithMessages base + '''
             Map<String,String> map = [x:"foo", y:"$bar"]
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
 
         shouldFailWithMessages base + '''
             void m(Map<?,String> map) {}
             m([x:"foo", y:"$bar"])
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
 
         shouldFailWithMessages base + '''
             void m(Map<?,String> map) {}
             m(x:"foo", y:"$bar")
-        ''', 'You are trying to use a GString in place of a String'
+        ''',
+        'You are trying to use a GString in place of a String'
     }
 
     // GROOVY-5559: related behaviour
@@ -1956,49 +1973,49 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-5594
     void testMapEntryUsingPropertyNotation() {
         assertScript '''
-        Map.Entry<Date, Integer> entry = null
+            Map.Entry<Date, Integer> entry = null
 
-        @ASTTest(phase=INSTRUCTION_SELECTION, value={
-            assert node.getNodeMetaData(INFERRED_TYPE) == make(Date)
-        })
-        def k = entry?.key
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                assert node.getNodeMetaData(INFERRED_TYPE) == make(Date)
+            })
+            def k = entry?.key
 
-        @ASTTest(phase=INSTRUCTION_SELECTION, value={
-            assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
-        })
-        def v = entry?.value
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                assert node.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
+            })
+            def v = entry?.value
         '''
     }
 
     void testInferenceFromMap() {
         assertScript '''
-        Map<Date, Integer> map = [:]
+            Map<Date, Integer> map = [:]
 
-        @ASTTest(phase=INSTRUCTION_SELECTION, value={
-            def infType = node.getNodeMetaData(INFERRED_TYPE)
-            assert infType == make(Set)
-            def entryInfType = infType.genericsTypes[0].type
-            assert entryInfType == make(Map.Entry)
-            assert entryInfType.genericsTypes[0].type == make(Date)
-            assert entryInfType.genericsTypes[1].type == Integer_TYPE
-        })
-        def entries = map?.entrySet()
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def infType = node.getNodeMetaData(INFERRED_TYPE)
+                assert infType == make(Set)
+                def entryInfType = infType.genericsTypes[0].type
+                assert entryInfType == make(Map.Entry)
+                assert entryInfType.genericsTypes[0].type == make(Date)
+                assert entryInfType.genericsTypes[1].type == Integer_TYPE
+            })
+            def entries = map?.entrySet()
         '''
     }
 
     void testInferenceFromListOfMaps() {
         assertScript '''
-        List<Map<Date, Integer>> maps = []
+            List<Map<Date, Integer>> maps = []
 
-        @ASTTest(phase=INSTRUCTION_SELECTION, value={
-            def listType = node.getNodeMetaData(INFERRED_TYPE)
-            assert listType == Iterator_TYPE
-            def infType = listType.genericsTypes[0].type
-            assert infType == make(Map)
-            assert infType.genericsTypes[0].type == make(Date)
-            assert infType.genericsTypes[1].type == Integer_TYPE
-        })
-        def iter = maps?.iterator()
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def listType = node.getNodeMetaData(INFERRED_TYPE)
+                assert listType == Iterator_TYPE
+                def infType = listType.genericsTypes[0].type
+                assert infType == make(Map)
+                assert infType.genericsTypes[0].type == make(Date)
+                assert infType.genericsTypes[1].type == Integer_TYPE
+            })
+            def iter = maps?.iterator()
         '''
     }
 
@@ -2050,7 +2067,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     void testInferDiamondUsingAIC() {
         shouldFailWithMessages '''
             Map<String,Date> map = new HashMap<>() {}
-        ''', 'Cannot use diamond <> with anonymous inner classes'
+        ''',
+        'Cannot use diamond <> with anonymous inner classes'
     }
 
     // GROOVY-5614
@@ -2082,7 +2100,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             r.bindings2['a'] = 'A'
             r.bindings2.put('b', 'B')
-
         '''
     }
     void testInferDiamondForAssignment() {
@@ -2137,7 +2154,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             })
             Map<Date, Date> map = new HashMap<>()
             map.put('foo', new Date())
-        ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.lang.String, java.util.Date). Please check if the declared type is correct and if the method exists.'
+        ''',
+        'Cannot find matching method java.util.HashMap#put(java.lang.String, java.util.Date). Please check if the declared type is correct and if the method exists.'
     }
     void testInferDiamondForAssignmentWithDatesAndIllegalKeyUsingSquareBracket() {
         shouldFailWithMessages '''
@@ -2156,7 +2174,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             })
             Map<Date, Date> map = new HashMap<>()
             map['foo'] = new Date()
-        ''', 'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
+        ''',
+        'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.lang.String, java.util.Date]'
     }
     void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingPut() {
         shouldFailWithMessages '''
@@ -2175,7 +2194,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             })
             Map<Date, Date> map = new HashMap<>()
             map.put(new Date(), 'foo')
-        ''', '[Static type checking] - Cannot find matching method java.util.HashMap#put(java.util.Date, java.lang.String). Please check if the declared type is correct and if the method exists.'
+        ''',
+        'Cannot find matching method java.util.HashMap#put(java.util.Date, java.lang.String). Please check if the declared type is correct and if the method exists.'
     }
     void testInferDiamondForAssignmentWithDatesAndIllegalValueUsingSquareBracket() {
         shouldFailWithMessages '''
@@ -2194,21 +2214,22 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             })
             Map<Date, Date> map = new HashMap<>()
             map[new Date()] = 'foo'
-        ''', 'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
+        ''',
+        'Cannot call <K,V> java.util.HashMap <java.util.Date, java.util.Date>#putAt(java.util.Date, java.util.Date) with arguments [java.util.Date, java.lang.String]'
     }
 
     void testCallMethodWithParameterizedArrayList() {
         assertScript '''
-        class MyUtility {
-            def methodOne() {
-                def someFiles = new ArrayList<File>()
-                def someString = ''
-                methodTwo someString, someFiles
-            }
+            class MyUtility {
+                def methodOne() {
+                    def someFiles = new ArrayList<File>()
+                    def someString = ''
+                    methodTwo someString, someFiles
+                }
 
-            def methodTwo(String s, List<File> files) {}
-        }
-        new MyUtility()
+                def methodTwo(String s, List<File> files) {}
+            }
+            new MyUtility()
         '''
     }
 
@@ -2222,35 +2243,35 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-5617
     void testIntermediateListAssignmentOfGStrings() {
         assertScript '''
-        def test() {
-            @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                def type = node.getNodeMetaData(INFERRED_TYPE)
-                assert type == make(List)
-                assert type.genericsTypes.length==1
-                assert type.genericsTypes[0].type == GSTRING_TYPE
-            })
-            List<GString> dates = ["${new Date()-1}", "${new Date()}", "${new Date()+1}"]
-            dates*.toUpperCase()
-            @ASTTest(phase=INSTRUCTION_SELECTION, value={
-                def type = node.getNodeMetaData(INFERRED_TYPE)
-                assert type == make(List)
-                assert type.genericsTypes.length==1
-                assert type.genericsTypes[0].type == GSTRING_TYPE
-            })
-            List<GString> copied = []
-            copied.addAll(dates)
-            List<String> upper = copied*.toUpperCase()
-        }
-        test()
+            def test() {
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    def type = node.getNodeMetaData(INFERRED_TYPE)
+                    assert type == make(List)
+                    assert type.genericsTypes.length==1
+                    assert type.genericsTypes[0].type == GSTRING_TYPE
+                })
+                List<GString> dates = ["${new Date()-1}", "${new Date()}", "${new Date()+1}"]
+                dates*.toUpperCase()
+                @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                    def type = node.getNodeMetaData(INFERRED_TYPE)
+                    assert type == make(List)
+                    assert type.genericsTypes.length==1
+                    assert type.genericsTypes[0].type == GSTRING_TYPE
+                })
+                List<GString> copied = []
+                copied.addAll(dates)
+                List<String> upper = copied*.toUpperCase()
+            }
+            test()
         '''
     }
 
     // GROOVY-5650
     void testRegressionInGenericsTypeInference() {
         assertScript '''import groovy.transform.stc.GenericsSTCTest.JavaClassSupport as JavaClass
-        List<JavaClass.StringContainer> containers = new ArrayList<>();
-        containers.add(new JavaClass.StringContainer());
-        List<String> strings = JavaClass.unwrap(containers);
+            List<JavaClass.StringContainer> containers = new ArrayList<>();
+            containers.add(new JavaClass.StringContainer());
+            List<String> strings = JavaClass.unwrap(containers);
         '''
     }
 
@@ -2276,18 +2297,73 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         assertScript '''
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 def ift = node.getNodeMetaData(INFERRED_TYPE)
-                assert ift == make(List)
-                assert ift.isUsingGenerics()
+                assert ift == LIST_TYPE
                 def gts = ift.genericsTypes
-                assert gts.length==1
+                assert gts != null
+                assert gts.length == 1
                 assert gts[0].type == STRING_TYPE
             })
             Iterable<String> list = (List) null
         '''
     }
 
+    @NotYetImplemented // GROOVY-5692, GROOVY-10006
     void testCompatibleArgumentsForPlaceholders1() {
         assertScript '''
+            def <T> T test(T one, T two) { }
+            def result = test(1,"II")
+        '''
+        assertScript '''
+            def <T> T test(T one, T two, T three) { }
+            def result = test(1,"II",Class)
+        '''
+        assertScript '''
+            def <T extends Number> T test(T one, T two) { }
+            def result = test(1L,2G)
+        '''
+    }
+
+    @NotYetImplemented // GROOVY-5692
+    void testCompatibleArgumentsForPlaceholders2() {
+        assertScript '''
+            def <T> boolean test(T one, List<T> many) { }
+            test(1,["II","III"])
+        '''
+    }
+
+    // GROOVY-10220
+    void testCompatibleArgumentsForPlaceholders3() {
+        assertScript '''
+            class C<S, T extends Number> {
+            }
+            class D<T> {
+                C<? extends T, Integer> f
+                D(C<? extends T, Integer> p) {
+                    f = p
+                }
+            }
+
+            assert new D<String>(null).f == null
+        '''
+    }
+
+    // GROOVY-10235
+    void testCompatibleArgumentsForPlaceholders4() {
+        assertScript '''
+            import static java.util.concurrent.ConcurrentHashMap.newKeySet
+
+            void accept(Collection<Integer> integers) {
+                assert integers
+            }
+
+            Set<Integer> integers = newKeySet()
+            integers.add(42)
+            accept(integers)
+        '''
+    }
+
+    void testCompatibleArgumentsForPlaceholders5() {
+        assertScript '''
             def <X> X foo(X x) {
             }
             def <Y> Y bar() {
@@ -2300,7 +2376,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     }
 
     // GROOVY-10482
-    void testCompatibleArgumentsForPlaceholders2() {
+    void testCompatibleArgumentsForPlaceholders6() {
         ['', 'def', 'public', 'static', '@Deprecated'].each {
             assertScript """
                 class Foo<X> {
@@ -2339,28 +2415,95 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         }
     }
 
-    void testIncompatibleGenericsForTwoArguments() {
-        shouldFailWithMessages '''
-            public <T> void printEqual(T arg1, T arg2) {
-                println arg1 == arg2
+    // GROOVY-10100
+    void testCompatibleArgumentsForPlaceholders8() {
+        assertScript '''
+            import java.util.function.Function
+
+            class C<T> {
+                T m(Object... args) {
+                }
+            }
+            def <T extends Number> void test() {
+                C<T> c = new C<>()
+                Function<String[], T> f = c::m
+                T t = f.apply(new String[]{"string"}) // Cannot assign value of type java.lang.String[] to variable of type T
             }
-            printEqual(1, 'foo')
+            test()
+        '''
+    }
+
+    // GROOVY-10115
+    void testCompatibleArgumentsForPlaceholders9() {
+        assertScript '''
+            class C<X, T extends X> {
+                T t
+                C(T t) {
+                    this.t = t
+                }
+            }
+            new C(null)
+        '''
+    }
+
+    @NotYetImplemented // GROOVY-10116
+    void testCompatibleArgumentsForPlaceholders10() {
+        assertScript '''
+            class Foo<X,T> {
+                Foo(Bar<X,T> bar) {
+                }
+            }
+            class Bar<X,T> {
+            }
+            class Baz<T> {
+                void test() {
+                    Foo<T,Long> x = new Foo<T,Long>(new Bar<T,Long>()) // Cannot call Foo#<init>(Bar<T,Long>) with arguments [Bar<T,Long>]
+                }
+            }
+            new Baz().test()
+        '''
+    }
+
+    void testIncompatibleArgumentsForPlaceholders1() {
+        shouldFailWithMessages '''
+            def <T extends Number> T test(T one, T two) { }
+            test(1,"II")
         ''',
-        '#printEqual(T, T) with arguments [int, java.lang.String]'
+        '#test(int, java.lang.String). Please check if the declared type is correct and if the method exists.'
     }
 
-    void testIncompatibleGenericsForTwoArgumentsUsingEmbeddedPlaceholder() {
+    @NotYetImplemented // GROOVY-7720
+    void testIncompatibleArgumentsForPlaceholders2() {
+        shouldFailWithMessages '''
+            class Consumer<T> {
+                <U> void accept(U param) {
+                    T local = param
+                }
+            }
+        ''',
+        'Cannot assign value of type U to variable of type T'
+
         shouldFailWithMessages '''
-            public <T> void printEqual(T arg1, List<T> arg2) {
-                println arg1 == arg2
+            class Converter<T, U> {
+                U convert(T param) {
+                    return param
+                }
+            }
+        ''',
+        'Cannot return value of type T for method returning U'
+
+        shouldFailWithMessages '''
+            class C<X, Y> {
+            }
+            def <X extends C<Number, String>> X[] m() {
+                new X[]{new C<Object, String>()}
             }
-            printEqual(1, ['foo'])
         ''',
-        '#printEqual(T, java.util.List <T>) with arguments [int, java.util.List <java.lang.String>]'
+        'Cannot convert from C<java.lang.Object, java.lang.String> to X'
     }
 
-    // GROOVY-9902
-    void testIncompatibleArgumentsForGenericArgument_IncludingDelegation() {
+    // GROOVY-9902: incomplete generics should not stop type checking
+    void testIncompatibleArgumentsForPlaceholders3() {
         shouldFailWithMessages '''
             class Holder<Unknown> {
                 TypedProperty<Number, Unknown> numberProperty = prop(Number)
@@ -2399,7 +2542,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         'Cannot call TypedProperty <Number, Unknown>#eq(java.lang.Number) with arguments [java.lang.String]'
     }
 
-    void testGroovy5748() {
+    // GROOVY-5748
+    void testPlaceholdersAndWildcards() {
         assertScript '''
             interface IStack<T> {
                 INonEmptyStack<T, ? extends IStack<T>> push(T x)
@@ -2455,7 +2599,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             assert twoIntegers.getTop() == 2
 
             def oneIntegerAgain = stack.push(1).push(2).pop()
-            assert oneIntegerAgain.getTop() == 1 // BOOM!!!!
+            assert oneIntegerAgain.getTop() == 1 // Cannot find matching method IStack#getTop()
         '''
     }
 
@@ -2472,14 +2616,14 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-5735
     void testCorrespondingParameterType() {
         assertScript '''
-        public <T> void someMethod (java.lang.Class<T> clazz, T object) {}
+            public <T> void someMethod (java.lang.Class<T> clazz, T object) {}
 
-        void method() {
-            List<String> list = null
-            someMethod(java.util.List.class, list)
-        }
+            void method() {
+                List<String> list = null
+                someMethod(java.util.List.class, list)
+            }
 
-        method()
+            method()
         '''
     }
 
@@ -2929,7 +3073,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
                 def cl = node.rightExpression.arguments[0]
                 assert cl instanceof ClosureExpression
                 def type = cl.getNodeMetaData(INFERRED_TYPE)
-                assert type == make(Closure)
+                assert type == CLOSURE_TYPE
                 assert type.isUsingGenerics()
                 assert type.genericsTypes
                 assert type.genericsTypes[0].type.name == 'CTypeTest'
@@ -3187,66 +3331,57 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-5839
     void testMethodShadowGenerics() {
         shouldFailWithMessages '''
-            public class GoodCodeRed<T> {
-                Collection<GoodCodeRed<T>> attached = []
-                public <T> void attach(GoodCodeRed<T> toAttach) {
-                    attached.add(toAttach)
-                }
-                static void foo() {
-                    def g1 = new GoodCodeRed<Long>()
-                    def g2 = new GoodCodeRed<Integer>()
-                    g1.attach(g2);
+            class C<T> {
+                Collection<C<T>> attached = []
+                def <T> void attach(C<T> toAttach) {
+                    attached.add(toAttach) // TODO: GROOVY-7719
                 }
             }
-            GoodCodeRed.foo()
-        ''', 'Cannot call <T> GoodCodeRed <Long>#attach(GoodCodeRed <Long>) with arguments [GoodCodeRed <Integer>]'
+            def c1 = new C<Short>()
+            def c2 = new C<Long>()
+            c1.attach(c2)
+        ''',
+        'Cannot call <T> C <Short>#attach(C <Short>) with arguments [C <Long>]'
     }
 
-    void testHiddenGenerics() {
-        // Groovy-6237
+    void testSuperClassGenerics() {
+        // GROOVY-6237
         assertScript '''
-            class MyList extends LinkedList<Object> {}
+            class MyList extends LinkedList<Object> {
+            }
             List<Object> o = new MyList()
         '''
 
         shouldFailWithMessages '''
-            class Blah {}
-            class MyList extends LinkedList<Object> {}
-            List<Blah> o = new MyList()
-        ''', 'Incompatible generic argument types. Cannot assign MyList to: java.util.List <Blah>'
+            class MyList extends LinkedList<Object> {
+            }
+            List<String> o = new MyList()
+        ''',
+        'Incompatible generic argument types. Cannot assign MyList to: java.util.List <String>'
 
-        // Groovy-5873
-        assertScript """
-            abstract class Parent<T> {
+        // GROOVY-5873
+        assertScript '''
+            abstract class A<T> {
                 public T value
             }
-            class Impl extends Parent<Integer> {}
-            Impl impl = new Impl()
-            Integer i = impl.value
-        """
+            class C extends A<Integer> {
+            }
+            C c = new C()
+            Integer i = c.value
+        '''
 
         // GROOVY-5920
-        assertScript """
+        assertScript '''
             class Data<T> {
-              T value
+                T value
             }
-
             class StringDataIterator implements Iterator<Data<String>> {
-              boolean hasNext() { true }
-              void    remove()  {}
-              Data<String> next() {
-                new Data<String>( value: 'tim' )
-              }
+                boolean hasNext() { true }
+                Data<String> next() { new Data<String>(value: 'tim') }
             }
-
-            class Runner {
-              static main( args ) {
-                Data<String> elem = new StringDataIterator().next()
-                assert elem.value.length() == 3
-              }
-            }
-            Runner.main(null);
-        """
+            Data<String> elem = new StringDataIterator().next()
+            assert elem.value.length() == 3
+        '''
     }
 
     void testReturnTypeInferenceRemovalWithGenerics() {
@@ -3346,7 +3481,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    //GROOVY-6723, GROOVY-6415
+    // GROOVY-6723, GROOVY-6415
     void testIndirectMethodLevelGenerics() {
         assertScript '''
             class C1<A> {
@@ -3355,6 +3490,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             }
             new C1().m1(null) // the call does not really matter
         '''
+
         assertScript '''
             class Test1 {
                 static <A, B> void pair1(A a, B b) {}
@@ -3514,7 +3650,8 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testGROOVY5981() {
+    // GROOVY-5981
+    void testCovariantAssignment() {
         assertScript '''
             import javax.swing.*
             import java.awt.*
@@ -3522,16 +3659,12 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             class ComponentFixture<T extends Component> {}
             class JButtonFixture extends ComponentFixture<JButton> {}
             class ContainerFixture<T extends Container> extends ComponentFixture<T> {}
-            abstract class ComponentAdapter<Fixture extends ComponentFixture> {
-                Fixture getFixture() {
-                    return fixture
-                }
-            }
+            abstract class ComponentAdapter<Fixture extends ComponentFixture> { Fixture getFixture() {} }
             abstract class ContainerAdapter<Fixture extends ContainerFixture> extends ComponentAdapter<Fixture> {}
 
             class ButtonComponent extends ComponentAdapter<JButtonFixture> {
-                void setFixtureResolver(final ContainerAdapter<? extends ContainerFixture> containerAdapter) {
-                    final ContainerFixture containerFixture = containerAdapter.getFixture()
+                void setFixtureResolver(ContainerAdapter<? extends ContainerFixture> containerAdapter) {
+                    ContainerFixture containerFixture = containerAdapter.getFixture() // Cannot assign value of type ComponentFixture to variable of type ContainerFixture
                 }
             }
 
@@ -3678,12 +3811,18 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     void testReturnTypeChecking() {
         shouldFailWithMessages '''
-            class Foo {
-                List<String> run() {
-                    [11, 12]
-                }
+            List<String> test() {
+                return [1,2,3]
             }
-        ''', 'Incompatible generic argument types. Cannot assign java.util.List <java.lang.Integer> to: java.util.List <String>'
+        ''',
+        'Cannot assign java.util.List <java.lang.Integer> to: java.util.List <String>'
+
+        shouldFailWithMessages '''
+            List<CharSequence> test() {
+                return [1,2,3]
+            }
+        ''',
+        'Cannot assign java.util.List <java.lang.Integer> to: java.util.List <CharSequence>'
     }
 
     void testBoundedReturnTypeChecking() {
@@ -3739,7 +3878,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
             class Foo<T extends Bar> {
                 T method(T t) {
                     def c = { -> t }
-                    return c() // Cannot return value of type Object on method returning type T
+                    return c() // Cannot return value of type Object for method returning T
                 }
             }
             def bar = new Bar()
@@ -3747,7 +3886,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    // GROOVY-9981
+    // GROOVY-9891
     void testBoundedReturnTypeChecking3() {
         assertScript '''
             class Pogo {
@@ -3887,11 +4026,9 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     // GROOVY-7804
     void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
         assertScript '''
-            interface Supplier<T> {
-                public <T> T get()
-            }
+            interface Supplier<T> { def <T> T get() }
 
-            static <T> T doGet(Supplier<T> supplier) { supplier.get() }
+            def <T> T doGet(Supplier<T> supplier) { supplier.get() }
 
             assert doGet { -> 'foo' } == 'foo'
         '''
@@ -3909,6 +4046,20 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10528
+    void testRawTypeGuard() {
+        assertScript '''
+            void test(... args) {
+                args.each { object ->
+                    if (object instanceof Iterable) {
+                        object.each { test(it) }
+                    }
+                }
+            }
+            test(1,[2,3])
+        '''
+    }
+
     //--------------------------------------------------------------------------
 
     static class MyList
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 202ab7d..f01c511 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -32,70 +32,43 @@ final class LambdaTest {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
-            import java.util.stream.Stream
 
             @CompileStatic
-            public class Test1 {
-                public static void main(String[] args) {
-                    p();
-                }
-
-                public static void p() {
-                    assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 1).collect(Collectors.toList());
-                }
+            def f() {
+                [1, 2, 3].stream().map(e -> e + 1).collect(Collectors.toList())
             }
-        '''
-    }
-
-    @Test
-    void testFunction2() {
-        assertScript '''
-            import groovy.transform.CompileStatic
-            import java.util.stream.Collectors
-            import java.util.stream.Stream
-
-            public class Test1 {
-                public static void main(String[] args) {
-                    p();
-                }
 
-                @CompileStatic
-                public static void p() {
-                    assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 1).collect(Collectors.toList());
-                }
-            }
+            assert f() == [2, 3, 4]
         '''
     }
 
     @Test
-    void testFunctionScript() {
+    void testFunction2() {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
-            import java.util.stream.Stream
 
             @CompileStatic
-            void p() {
-                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e + 1).collect(Collectors.toList());
+            def f() {
+                [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
             }
 
-            p()
+            assert f() == [2, 3, 4]
         '''
     }
 
     @Test
-    void testFunctionScript2() {
+    void testFunctionWithTypeArgument() {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
-            import java.util.stream.Stream
 
             @CompileStatic
-            void p() {
-                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 1).collect(Collectors.toList());
+            List<String> f() {
+                [1, 2, 3].stream().<String>map(i -> null).collect(Collectors.toList())
             }
 
-            p()
+            assert f() == [null, null, null]
         '''
     }
 
@@ -103,94 +76,57 @@ final class LambdaTest {
     void testBinaryOperator() {
         assertScript '''
             import groovy.transform.CompileStatic
-            import java.util.stream.Collectors
-            import java.util.stream.Stream
 
             @CompileStatic
-            public class Test1 {
-                public static void main(String[] args) {
-                    p();
-                }
-
-                public static void p() {
-                    assert 13 == [1, 2, 3].stream().reduce(7, (Integer r, Integer e) -> r + e);
-                }
+            int f() {
+                [1, 2, 3].stream().reduce(7, (Integer r, Integer e) -> r + e)
             }
+
+            assert f() == 13
         '''
     }
 
-    @Test // GROOVY-8917: Failed to infer parameter type of some SAM, e.g. BinaryOperator
-    void testBinaryOperatorWithoutExplicitTypeDef() {
+    @Test // GROOVY-8917
+    void testBinaryOperatorWithoutExplicitTypes() {
         assertScript '''
             import groovy.transform.CompileStatic
-            import java.util.stream.Collectors
-            import java.util.stream.Stream
 
             @CompileStatic
-            public class Test1 {
-                public static void main(String[] args) {
-                    p();
-                }
-
-                public static void p() {
-                    assert 13 == [1, 2, 3].stream().reduce(7, (r, e) -> r + e);
-                }
+            int f() {
+                [1, 2, 3].stream().reduce(7, (r, e) -> r + e)
             }
+
+            assert f() == 13
         '''
     }
 
     @Test
-    void testBinaryOperatorWithoutExplicitTypeDef2() {
+    void testBinaryOperatorWithoutExplicitTypes2() {
         assertScript '''
             import groovy.transform.CompileStatic
-            import java.util.stream.Collectors
-            import java.util.stream.Stream
             import java.util.function.BinaryOperator
 
             @CompileStatic
-            public class Test1 {
-                public static void main(String[] args) {
-                    p();
-                }
-
-                public static void p() {
-                    BinaryOperator<Integer> accumulator = (r, e) -> r + e
-                    assert 13 == [1, 2, 3].stream().reduce(7, accumulator);
-                }
+            int f() {
+                BinaryOperator<Integer> accumulator = (r, e) -> r + e
+                return [1, 2, 3].stream().reduce(7, accumulator)
             }
-        '''
-    }
-
-    @Test
-    void testConsumer() {
-        assertScript '''
-            @groovy.transform.CompileStatic
-            class Test1 {
-                static main(args) {
-                    p()
-                }
 
-                static void p() {
-                    [1, 2, 3].stream().forEach(e -> { System.out.println(e + 1); })
-                }
-            }
+            assert f() == 13
         '''
     }
 
-    @Test // GROOVY-9340
-    void testConsumerWithSelfType() {
+    @Test // GROOVY-10282
+    void testBiFunctionAndBinaryOperatorWithSharedTypeParameter() {
         assertScript '''
-            @groovy.transform.CompileStatic
-            class Test1 {
-                static main(args) {
-                    p()
-                }
+            import groovy.transform.CompileStatic
+            import java.util.stream.IntStream
 
-                static void p() {
-                    java.util.function.Consumer<Test1> c = t -> null
-                    c.accept(this.newInstance())
-                }
+            @CompileStatic
+            def f() {
+                IntStream.range(0, 10).boxed().reduce('', (s, i) -> s + '-', String::concat)
             }
+            assert f() == '----------'
         '''
     }
 
@@ -294,7 +230,7 @@ final class LambdaTest {
     }
 
     @Test
-    void testComparator1() {
+    void testComparator() {
         assertScript '''
             @groovy.transform.CompileStatic class T {
                 Comparator<Integer> c = (Integer a, Integer b) -> Integer.compare(a, b)
@@ -302,26 +238,29 @@ final class LambdaTest {
             def t = new T()
             assert t.c.compare(0,0) == 0
         '''
+    }
 
+    @Test // GROOVY-10372
+    void testComparator2() {
         def err = shouldFail '''
             @groovy.transform.CompileStatic class T {
-                Comparator<Integer> c = (int a, int b) -> Integer.compare(a, b)
+                Comparator<Integer> c = (int a, String b) -> 42
             }
         '''
-        assert err =~ /Cannot assign java.util.Comparator <int> to: java.util.Comparator <Integer>/
+        assert err =~ /Cannot assign java.util.Comparator <java.lang.String> to: java.util.Comparator <Integer>/
     }
 
     @Test // GROOVY-9977
-    void testComparator2() {
+    void testComparator3() {
         assertScript '''
             @groovy.transform.CompileStatic
             class T {
                 Comparator<Integer> c = (a, b) -> Integer.compare(a, b)
 
-                static void m1() {
+                void m1() {
                     Comparator<Integer> x = (a, b) -> Integer.compare(a, b)
                 }
-                void m2() {
+                static void m2() {
                     Comparator<Integer> y = (a, b) -> Integer.compare(a, b)
                 }
             }
@@ -331,7 +270,7 @@ final class LambdaTest {
     }
 
     @Test // GROOVY-9997
-    void testComparator3() {
+    void testComparator4() {
         assertScript '''
             @groovy.transform.TypeChecked
             void test() {
@@ -388,7 +327,8 @@ final class LambdaTest {
         '''
     }
 
-    void testFunctionWithLocalVariables4() {
+    @Test
+    void testFunctionWithLocalVariables3() {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
@@ -410,7 +350,7 @@ final class LambdaTest {
     }
 
     @Test
-    void testFunctionWithLocalVariables5() {
+    void testFunctionWithLocalVariables4() {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
@@ -434,7 +374,7 @@ final class LambdaTest {
     }
 
     @Test
-    void testFunctionWithLocalVariables6() {
+    void testFunctionWithLocalVariables5() {
         assertScript '''
             import groovy.transform.CompileStatic
             import java.util.stream.Collectors
@@ -807,6 +747,58 @@ final class LambdaTest {
         '''
     }
 
+    @Test // GROOVY-9340
+    void testConsumer8() {
+        assertScript '''
+            @groovy.transform.CompileStatic
+            class Test1 {
+                static main(args) {
+                    p()
+                }
+
+                static void p() {
+                    java.util.function.Consumer<Test1> c = t -> null
+                    c.accept(this.newInstance())
+                }
+            }
+        '''
+    }
+
+    @Test
+    void testConsumer9() {
+        assertScript '''
+            @groovy.transform.CompileStatic
+            class Test1 {
+                static main(args) {
+                    p()
+                }
+
+                static void p() {
+                    [1, 2, 3].stream().forEach(e -> { System.out.println(e + 1); })
+                }
+            }
+        '''
+    }
+
+    @Test // GROOVY-10056
+    void testConsumer10() {
+        ['CompileStatic', 'TypeChecked'].each { xform ->
+            assertScript """
+                @groovy.transform.${xform}
+                void test() {
+                    String[][] arrayArray = new String[][] {
+                        new String[] {'a','b','c'},
+                        new String[] {'d','e','f'}
+                    }
+                    Arrays.stream(arrayArray).limit(1).forEach(array -> {
+                        assert Arrays.asList(array) == ['a','b','c']
+                    })
+                }
+                test()
+            """
+        }
+    }
+
     @Test
     void testFunctionalInterface1() {
         assertScript '''
@@ -973,7 +965,7 @@ final class LambdaTest {
                     Function<Integer, String> f = (Integer e) -> 'a' + e
                     assert ['a1', 'a2', 'a3'] == [1, 2, 3].stream().map(f).collect(Collectors.toList())
 
-                    assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 1).collect(Collectors.toList());
+                    assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList());
                 }
             }
         '''
@@ -1068,7 +1060,7 @@ final class LambdaTest {
             @groovy.transform.CompileStatic
             void p() {
                 assert ['1', '2', '3'] == [1, 2, 3].stream().map(Object::toString).collect(Collectors.toList())
-                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 1).collect(Collectors.toList())
+                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus(1)).collect(Collectors.toList())
                 assert ['1', '2', '3'] == [1, 2, 3].stream().map(Object::toString).collect(Collectors.toList())
             }
 
@@ -1232,23 +1224,21 @@ final class LambdaTest {
     @Test
     void testSerialize1() {
         assertScript '''
-            import java.util.function.Function
-
-            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+            }
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                def p() {
-                    def out = new ByteArrayOutputStream()
+            byte[] test() {
+                try (def out = new ByteArrayOutputStream()) {
                     out.withObjectOutputStream {
-                        SerializableFunction<Integer, String> f = ((Integer e) -> 'a' + e)
+                        SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
                         it.writeObject(f)
                     }
-                    return out.toByteArray()
+                    out.toByteArray()
                 }
             }
 
-            assert new Test1().p().length > 0
+            assert test().length > 0
         '''
     }
 
@@ -1258,18 +1248,17 @@ final class LambdaTest {
             import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                def p() {
-                    def out = new ByteArrayOutputStream()
+            byte[] test() {
+                try (def out = new ByteArrayOutputStream()) {
                     out.withObjectOutputStream {
-                        Function<Integer, String> f = ((Integer e) -> 'a' + e)
+                        Function<Integer, String> f = ((Integer i) -> 'a' + i)
                         it.writeObject(f)
                     }
-                    return out.toByteArray()
+                    out.toByteArray()
                 }
             }
 
-            new Test1().p()
+            test()
         '''
 
         assert err.message.contains('$Lambda$')
@@ -1279,415 +1268,403 @@ final class LambdaTest {
     void testDeserialize1() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                byte[] p() {
+            class C {
+                byte[] test() {
                     def out = new ByteArrayOutputStream()
-                    out.withObjectOutputStream {
-                        SerializableFunction<Integer, String> f = ((Integer e) -> 'a' + e)
+                    out.withObjectOutputStream { it ->
+                        SerializableFunction<Integer, String> f = (Integer i) -> 'a' + i
                         it.writeObject(f)
                     }
-                    return out.toByteArray()
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize1_InitializeBlock() {
+    void testDeserialize2() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 implements Serializable {
-                private static final long serialVersionUID = -1L;
-                String a = 'a'
+            class C implements Serializable {
+                private static final long serialVersionUID = -1L
+                String s = 'a'
                 SerializableFunction<Integer, String> f
 
                 {
-                    f = ((Integer e) -> a + e)
+                    f = (Integer i) -> s + i
                 }
 
-                byte[] p() {
+                byte[] test() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
                         it.writeObject(f)
                     }
-
-                    return out.toByteArray()
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize1_InitializeBlockShouldFail() {
+    void testDeserialize3() {
         def err = shouldFail NotSerializableException, '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                String a = 'a'
+            class C {
+                String s = 'a'
                 SerializableFunction<Integer, String> f
 
                 {
-                    f = ((Integer e) -> a + e)
+                    f = (Integer i) -> s + i
                 }
 
-                byte[] p() {
+                byte[] test() {
                     def out = new ByteArrayOutputStream()
                     out.withObjectOutputStream {
                         it.writeObject(f)
                     }
-
-                    return out.toByteArray()
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new Test1().p()
+                static main(args) {
+                    this.newInstance().test()
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
-
-        assert err.message.contains('tests.lambda.Test1')
+        assert err.message.contains('tests.lambda.C')
     }
 
     @Test
-    void testDeserialize2() {
+    void testDeserialize4() {
         assertScript '''
-            import java.util.function.Function
-
             @groovy.transform.CompileStatic
-            class Test1 {
-                static byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        out.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> 'a' + e)
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                static byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    out.withObjectOutputStream { it ->
+                        SerializableFunction<Integer, String> f = (Integer i) -> 'a' + i
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(Test1.p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize3() {
+    void testDeserialize5() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        out.withObjectOutputStream {
-                            String c = 'a'
-                            SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    out.withObjectOutputStream {
+                        String s = 'a'
+                        SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize4() {
+    void testDeserialize6() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        String c = 'a'
-                        SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    String s = 'a'
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize5() {
+    void testDeserialize7() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                static byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        String c = 'a'
-                        SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                static byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    String s = 'a'
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(Test1.p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize6_InstanceFields() {
+    void testDeserialize8() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 implements Serializable {
+            class C implements Serializable {
                 private static final long serialVersionUID = -1L;
-                private String c = 'a'
+                private String s = 'a'
 
-                byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+                byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize6_InstanceFieldsShouldFail() {
+    void testDeserialize9() {
         def err = shouldFail NotSerializableException, '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                private String c = 'a'
-
-                byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
+            class C {
+                private String s = 'a'
 
-                        return out.toByteArray()
+                byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
 
-        assert err.message.contains('tests.lambda.Test1')
+        assert err.message.contains('tests.lambda.C')
     }
 
     @Test
-    void testDeserialize6_InstanceMethods() {
+    void testDeserialize10() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 implements Serializable {
+            class C implements Serializable {
                 private static final long serialVersionUID = -1L;
-                private String c() { 'a' }
+                private String getS() { 'a' }
 
-                byte[] p() {
+                byte[] test() {
                     def out = new ByteArrayOutputStream()
-                    SerializableFunction<Integer, String> f = (Integer i) -> c() + i
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
                     out.withObjectOutputStream {
                         it.writeObject(f)
                     }
                     out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize6_InstanceMethodsShouldFail() {
+    void testDeserialize11() {
         def err = shouldFail NotSerializableException, '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                private String c() { 'a' }
+            class C {
+                private String getS() { 'a' }
 
-                byte[] p() {
+                byte[] test() {
                     def out = new ByteArrayOutputStream()
-                    SerializableFunction<Integer, String> f = (Integer i) -> c() + i
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
                     out.withObjectOutputStream {
                         it.writeObject(f)
                     }
                     out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(new Test1().p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.newInstance().test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
 
-        assert err.message.contains('tests.lambda.Test1')
+        assert err.message.contains('tests.lambda.C')
     }
 
     @Test
-    void testDeserialize7_StaticFields() {
+    void testDeserialize12() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                private static final String c = 'a'
-                static byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f = (Integer e) -> c + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                private static final String s = 'a'
+                static byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(Test1.p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
 
     @Test
-    void testDeserialize7_StaticMethods() {
+    void testDeserialize13() {
         assertScript '''
             package tests.lambda
-            import java.util.function.Function
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                private static String c() { 'a' }
-                static byte[] p() {
-                        def out = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f = (Integer e) -> c() + e
-                        out.withObjectOutputStream {
-                            it.writeObject(f)
-                        }
-
-                        return out.toByteArray()
+            class C {
+                private static String getS() { 'a' }
+                static byte[] test() {
+                    def out = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f = (Integer i) -> s + i
+                    out.withObjectOutputStream {
+                        it.writeObject(f)
+                    }
+                    out.toByteArray()
                 }
 
-                static void main(String[] args) {
-                    new ByteArrayInputStream(Test1.p()).withObjectInputStream(Test1.class.classLoader) {
+                static main(args) {
+                    new ByteArrayInputStream(this.test()).withObjectInputStream(this.classLoader) {
                         SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                        assert 'a1' == f.apply(1)
+                        assert f.apply(1) == 'a1'
                     }
                 }
 
-                interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+                interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+                }
             }
         '''
     }
@@ -1695,56 +1672,53 @@ final class LambdaTest {
     @Test
     void testDeserializeNestedLambda1() {
         assertScript '''
-            import java.util.function.Function
-
-            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+            }
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                def p() {
-                        def out1 = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f1 = (Integer e) -> 'a' + e
-                        out1.withObjectOutputStream {
-                            it.writeObject(f1)
-                        }
-                        def result1 = out1.toByteArray()
+            class C {
+                def test() {
+                    def out1 = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f1 = (Integer i) -> 'a' + i
+                    out1.withObjectOutputStream {
+                        it.writeObject(f1)
+                    }
 
-                        def out2 = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f2 = (Integer e) -> 'b' + e
-                        out2.withObjectOutputStream {
-                            it.writeObject(f2)
-                        }
-                        def result2 = out2.toByteArray()
+                    def out2 = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f2 = (Integer i) -> 'b' + i
+                    out2.withObjectOutputStream {
+                        it.writeObject(f2)
+                    }
 
-                        // nested lambda expression
-                        def out3 = new ByteArrayOutputStream()
-                        SerializableFunction<Integer, String> f3 = (Integer e) -> {
-                            SerializableFunction<Integer, String> nf = ((Integer ne) -> 'n' + ne)
-                            'c' + nf(e)
-                        }
-                        out3.withObjectOutputStream {
-                            it.writeObject(f3)
-                        }
-                        def result3 = out3.toByteArray()
+                    // nested lambda expression
+                    def out3 = new ByteArrayOutputStream()
+                    SerializableFunction<Integer, String> f3 = (Integer i) -> {
+                        SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
+                        nf(i) + 'c'
+                    }
+                    out3.withObjectOutputStream {
+                        it.writeObject(f3)
+                    }
 
-                        return [result1, result2, result3]
+                    [out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
                 }
             }
 
-            def (byte[] serializedLambdaBytes1, byte[] serializedLambdaBytes2, byte[] serializedLambdaBytes3) = new Test1().p()
-            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(Test1.class.classLoader) {
+            def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = new C().test()
+
+            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'a1' == f.apply(1)
+                assert f.apply(1) == 'a1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'b1' == f.apply(1)
+                assert f.apply(1) == 'b1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'cn1' == f.apply(1)
+                assert f.apply(1) == 'c1c'
             }
         '''
     }
@@ -1752,56 +1726,53 @@ final class LambdaTest {
     @Test
     void testDeserializeNestedLambda2() {
         assertScript '''
-            import java.util.function.Function
-
-            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+            }
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                def p() {
-                        def out1 = new ByteArrayOutputStream()
-                        out1.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> 'a' + e)
-                            it.writeObject(f)
-                        }
-                        def result1 = out1.toByteArray()
+            class C {
+                def test() {
+                    def out1 = new ByteArrayOutputStream()
+                    out1.withObjectOutputStream {
+                        SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
+                        it.writeObject(f)
+                    }
 
-                        def out2 = new ByteArrayOutputStream()
-                        out2.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> 'b' + e)
-                            it.writeObject(f)
-                        }
-                        def result2 = out2.toByteArray()
-
-                        // nested lambda expression
-                        def out3 = new ByteArrayOutputStream()
-                        out3.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> {
-                                SerializableFunction<Integer, String> nf = ((Integer ne) -> 'n' + ne)
-                                'c' + nf(e)
-                            })
-                            it.writeObject(f)
+                    def out2 = new ByteArrayOutputStream()
+                    out2.withObjectOutputStream {
+                        SerializableFunction<Integer, String> f = ((Integer i) -> 'b' + i)
+                        it.writeObject(f)
+                    }
+
+                    // nested lambda expression
+                    def out3 = new ByteArrayOutputStream()
+                    out3.withObjectOutputStream { it ->
+                        SerializableFunction<Integer, String> f = (Integer i) -> {
+                            SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
+                            nf(i) + 'c'
                         }
-                        def result3 = out3.toByteArray()
+                        it.writeObject(f)
+                    }
 
-                        return [result1, result2, result3]
+                    [out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
                 }
             }
 
-            def (byte[] serializedLambdaBytes1, byte[] serializedLambdaBytes2, byte[] serializedLambdaBytes3) = new Test1().p()
-            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(Test1.class.classLoader) {
+            def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = new C().test()
+
+            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'a1' == f.apply(1)
+                assert f.apply(1) == 'a1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'b1' == f.apply(1)
+                assert f.apply(1) == 'b1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'cn1' == f.apply(1)
+                assert f.apply(1) == 'c1c'
             }
         '''
     }
@@ -1809,56 +1780,53 @@ final class LambdaTest {
     @Test
     void testDeserializeNestedLambda3() {
         assertScript '''
-            import java.util.function.Function
-
-            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+            }
 
             @groovy.transform.CompileStatic
-            class Test1 {
-                static p() {
-                        def out1 = new ByteArrayOutputStream()
-                        out1.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> 'a' + e)
-                            it.writeObject(f)
-                        }
-                        def result1 = out1.toByteArray()
+            class C {
+                static test() {
+                    def out1 = new ByteArrayOutputStream()
+                    out1.withObjectOutputStream {
+                        SerializableFunction<Integer, String> f = ((Integer i) -> 'a' + i)
+                        it.writeObject(f)
+                    }
 
-                        def out2 = new ByteArrayOutputStream()
-                        out2.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> 'b' + e)
-                            it.writeObject(f)
-                        }
-                        def result2 = out2.toByteArray()
-
-                        // nested lambda expression
-                        def out3 = new ByteArrayOutputStream()
-                        out3.withObjectOutputStream {
-                            SerializableFunction<Integer, String> f = ((Integer e) -> {
-                                SerializableFunction<Integer, String> nf = ((Integer ne) -> 'n' + ne)
-                                'c' + nf(e)
-                            })
-                            it.writeObject(f)
+                    def out2 = new ByteArrayOutputStream()
+                    out2.withObjectOutputStream {
+                        SerializableFunction<Integer, String> f = ((Integer i) -> 'b' + i)
+                        it.writeObject(f)
+                    }
+
+                    // nested lambda expression
+                    def out3 = new ByteArrayOutputStream()
+                    out3.withObjectOutputStream { it ->
+                        SerializableFunction<Integer, String> f = (Integer i) -> {
+                            SerializableFunction<Integer, String> nf = (Integer j) -> 'c' + j
+                            nf(i) + 'c'
                         }
-                        def result3 = out3.toByteArray()
+                        it.writeObject(f)
+                    }
 
-                        return [result1, result2, result3]
+                    [out1.toByteArray(), out2.toByteArray(), out3.toByteArray()]
                 }
             }
 
-            def (byte[] serializedLambdaBytes1, byte[] serializedLambdaBytes2, byte[] serializedLambdaBytes3) = Test1.p()
-            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(Test1.class.classLoader) {
+            def (serializedLambdaBytes1, serializedLambdaBytes2, serializedLambdaBytes3) = C.test()
+
+            new ByteArrayInputStream(serializedLambdaBytes1).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'a1' == f.apply(1)
+                assert f.apply(1) == 'a1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes2).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'b1' == f.apply(1)
+                assert f.apply(1) == 'b1'
             }
 
-            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(Test1.class.classLoader) {
+            new ByteArrayInputStream(serializedLambdaBytes3).withObjectInputStream(this.class.classLoader) {
                 SerializableFunction<Integer, String> f = (SerializableFunction<Integer, String>) it.readObject()
-                assert 'cn1' == f.apply(1)
+                assert f.apply(1) == 'c1c'
             }
         '''
     }
@@ -1866,9 +1834,8 @@ final class LambdaTest {
     @Test
     void testDeserializeNestedLambda4() {
         assertScript '''
-            import java.util.function.Function
-
-            interface SerializableFunction<T, R> extends Function<T, R>, Serializable {}
+            interface SerializableFunction<I,O> extends Serializable, java.util.function.Function<I,O> {
+            }
 
             @groovy.transform.CompileStatic
             class C {