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/01 15:38:03 UTC

[groovy] branch master updated: 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 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 43715e5  GROOVY-10336: STC: handle method reference(s) supplied to variadic param
43715e5 is described below

commit 43715e58bff3cb579371e68e1423c153c6742f9a
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
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 38 ++++++++++++----------
 .../transform/stc/MethodReferenceTest.groovy       | 18 ++++++++++
 2 files changed, 38 insertions(+), 18 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 e132713..ee72e98 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -3611,34 +3611,36 @@ 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();
-
-            if (!isFunctionalInterface(paramType.redirect())) {
-                addError("The argument is a method reference, but the parameter type is not a functional interface", argumentExpression);
-                newArgumentExpressionList.add(argumentExpression);
+                newArgumentExpressions.add(argumentExpression);
             } else {
-                newArgumentExpressionList.add(constructLambdaExpressionForMethodReference(paramType));
-                methodReferenceParamIndexList.add(i);
+                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);
+                    newArgumentExpressions.add(argumentExpression);
+                } else {
+                    methodReferencePositions.add(i);
+                    newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType));
+                }
             }
         }
 
-        if (methodReferenceParamIndexList.isEmpty()) return; // GROOVY-10269
+        if (methodReferencePositions.isEmpty()) return; // GROOVY-10269
 
-        visitMethodCallArguments(receiver, args(newArgumentExpressionList), true, selectedMethod);
+        visitMethodCallArguments(receiver, args(newArgumentExpressions), true, selectedMethod);
 
-        for (int index : methodReferenceParamIndexList) {
-            Expression lambdaExpression = newArgumentExpressionList.get(index);
+        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 a5ad7aa..da8a61f 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -644,4 +644,22 @@ final class MethodReferenceTest {
 
         assert err =~ /The argument is a method reference, but the parameter type is not a functional interface/
     }
+
+    @Test // GROOVY-10336
+    void testNotFunctionalInterface2() {
+        def err = shouldFail shell, '''
+            class C {
+                Integer m() { 1 }
+            }
+            @CompileStatic
+            void test() {
+                Supplier<Long> outer = () -> {
+                    Closure<Long> inner = (Object o, Supplier<Integer> s) -> 2L
+                    inner(new Object(), new C()::m) // TODO: resolve call(Object,Supplier<Integer>)
+                }
+            }
+        '''
+
+        assert err =~ /The argument is a method reference, but the parameter type is not a functional interface/
+    }
 }