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/11/01 16:39:58 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-7141: STC: infer param types for closure map to SAM-type coercion

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

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


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 3a72151294 GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
3a72151294 is described below

commit 3a72151294419195e37c29ac24f316d4b1361577
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Nov 1 11:28:09 2022 -0500

    GROOVY-7141: STC: infer param types for closure map to SAM-type coercion
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 30 +++++++++++++-------
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    | 32 +++++++++++++++++++++-
 2 files changed, 51 insertions(+), 11 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 d984b01674..89b931de4d 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -666,7 +666,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
             ClassNode inferredType = localVariable.getNodeMetaData(INFERRED_TYPE);
             inferredType = getInferredTypeFromTempInfo(localVariable, inferredType);
-            if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getType())) {
+            if (inferredType != null && !isObjectType(inferredType) && !inferredType.equals(accessedVariable.getOriginType())) {
                 vexp.putNodeMetaData(INFERRED_TYPE, inferredType);
             }
         }
@@ -919,9 +919,20 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private void applyTargetType(final ClassNode target, final Expression source) {
-        if (isFunctionalInterface(target)) {
+        if (isClosureWithType(target)) {
+            if (source instanceof ClosureExpression) {
+                GenericsType returnType = target.getGenericsTypes()[0];
+                storeInferredReturnType(source, getCombinedBoundType(returnType));
+            }
+        } else if (isFunctionalInterface(target)) {
             if (source instanceof ClosureExpression) {
                 inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) source);
+            } else if (source instanceof MapExpression) { // GROOVY-7141
+                List<MapEntryExpression> spec = ((MapExpression) source).getMapEntryExpressions();
+                if (spec.size() == 1 && spec.get(0).getValueExpression() instanceof ClosureExpression
+                        && findSAM(target).getName().equals(spec.get(0).getKeyExpression().getText())) {
+                    inferParameterAndReturnTypesOfClosureOnRHS(target, (ClosureExpression) spec.get(0).getValueExpression());
+                }
             } else if (source instanceof MethodReferenceExpression) {
                 LambdaExpression lambdaExpression = constructLambdaExpressionForMethodReference(target, (MethodReferenceExpression) source);
 
@@ -929,11 +940,6 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 source.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
                 source.putNodeMetaData(CLOSURE_ARGUMENTS, Arrays.stream(lambdaExpression.getParameters()).map(Parameter::getType).toArray(ClassNode[]::new));
             }
-        } else if (isClosureWithType(target)) {
-            if (source instanceof ClosureExpression) {
-                GenericsType returnType = target.getGenericsTypes()[0];
-                storeInferredReturnType(source, getCombinedBoundType(returnType));
-            }
         }
     }
 
@@ -942,13 +948,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         Parameter[] closureParameters = getParametersSafe(rhsExpression);
         ClassNode[] samParameterTypes = typeInfo.getV1();
 
-        int n = closureParameters.length, m = samParameterTypes.length;
-        if (n == m || (1 == m && hasImplicitParameter(rhsExpression))) {
+        if (samParameterTypes.length == 1 && hasImplicitParameter(rhsExpression)) {
+            Variable it = rhsExpression.getVariableScope().getDeclaredVariable("it"); // GROOVY-7141
+            closureParameters = new Parameter[]{it instanceof Parameter ? (Parameter) it : new Parameter(dynamicType(), "")};
+        }
+
+        int n = closureParameters.length;
+        if (n == samParameterTypes.length) {
             for (int i = 0; i < n; i += 1) {
                 Parameter parameter = closureParameters[i];
                 if (parameter.isDynamicTyped()) {
                     parameter.setType(samParameterTypes[i]);
-                    parameter.setOriginType(samParameterTypes[i]);
                 } else {
                     checkParamType(parameter, samParameterTypes[i], i == n-1, rhsExpression instanceof LambdaExpression);
                 }
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index c05b254241..ed5344d30d 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -1195,7 +1195,37 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    void testInferenceWithSAMTypeCoercion() {
+    // GROOVY-7141
+    void testInferenceWithSAMTypeCoercion1() {
+        String sam = '''
+            @FunctionalInterface
+            interface I {
+                String foo(String s)
+            }
+        '''
+        assertScript sam + '''
+            def impl = [foo: { it.toUpperCase() }] as I
+            String result = impl.foo('bar')
+            assert result == 'BAR'
+        '''
+        assertScript sam + '''
+            def impl = [foo: { s -> s.toUpperCase() }] as I
+            String result = impl.foo('bar')
+            assert result == 'BAR'
+        '''
+        assertScript sam + '''
+            def impl = [foo: { String s -> s.toUpperCase() }] as I
+            String result = impl.foo('bar')
+            assert result == 'BAR'
+        '''
+        assertScript '''
+            def impl = [apply: { it.toUpperCase() }] as java.util.function.Function<String,String>
+            String result = impl.apply('bar')
+            assert result == 'BAR'
+        '''
+    }
+
+    void testInferenceWithSAMTypeCoercion2() {
         assertScript '''import java.util.concurrent.Callable
             interface Action<T> {
                 void execute(T thing)