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/01/30 20:43:23 UTC

[groovy] 01/04: GROOVY-10336: STC: handle method reference(s) supplied to variadic param

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

commit 0864af26c811c4b866960d49d5d516d201be3089
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Mon Nov 1 10:37:29 2021 -0500

    GROOVY-10336: STC: handle method reference(s) supplied to variadic param
    
    Conflicts:
    	src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 45 +++++++++++-----------
 .../transform/stc/MethodReferenceTest.groovy       | 20 ++++++++++
 2 files changed, 42 insertions(+), 23 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 206b6bc..453040d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3629,39 +3629,38 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
 
         Parameter[] parameters = selectedMethod.getParameters();
+        final int nthParameter = parameters.length - 1;
 
-        List<Integer> methodReferenceParamIndexList = new LinkedList<>();
-        List<Expression> newArgumentExpressionList = new LinkedList<>();
+        List<Integer> methodReferencePositions = new LinkedList<>();
+        List<Expression> newArgumentExpressions = new LinkedList<>();
         for (int i = 0, n = argumentExpressions.size(); i < n; i += 1) {
             Expression argumentExpression = argumentExpressions.get(i);
             if (!(argumentExpression instanceof MethodReferenceExpression)) {
-                newArgumentExpressionList.add(argumentExpression);
-                continue;
-            }
-
-            Parameter param = parameters[i];
-            ClassNode paramType = param.getType();
+                newArgumentExpressions.add(argumentExpression);
+            } else {
+                Parameter param = parameters[Math.min(i, nthParameter)]; // GROOVY-10336
+                ClassNode paramType = param.getType();
+                if (i >= nthParameter && paramType.isArray())
+                    paramType = paramType.getComponentType();
 
-            if (!isFunctionalInterface(paramType.redirect())) {
-                addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression);
-                newArgumentExpressionList.add(argumentExpression);
-                continue;
+                if (!isFunctionalInterface(paramType.redirect())) {
+                    addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression);
+                    newArgumentExpressions.add(argumentExpression);
+                } else {
+                    methodReferencePositions.add(i);
+                    newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType));
+                }
             }
-
-            LambdaExpression constructedLambdaExpression = constructLambdaExpressionForMethodReference(paramType);
-
-            newArgumentExpressionList.add(constructedLambdaExpression);
-            methodReferenceParamIndexList.add(i);
         }
 
-        if (methodReferenceParamIndexList.isEmpty()) return; // GROOVY-10269
+        if (methodReferencePositions.isEmpty()) return; // GROOVY-10269
 
-        visitMethodCallArguments(receiver, new ArgumentListExpression(newArgumentExpressionList), true, selectedMethod);
+        visitMethodCallArguments(receiver, args(newArgumentExpressions), true, selectedMethod);
 
-        for (Integer methodReferenceParamIndex : methodReferenceParamIndexList) {
-            LambdaExpression lambdaExpression = (LambdaExpression) newArgumentExpressionList.get(methodReferenceParamIndex);
-            ClassNode[] argumentTypes = lambdaExpression.getNodeMetaData(CLOSURE_ARGUMENTS);
-            argumentExpressions.get(methodReferenceParamIndex).putNodeMetaData(CLOSURE_ARGUMENTS, argumentTypes);
+        for (int index : methodReferencePositions) {
+            Expression lambdaExpression = newArgumentExpressions.get(index);
+            Expression methodReferenceExpression = argumentExpressions.get(index);
+            methodReferenceExpression.putNodeMetaData(CLOSURE_ARGUMENTS, lambdaExpression.getNodeMetaData(CLOSURE_ARGUMENTS));
         }
     }
 
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index 70ed133..7afcd0e 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -692,4 +692,24 @@ final class MethodReferenceTest extends GroovyTestCase {
 
         assert err =~ /The argument is a method reference, but the parameter type is not a functional interface/
     }
+
+    // GROOVY-10336
+    void testNotFunctionalInterface2() {
+        def err = shouldFail '''
+            import java.util.function.Supplier
+
+            class C {
+                Integer m() { 1 }
+            }
+            @groovy.transform.CompileStatic
+            void test() {
+                Supplier<Long> outer = () -> {
+                    Closure<Long> inner = (Object o, Supplier<Integer> s) -> 2L
+                    inner(new Object(), new C()::m)
+                }
+            }
+        '''
+
+        assert err =~ /The argument is a method reference, but the parameter type is not a functional interface/
+    }
 }