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/06/29 18:56:51 UTC

[groovy] branch master updated: GROOVY-10653: STC: outer closure parameter reference

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 8cf97aaa2b GROOVY-10653: STC: outer closure parameter reference
8cf97aaa2b is described below

commit 8cf97aaa2b20936ec7217043e7d5cbb13f9bc0d5
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Wed Jun 29 13:38:25 2022 -0500

    GROOVY-10653: STC: outer closure parameter reference
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 41 +++++++++++-----------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 24 +++++++++++++
 2 files changed, 44 insertions(+), 21 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 5f925c2e5a..ae0acf3d27 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5060,9 +5060,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     type = typeCheckingContext.controlStructureVariables.get(parameter);
                 }
                 // now check for closure override
-                TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
-                if (type == null && enclosingClosure != null && temporaryTypesForExpression == null) {
-                    type = getTypeFromClosureArguments(parameter, enclosingClosure);
+                if (type == null && temporaryTypesForExpression == null) {
+                    type = getTypeFromClosureArguments(parameter);
                 }
                 if (type != null) {
                     storeType(vexp, type);
@@ -5141,25 +5140,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return ((Expression) node).getType();
     }
 
-    private ClassNode getTypeFromClosureArguments(final Parameter parameter, final TypeCheckingContext.EnclosingClosure enclosingClosure) {
-        ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
-        ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
-        if (closureParamTypes == null) return null;
-        Parameter[] parameters = closureExpression.getParameters();
-        String name = parameter.getName();
-
-        if (parameters != null) {
-            if (parameters.length == 0) {
-                return "it".equals(name) && closureParamTypes.length != 0 ? closureParamTypes[0] : null;
-            }
-
-            for (int index = 0; index < parameters.length; index++) {
-                if (name.equals(parameters[index].getName())) {
-                    return closureParamTypes.length > index ? closureParamTypes[index] : null;
+    private ClassNode getTypeFromClosureArguments(final Parameter parameter) {
+        for (TypeCheckingContext.EnclosingClosure enclosingClosure : typeCheckingContext.getEnclosingClosureStack()) {
+            ClosureExpression closureExpression = enclosingClosure.getClosureExpression();
+            ClassNode[] closureParamTypes = closureExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
+            if (closureParamTypes != null) {
+                Parameter[] parameters = closureExpression.getParameters();
+                if (parameters != null) {
+                    final int n = parameters.length;
+                    String parameterName = parameter.getName();
+                    if (n == 0 && parameterName.equals("it")) {
+                        return closureParamTypes.length > 0 ? closureParamTypes[0] : null;
+                    }
+                    for (int i = 0; i < n; i += 1) {
+                        if (parameterName.equals(parameters[i].getName())) {
+                            return closureParamTypes.length > i ? closureParamTypes[i] : null;
+                        }
+                    }
                 }
             }
         }
-
         return null;
     }
 
@@ -5997,8 +5997,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             if (inferredType == null) {
                 inferredType = typeCheckingContext.controlStructureVariables.get(parameter); // for/catch/closure
                 if (inferredType == null) {
-                    TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
-                    if (enclosingClosure != null) inferredType = getTypeFromClosureArguments(parameter, enclosingClosure);
+                    inferredType = getTypeFromClosureArguments(parameter); // @ClosureParams or SAM-type coercion
                 }
                 setNodeMetaData(INFERRED_TYPE, inferredType != null ? inferredType : parameter.getType()); // GROOVY-10651
             }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index a5762380cf..251b7368f7 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -4824,6 +4824,30 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10653
+    void testMockito() {
+        assertScript '''
+            @Grab('org.mockito:mockito-core:4.5.1')
+            import static org.mockito.Mockito.*
+
+            class C {
+                String string
+            }
+            interface I {
+                C f(String s)
+            }
+
+            def i = mock(I)
+            when(i.f(anyString())).thenAnswer { /*InvocationOnMock*/ iom ->
+              //new C(string: iom.arguments[0]) works
+                new C().tap {
+                    string = iom.arguments[0]
+                }
+            }
+            assert i.f('x') instanceof C
+        '''
+    }
+
     //--------------------------------------------------------------------------
 
     static class MyList