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 2021/11/17 16:03:35 UTC

[groovy] branch master updated: GROOVY-10372: STC: check param types for functional interface conversion

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

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


The following commit(s) were added to refs/heads/master by this push:
     new fdb2fc5  GROOVY-10372: STC: check param types for functional interface conversion
fdb2fc5 is described below

commit fdb2fc5089ed2c1ae6b000082dfea41d86d77577
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Nov 17 09:16:19 2021 -0600

    GROOVY-10372: STC: check param types for functional interface conversion
---
 .../transform/stc/StaticTypeCheckingVisitor.java   |  56 +--
 src/test/groovy/bugs/Groovy9790.groovy             |   3 +-
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    | 397 +++++++++------------
 src/test/groovy/transform/stc/LambdaTest.groovy    |  28 +-
 .../transform/stc/TypeInferenceSTCTest.groovy      |   5 +-
 .../asm/sc/StaticCompilationTestSupport.groovy     |   1 +
 .../stc/StaticTypeCheckingTestCase.groovy          |  16 +-
 7 files changed, 239 insertions(+), 267 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 1743b31..cab64fe 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -965,16 +965,22 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 if (parameter.isDynamicTyped()) {
                     parameter.setType(samParameterTypes[i]);
                     parameter.setOriginType(samParameterTypes[i]);
+                } else {
+                    checkParamType(parameter, samParameterTypes[i], i == n-1, rhsExpression instanceof LambdaExpression);
                 }
             }
         } else {
-            String descriptor = toMethodParametersString(findSAM(lhsType).getName(), samParameterTypes);
-            addStaticTypeError("Wrong number of parameters for method target " + descriptor, rhsExpression);
+            addStaticTypeError("Wrong number of parameters for method target " + toMethodParametersString(findSAM(lhsType).getName(), samParameterTypes), rhsExpression);
         }
 
         storeInferredReturnType(rhsExpression, typeInfo.getV2());
     }
 
