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/09/03 21:05:39 UTC

[groovy] branch GROOVY_3_0_X updated: GROOVY-10734: STC: `Type::instanceMethod` specifies first param type

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 c493f05eba GROOVY-10734: STC: `Type::instanceMethod` specifies first param type
c493f05eba is described below

commit c493f05eba6e0156986d99f2c08e99b288d7cc47
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Sat Sep 3 11:17:37 2022 -0500

    GROOVY-10734: STC: `Type::instanceMethod` specifies first param type
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 27 ++++++++++++++++------
 .../transform/stc/MethodReferenceTest.groovy       | 18 +++++++++++++++
 2 files changed, 38 insertions(+), 7 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 7154253555..1ab4edd184 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -934,7 +934,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (rhsExpression instanceof ClosureExpression) {
             inferParameterAndReturnTypesOfClosureOnRHS(lhsType, (ClosureExpression) rhsExpression);
         } else if (rhsExpression instanceof MethodReferenceExpression) {
-            LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lhsType);
+            LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(lhsType, (MethodReferenceExpression) rhsExpression);
 
             inferParameterAndReturnTypesOfClosureOnRHS(lhsType, lambdaExpression);
             rhsExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
@@ -3665,7 +3665,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     newArgumentExpressions.add(argumentExpression);
                 } else {
                     methodReferencePositions.add(i);
-                    newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType));
+                    newArgumentExpressions.add(constructLambdaExpressionForMethodReference(paramType, (MethodReferenceExpression) argumentExpression));
                 }
             }
         }
@@ -3681,11 +3681,24 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType) {
-        int nParameters = findSAM(functionalInterfaceType).getParameters().length;
-        Parameter[] parameters = new Parameter[nParameters];
-        for (int i = 0; i < nParameters; i += 1) {
-            parameters[i] = new Parameter(DYNAMIC_TYPE, "p" + i);
+    private LambdaExpression constructLambdaExpressionForMethodReference(final ClassNode functionalInterfaceType, final MethodReferenceExpression methodReference) {
+        Parameter[] parameters = findSAM(functionalInterfaceType).getParameters();
+        int nParameters = parameters.length;
+        if (nParameters > 0) {
+            ClassNode firstParamType = DYNAMIC_TYPE;
+            // GROOVY-10734: Type::instanceMethod has implied first param
+            List<MethodNode> candidates = methodReference.getNodeMetaData(MethodNode.class);
+            if (candidates != null && !candidates.isEmpty()) {
+                ClassNode objExpType = getType(methodReference.getExpression());
+                if (isClassClassNodeWrappingConcreteType(objExpType)
+                        && candidates.stream().allMatch(mn -> !mn.isStatic())) {
+                    firstParamType = objExpType.getGenericsTypes()[0].getType();
+                }
+            }
+            parameters = new Parameter[nParameters];
+            for (int i = 0; i < nParameters; i += 1) {
+                parameters[i] = new Parameter(i == 0 ? firstParamType : DYNAMIC_TYPE, "p" + i);
+            }
         }
         return new LambdaExpression(parameters, GENERATED_EMPTY_STATEMENT);
     }
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index d7f14b24db..f2ea2d9e62 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -195,6 +195,24 @@ final class MethodReferenceTest extends GroovyTestCase {
         '''
     }
 
+    // class::instanceMethod -- GROOVY-10734
+    void testFunctionCI7() {
+        assertScript '''
+            class C {
+                String p
+            }
+            @groovy.transform.CompileStatic
+            Map test(Collection<C> items) {
+                items.stream().collect(
+                    java.util.stream.Collectors.groupingBy(C::getP) // Failed to find the expected method[getP(Object)] in the type[C]
+                )
+            }
+            def map = test([new C(p:'foo'), new C(p:'bar'), new C(p:'foo')])
+            assert map.foo.size() == 2
+            assert map.bar.size() == 1
+        '''
+    }
+
     // class::instanceMethod -- GROOVY-9974
     void testPredicateCI() {
         assertScript '''