+    private void checkParamType(final Parameter source, final ClassNode target, final boolean isLast, final boolean lambda) {
+        if (/*lambda ? !source.getOriginType().equals(target) :*/!typeCheckMethodArgumentWithGenerics(source.getOriginType(), target, isLast))
+            addStaticTypeError("Expected type " + prettyPrintType(target) + " for " + (lambda ? "lambda" : "closure") + " parameter: " + source.getName(), source);
+    }
+
     /**
      * Given a binary expression corresponding to an assignment, will check that
      * the type of the RHS matches one of the possible setters and if not, throw
@@ -2954,10 +2960,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 } else if ((n = p.length) == 0) {
                     // implicit parameter(s)
                     paramTypes = samParamTypes;
-                } else {
-                    paramTypes = new ClassNode[n];
-                    for (int i = 0; i < n; i += 1) {
-                        paramTypes[i] = i < samParamTypes.length ? samParamTypes[i] : null;
+                } else { // TODO: error for length mismatch
+                    paramTypes = Arrays.copyOf(samParamTypes, n);
+                    for (int i = 0; i < Math.min(n, samParamTypes.length); i += 1) {
+                        checkParamType(p[i], paramTypes[i], i == n-1, expression instanceof LambdaExpression);
                     }
                 }
                 expression.putNodeMetaData(CLOSURE_ARGUMENTS, paramTypes);
@@ -3030,25 +3036,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
         }
         if (candidates.size() > 1) {
-            Iterator<ClassNode[]> candIt = candidates.iterator();
-            while (candIt.hasNext()) {
+            for (Iterator<ClassNode[]> candIt = candidates.iterator(); candIt.hasNext(); ) {
                 ClassNode[] inferred = candIt.next();
                 for (int i = 0, n = closureParams.length; i < n; i += 1) {
                     Parameter closureParam = closureParams[i];
-                    ClassNode originType = closureParam.getOriginType();
+                    ClassNode declaredType = closureParam.getOriginType();
                     ClassNode inferredType;
-                    if (i < inferred.length - 1 || inferred.length == closureParams.length) {
+                    if (i < inferred.length - 1 || inferred.length == n) {
                         inferredType = inferred[i];
-                    } else { // vargs?
-                        ClassNode lastArgInferred = inferred[inferred.length - 1];
-                        if (lastArgInferred.isArray()) {
-                            inferredType = lastArgInferred.getComponentType();
+                    } else {
+                        ClassNode lastInferred = inferred[inferred.length - 1];
+                        if (lastInferred.isArray()) {
+                            inferredType = lastInferred.getComponentType();
                         } else {
                             candIt.remove();
                             continue;
                         }
                     }
-                    if (!typeCheckMethodArgumentWithGenerics(originType, inferredType, i == (n - 1))) {
+                    if (!typeCheckMethodArgumentWithGenerics(declaredType, inferredType, i == (n - 1))) {
                         candIt.remove();
                     }
                 }
@@ -3067,24 +3072,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             } else {
                 for (int i = 0, n = closureParams.length; i < n; i += 1) {
                     Parameter closureParam = closureParams[i];
-                    ClassNode originType = closureParam.getOriginType();
+                    ClassNode declaredType = closureParam.getOriginType();
                     ClassNode inferredType = OBJECT_TYPE;
-                    if (i < inferred.length - 1 || inferred.length == closureParams.length) {
+                    if (i < inferred.length - 1 || inferred.length == n) {
                         inferredType = inferred[i];
-                    } else { // vargs?
-                        ClassNode lastArgInferred = inferred[inferred.length - 1];
-                        if (lastArgInferred.isArray()) {
-                            inferredType = lastArgInferred.getComponentType();
+                    } else {
+                        ClassNode lastInferred = inferred[inferred.length - 1];
+                        if (lastInferred.isArray()) {
+                            inferredType = lastInferred.getComponentType();
                         } else {
-                            addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + closureParams.length, expression);
+                            addError("Incorrect number of parameters. Expected " + inferred.length + " but found " + n, expression);
                         }
                     }
-                    boolean lastArg = i == (n - 1);
-
-                    if (!typeCheckMethodArgumentWithGenerics(originType, inferredType, lastArg)) {
-                        addError("Expected parameter of type " + prettyPrintType(inferredType) + " but got " + prettyPrintType(originType), closureParam.getType());
-                    }
-
+                    checkParamType(closureParam, inferredType, i == n-1, false);
                     typeCheckingContext.controlStructureVariables.put(closureParam, inferredType);
                 }
             }
diff --git a/src/test/groovy/bugs/Groovy9790.groovy b/src/test/groovy/bugs/Groovy9790.groovy
index ca04ddd..61fa822 100644
--- a/src/test/groovy/bugs/Groovy9790.groovy
+++ b/src/test/groovy/bugs/Groovy9790.groovy
@@ -81,7 +81,6 @@ final class Groovy9790 {
 
             test()
         '''
-
-        assert err.toString().contains('The inferred type[int] is not compatible with the parameter type[java.lang.String]')
+        assert err =~ /Expected type int for lambda parameter: s/
     }
 }
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 5cb1930..bf2e779 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -29,7 +29,8 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
         shouldFailWithMessages '''
             ['a','b'].collect { Date it -> it.toUpperCase() }
-        ''', 'Expected parameter of type java.lang.String but got java.util.Date'
+        ''',
+        'Expected type java.lang.String for closure parameter: it'
     }
 
     void testInferenceForDGM_collectUsingImplicitIt() {
@@ -228,193 +229,169 @@ assert result == ['b', 'r', 'e', 'a', 'd', 'b', 'u', 't', 't', 'e', 'r']
     }
 
     void testInferenceOnNonExtensionMethod() {
-        assertScript '''import groovy.transform.stc.ClosureParams
-            import groovy.transform.stc.FirstParam
-            public <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) }
+        assertScript '''import groovy.transform.stc.FirstParam
+            def <T> T foo(T arg, @ClosureParams(FirstParam) Closure c) { c.call(arg) }
             assert foo('a') { it.toUpperCase() } == 'A'
-'''
+        '''
     }
 
     void testFromStringWithSimpleType() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
-foo { String str -> println str.toUpperCase()}
-'''
+            void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
+            foo { String str -> println str.toUpperCase()}
+        '''
 
         shouldFailWithMessages '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
-foo { Date str -> println str}
-''', 'Expected parameter of type java.lang.String but got java.util.Date'
+            void foo(@ClosureParams(value=FromString,options="java.lang.String") Closure cl) { cl.call('foo') }
+            foo { Date str -> println str}
+        ''',
+        'Expected type java.lang.String for closure parameter: str'
     }
 
     void testFromStringWithGenericType() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
-foo { List<String> str -> str.each { println it.toUpperCase() } }
-'''
+            void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
+            foo { List<String> str -> str.each { println it.toUpperCase() } }
+        '''
 
         shouldFailWithMessages '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
-foo { List<Date> d -> d.each { println it } }
-''', 'Expected parameter of type java.util.List<java.lang.String> but got java.util.List<java.util.Date>'
+            void foo(@ClosureParams(value=FromString,options="java.util.List<java.lang.String>") Closure cl) { cl.call(['foo']) }
+            foo { List<Date> d -> d.each { println it } }
+        ''',
+        'Expected type java.util.List<java.lang.String> for closure parameter: d'
     }
 
     void testFromStringWithDirectGenericPlaceholder() {
-
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-public <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) }
-foo('hey') { println it.toUpperCase() }
-'''
-
+            def <T> void foo(T t, @ClosureParams(value=FromString,options="T") Closure cl) { cl.call(t) }
+            foo('hey') { println it.toUpperCase() }
+        '''
     }
 
     void testFromStringWithGenericPlaceholder() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-public <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) }
-foo('hey') { List<String> str -> str.each { println it.toUpperCase() } }
-'''
-
+            def <T> void foo(T t, @ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call([t,t]) }
+            foo('hey') { List<String> str -> str.each { println it.toUpperCase() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClass() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo<T> {
-        public void foo(@ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call(['hey','ya']) }
-    }
-    def foo = new Foo<String>()
-
-    foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
-'''
+            class Foo<T> {
+                void foo(@ClosureParams(value=FromString,options="java.util.List<T>") Closure cl) { cl.call(['hey','ya']) }
+            }
+            def foo = new Foo<String>()
+            foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenerics() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo<T,U> {
-        public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
-    }
-    def foo = new Foo<Integer,String>()
-
-    foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
-'''
+            class Foo<T,U> {
+                void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
+            }
+            def foo = new Foo<Integer,String>()
+            foo.foo { List<String> str -> str.each { println it.toUpperCase() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignature() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo<T,U> {
-        public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
-    }
-    def foo = new Foo<Integer,String>()
-
-    foo.foo { it.each { println it.toUpperCase() } }
-'''
+            class Foo<T,U> {
+                public void foo(@ClosureParams(value=FromString,options="java.util.List<U>") Closure cl) { cl.call(['hey','ya']) }
+            }
+            def foo = new Foo<Integer,String>()
+            foo.foo { it.each { println it.toUpperCase() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQN() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo<T,U> {
-        public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call(['hey','ya']) }
-    }
-    def foo = new Foo<Integer,String>()
-
-    foo.foo { it.each { println it.toUpperCase() } }
-'''
+            class Foo<T,U> {
+                public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call(['hey','ya']) }
+            }
+            def foo = new Foo<Integer,String>()
+            foo.foo { it.each { println it.toUpperCase() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClass() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo {
-        void bar() {
-            println 'Haha!'
-        }
-    }
-
-    class Tor<D,U> {
-        public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call([new Foo(), new Foo()]) }
-    }
-    def tor = new Tor<Integer,Foo>()
-
-    tor.foo { it.each { it.bar() } }
-'''
+            class Foo {
+                void bar() {
+                    println 'Haha!'
+                }
+            }
+            class Tor<D,U> {
+                public void foo(@ClosureParams(value=FromString,options="List<U>") Closure cl) { cl.call([new Foo(), new Foo()]) }
+            }
+            def tor = new Tor<Integer,Foo>()
+            tor.foo { it.each { it.bar() } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndNoExplicitSignatureAndNoFQNAndReferenceToSameUnitClassAndTwoArgs() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo {
-        void bar() {
-            println 'Haha!'
-        }
-    }
-
-    class Tor<D,U> {
-        public void foo(@ClosureParams(value=FromString,options=["D,List<U>"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) }
-    }
-    def tor = new Tor<Integer,Foo>()
-
-    tor.foo { r, e -> r.times { e.each { it.bar() } } }
-'''
+            class Foo {
+                void bar() {
+                    println 'Haha!'
+                }
+            }
+            class Tor<D,U> {
+                public void foo(@ClosureParams(value=FromString,options=["D,List<U>"]) Closure cl) { cl.call(3, [new Foo(), new Foo()]) }
+            }
+            def tor = new Tor<Integer,Foo>()
+            tor.foo { r, e -> r.times { e.each { it.bar() } } }
+        '''
     }
 
     void testFromStringWithGenericPlaceholderFromClassWithTwoGenericsAndPolymorphicSignature() {
         assertScript '''import groovy.transform.stc.FromString
-import groovy.transform.stc.ClosureParams
-
-    class Foo {
-        void bar() {
-            println 'Haha!'
-        }
-    }
-
-    class Tor<D,U> {
-        public void foo(@ClosureParams(value=FromString,options=["D,List<U>", "D"]) Closure cl) {
-            if (cl.maximumNumberOfParameters==2) {
-                cl.call(3, [new Foo(), new Foo()])
-            } else {
-                cl.call(3)
+            class Foo {
+                void bar() {
+                    println 'Haha!'
+                }
             }
-        }
-    }
-    def tor = new Tor<Integer,Foo>()
-
-    tor.foo { r, e -> r.times { e.each { it.bar() } } }
-    tor.foo { it.times { println 'polymorphic' } }
-'''
+            class Tor<D,U> {
+                public void foo(@ClosureParams(value=FromString,options=["D,List<U>", "D"]) Closure cl) {
+                    if (cl.maximumNumberOfParameters==2) {
+                        cl.call(3, [new Foo(), new Foo()])
+                    } else {
+                        cl.call(3)
+                    }
+                }
+            }
+            def tor = new Tor<Integer,Foo>()
+            tor.foo { r, e -> r.times { e.each { it.bar() } } }
+            tor.foo { it.times { println 'polymorphic' } }
+        '''
     }
 
     void testStringGroovyMethodsFindMethodWithVargs() {
         assertScript '''
             "75001 Paris".find(/(\\d{5}\\s(\\w+))/) { all, zip, city -> println all.toUpperCase() }
-'''
-
+        '''
         assertScript '''
             "75001 Paris".find(/(\\d{5}\\s(\\w+))/) { String all, String zip, String city -> println all.toUpperCase() }
-'''
+        '''
         shouldFailWithMessages '''
             "75001 Paris".find(/(\\d{5}\\s(\\w+))/) { String all, Date zip, String city -> println all.toUpperCase() }
-''', 'Expected parameter of type java.lang.String but got java.util.Date'
+        ''',
+        'Expected type java.lang.String for closure parameter: zip'
+    }
+
+    void testFromStringInSameSourceUnit() {
+        assertScript '''import groovy.transform.stc.FromString
+            public <T> void doSomething(T val, @ClosureParams(value=FromString, options="T") Closure cl) {
+                cl(val)
+            }
+            doSomething('foo') {
+                println it.toUpperCase()
+            }
+            doSomething(new Date()) {
+                println it.time
+            }
+        '''
     }
 
     void testStringGroovyMethodsFindMethodWithList() {
@@ -1199,120 +1176,94 @@ import groovy.transform.stc.ClosureParams
         '''
     }
 
-    void testFromStringInSameSourceUnit() {
-        assertScript '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FromString
-
-public <T> void doSomething(T val, @ClosureParams(value=FromString, options="T") Closure cl) {
-    cl(val)
-}
-
-doSomething('foo') {
-    println it.toUpperCase()
-}
-
-doSomething(new Date()) {
-    println it.time
-}
-'''
-
-    }
-
     void testInferenceWithSAMTypeCoercion() {
         assertScript '''import java.util.concurrent.Callable
+            interface Action<T> {
+                void execute(T thing)
+            }
 
-interface Action<T> {
-    void execute(T thing)
-}
-
-class Wrapper<T> {
-
-    private final T thing
+            class Wrapper<T> {
 
-    Wrapper(T thing) {
-        this.thing = thing
-    }
+                private final T thing
 
-    void contravariantTake(Action<? super T> action) {
-        action.execute(thing)
-    }
+                Wrapper(T thing) {
+                    this.thing = thing
+                }
 
-    void invariantTake(Action<T> action) {
-        action.execute(thing)
-    }
+                void contravariantTake(Action<? super T> action) {
+                    action.execute(thing)
+                }
 
-}
+                void invariantTake(Action<T> action) {
+                    action.execute(thing)
+                }
 
-static <T> Wrapper<T> wrap(Callable<T> callable) {
-    new Wrapper(callable.call())
-}
+            }
 
-static Integer dub(Integer integer) {
-    integer * 2
-}
+            static <T> Wrapper<T> wrap(Callable<T> callable) {
+                new Wrapper(callable.call())
+            }
 
-wrap {
-    1
-} contravariantTake {
-    dub(it) // fails static compile, 'it' is not known to be Integer
-}
+            static Integer dub(Integer integer) {
+                integer * 2
+            }
 
-wrap {
-    1
-} invariantTake {
-    dub(it) // passes static compile, 'it' is known to be Integer
-}
+            wrap {
+                1
+            } contravariantTake {
+                dub(it) // fails static compile, 'it' is not known to be Integer
+            }
 
-'''
+            wrap {
+                1
+            } invariantTake {
+                dub(it) // passes static compile, 'it' is known to be Integer
+            }
+        '''
     }
 
     void testGroovy6602() {
-        shouldFailWithMessages '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FromString
-
-void foo(@ClosureParams(value = FromString, options = "java.lang.Number")
-         Closure cl) {
-    cl.call(4.5)
-}
-
-foo { Integer i -> println i }
-''', 'Expected parameter of type java.lang.Number but got java.lang.Integer'
+        shouldFailWithMessages '''import groovy.transform.stc.FromString
+            void foo(@ClosureParams(value=FromString, options="java.lang.Number") Closure cl) {
+                cl.call(4.5)
+            }
+            foo { Integer i -> println i }
+        ''',
+        'Expected type java.lang.Number for closure parameter: i'
     }
 
     void testGroovy6729() {
-        assertScript '''import groovy.transform.stc.ClosureParams
-import groovy.transform.stc.FirstParam
-
-    static <T> List<T> callee01(List<T>self, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
-        self.each {
-            c.call(it)
-        }
-        return self
-    }
-        callee01(["a","b","c"]) { a ->
-            println(a.toUpperCase()) // [Static type checking] - Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is correct and if the method exists.
-        }
-    '''
+        assertScript '''import groovy.transform.stc.FirstParam
+            static <T> List<T> callee01(List<T>self, @ClosureParams(FirstParam.FirstGenericType) Closure c) {
+                self.each {
+                    c.call(it)
+                }
+                return self
+            }
+            callee01(["a","b","c"]) { a ->
+                println(a.toUpperCase()) // [Static type checking] - Cannot find matching method java.lang.Object#toUpperCase(). Please check if the declared type is correct and if the method exists.
+            }
+        '''
     }
 
     void testGroovy6735() {
         assertScript '''
-def extractInfo(String s) {
-  def squareNums = s.findAll(/\\d+/) { String num -> num.toInteger() }.collect{ Integer num -> num ** 2 }
-  def wordSizePlusNum = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, String word, String num -> word.size() + num.toInteger() }
-  def numPlusWordSize = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, word, num -> num.toInteger() + word.size() }
-  [squareNums, wordSizePlusNum, numPlusWordSize]
-}
-assert extractInfo(" ab 12 cdef 34 jhg ") == [[144, 1156], [14, 38], [14, 38]]
-'''
+            def extractInfo(String s) {
+              def squareNums = s.findAll(/\\d+/) { String num -> num.toInteger() }.collect{ Integer num -> num ** 2 }
+              def wordSizePlusNum = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, String word, String num -> word.size() + num.toInteger() }
+              def numPlusWordSize = s.findAll(/\\s*(\\w+)\\s*(\\d+)/) { _, word, num -> num.toInteger() + word.size() }
+              [squareNums, wordSizePlusNum, numPlusWordSize]
+            }
+            assert extractInfo(" ab 12 cdef 34 jhg ") == [[144, 1156], [14, 38], [14, 38]]
+        '''
         assertScript '''
-def method() {
-  assert "foobarbaz".findAll('b(a)([rz])') { full, a, b -> assert "BA"=="B" + a.toUpperCase() }.size() == 2
-  assert "foobarbaz".findAll('ba') { String found -> assert "BA" == found.toUpperCase() }.size() == 2
-}
+            def method() {
+              assert "foobarbaz".findAll('b(a)([rz])') { full, a, b -> assert "BA"=="B" + a.toUpperCase() }.size() == 2
+              assert "foobarbaz".findAll('ba') { String found -> assert "BA" == found.toUpperCase() }.size() == 2
+            }
 
-method()
-'''
+            method()
+        '''
     }
 
     void testGroovy9058() {
@@ -1354,7 +1305,7 @@ method()
 
     void testGroovy9518b() {
         assertScript '''
-            import groovy.transform.stc.*
+            import groovy.transform.stc.SimpleType
 
             class C {
                 C(String s, @ClosureParams(value=SimpleType, options='java.util.List') Closure<Integer> c) {
@@ -1391,7 +1342,7 @@ method()
 
     void testGroovy9735() {
         assertScript '''
-            import groovy.transform.stc.*
+            import groovy.transform.stc.FirstParam
 
             class C<I extends Item> {
                 Queue<I> queue
@@ -1420,7 +1371,7 @@ method()
 
     void testGroovy9597a() {
         assertScript '''
-            import groovy.transform.stc.*
+            import groovy.transform.stc.FirstParam
 
             class A {
                 def <T> void proc(Collection<T> values, @ClosureParams(FirstParam.FirstGenericType) Closure<String> block) {
@@ -1443,7 +1394,7 @@ method()
 
     void testGroovy9597b() {
         assertScript '''
-            import groovy.transform.stc.*
+            import groovy.transform.stc.FirstParam
 
             class A {
                 static A of(@DelegatesTo(A) Closure x) {
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 6c9b0fd..7d0dedc 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -240,14 +240,14 @@ final class LambdaTest {
         '''
     }
 
-    //TODO: GROOVY-10277
+    @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<java.lang.Integer>/
+        assert err =~ /Expected type java.lang.Integer for lambda parameter: b/
     }
 
     @Test // GROOVY-9977
@@ -894,19 +894,35 @@ final class LambdaTest {
                     new Value<>(supplier.get())
                 }
                 def <T> Value<T> replace(Function<? super V, ? extends T> function) {
-                    new Value(function.apply(val))
+                    new Value<>(function.apply(val))
                 }
             }
 
             @groovy.transform.CompileStatic
             void test() {
-                assert new Value(123).replace(() -> 'foo').toString() == 'foo'
-                assert new Value(123).replace((Integer v) -> 'bar').toString() == 'bar'
+                assert new Value<>(123).replace(() -> 'foo').toString() == 'foo'
+                assert new Value<>(123).replace((Integer v) -> 'bar').toString() == 'bar'
             }
             test()
         '''
     }
 
+    @Test // GROOVY-10372
+    void testFunctionalInterface5() {
+        def err = shouldFail '''
+            interface I {
+                def m(List<String> strings)
+            }
+
+            @groovy.transform.CompileStatic
+            void test() {
+                I face = (List<Object> list) -> null
+            }
+            test()
+        '''
+        assert err =~ /Expected type java.util.List<java.lang.String> for lambda parameter: list/
+    }
+
     @Test
     void testFunctionWithUpdatingLocalVariable() {
         assertScript '''
diff --git a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
index 032fe5a..5f4e75f 100644
--- a/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/TypeInferenceSTCTest.groovy
@@ -574,7 +574,7 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testShouldNotFailWithWithAndExplicitTypedIt() {
+    void testShouldFailWithWithAndWrongExplicitIt() {
         shouldFailWithMessages '''
             class A {
                 int x
@@ -583,7 +583,8 @@ class TypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             a.with { String it ->
                 it.x = 2 // should be recognized as a.x at compile time
             }
-        ''', 'Expected parameter of type A but got java.lang.String'
+        ''',
+        'Expected type A for closure parameter: it'
     }
 
     void testShouldNotFailWithInheritanceAndWith() {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
index 4f1e62b..0f9a644 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
@@ -56,6 +56,7 @@ trait StaticCompilationTestSupport {
                 new ImportCustomizer().tap {
                     addImports(
                             'groovy.transform.ASTTest',
+                            'groovy.transform.stc.ClosureParams',
                             'org.codehaus.groovy.ast.ClassHelper',
                             'org.codehaus.groovy.transform.stc.StaticTypesMarker')
                     addStaticStars(
diff --git a/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy b/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
index d47038a..1bd6ff9 100644
--- a/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
+++ b/src/testFixtures/groovy/groovy/transform/stc/StaticTypeCheckingTestCase.groovy
@@ -42,12 +42,16 @@ abstract class StaticTypeCheckingTestCase extends GroovyTestCase {
         config = new CompilerConfiguration()
         def imports = new ImportCustomizer()
         imports.addImports(
-                'groovy.transform.ASTTest', 'org.codehaus.groovy.transform.stc.StaticTypesMarker',
-                'org.codehaus.groovy.ast.ClassHelper'
-            )
-        imports.addStaticStars('org.codehaus.groovy.control.CompilePhase')
-        imports.addStaticStars('org.codehaus.groovy.transform.stc.StaticTypesMarker')
-        imports.addStaticStars('org.codehaus.groovy.ast.ClassHelper')
+            'groovy.transform.ASTTest',
+            'groovy.transform.stc.ClosureParams',
+            'org.codehaus.groovy.ast.ClassHelper',
+            'org.codehaus.groovy.transform.stc.StaticTypesMarker'
+        )
+        imports.addStaticStars(
+            'org.codehaus.groovy.ast.ClassHelper',
+            'org.codehaus.groovy.control.CompilePhase',
+            'org.codehaus.groovy.transform.stc.StaticTypesMarker'
+        )
         config.addCompilationCustomizers(new ASTTransformationCustomizer(TypeChecked), imports)
         configure()
         shell = new GroovyShell(config)