You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2019/04/08 12:59:08 UTC

[groovy] 16/20: Support reference on the RHS

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

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

commit febc0673aff58f559a9dcfa7c62f4e83448e853e
Author: Daniel Sun <su...@apache.org>
AuthorDate: Mon Mar 25 23:51:20 2019 +0800

    Support reference on the RHS
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 35 ++++++++++++++++++--
 .../groovy/transform/stc/StaticTypesMarker.java    |  3 +-
 .../transform/stc/MethodReferenceTest.groovy       | 37 ++++++++++++++++++++++
 3 files changed, 71 insertions(+), 4 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 9294b7e..18a42a3 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -265,6 +265,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.toMeth
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.typeCheckMethodArgumentWithGenerics;
 import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.typeCheckMethodsWithGenerics;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.CLOSURE_ARGUMENTS;
+import static org.codehaus.groovy.transform.stc.StaticTypesMarker.CONSTRUCTED_LAMBDA_EXPRESSION;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_TYPE;
 //import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_INSTANCEOF;
 
@@ -827,7 +828,26 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
             } else {
                 lType = getType(leftExpression);
-                inferParameterAndReturnTypesOfClosureOnRHS(lType, rightExpression, op);
+
+                Expression constructedRightExpression = rightExpression;
+
+                boolean isMrExprRHS = rightExpression instanceof MethodReferenceExpression && ClassHelper.isFunctionalInterface(lType);
+                if (isMrExprRHS) {
+                    constructedRightExpression = constructLambdaExpressionForMethodReference(lType);
+                }
+
+                inferParameterAndReturnTypesOfClosureOnRHS(lType, constructedRightExpression, op);
+
+                if (isMrExprRHS) {
+                    LambdaExpression lambdaExpression = (LambdaExpression) constructedRightExpression;
+                    ClassNode[] argumentTypes =
+                            Arrays.stream(lambdaExpression.getParameters())
+                                    .map(Parameter::getType)
+                                    .toArray(ClassNode[]::new);
+
+                    rightExpression.putNodeMetaData(CLOSURE_ARGUMENTS, argumentTypes);
+                    rightExpression.putNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION, lambdaExpression);
+                }
 
                 rightExpression.visit(this);
             }
@@ -4355,8 +4375,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 // ex : def foos = ['a','b','c']
                 return right;
             }
-            if (rightRedirect.isDerivedFrom(CLOSURE_TYPE) && isSAMType(leftRedirect) && rightExpression instanceof ClosureExpression) {
-                return inferSAMTypeGenericsInAssignment(left, findSAM(left), right, (ClosureExpression) rightExpression);
+            if (rightRedirect.isDerivedFrom(CLOSURE_TYPE) && isSAMType(leftRedirect)) {
+                ClosureExpression closureExpression = null;
+                if (rightExpression instanceof ClosureExpression) {
+                    closureExpression = (ClosureExpression) rightExpression;
+                } else if (rightExpression instanceof MethodReferenceExpression) {
+                    closureExpression = rightExpression.getNodeMetaData(CONSTRUCTED_LAMBDA_EXPRESSION);
+                }
+
+                if (null != closureExpression) {
+                    return inferSAMTypeGenericsInAssignment(left, findSAM(left), right, closureExpression);
+                }
             }
 
             if (leftExpression instanceof VariableExpression) {
diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
index 03b678c..6f7d6d3 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
@@ -39,5 +39,6 @@ public enum StaticTypesMarker {
     DYNAMIC_RESOLUTION, // call recognized by a type checking extension as a dynamic method call
     SUPER_MOP_METHOD_REQUIRED, // used to store the list of MOP methods that still have to be generated
     PARAMETER_TYPE, // used to store the parameter type information of method invocation on an expression
-    INFERRED_FUNCTIONAL_INTERFACE_TYPE // used to store the function interface type information on an expression
+    INFERRED_FUNCTIONAL_INTERFACE_TYPE, // used to store the function interface type information on an expression
+    CONSTRUCTED_LAMBDA_EXPRESSION // used to store the constructed lambda expression for method reference and constructor reference
 }
diff --git a/src/test/groovy/transform/stc/MethodReferenceTest.groovy b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
index ffe7297..70b1f7f 100644
--- a/src/test/groovy/transform/stc/MethodReferenceTest.groovy
+++ b/src/test/groovy/transform/stc/MethodReferenceTest.groovy
@@ -272,4 +272,41 @@ class MethodReferenceTest extends GroovyTestCase {
 
         '''
     }
+
+    // class::staticMethod
+    void testFunctionCS_RHS() {
+        assertScript '''
+            import java.util.function.Function
+            import java.util.stream.Stream
+            import java.util.stream.Collectors
+
+            @groovy.transform.CompileStatic
+            void p() {
+                Function<Integer, Integer> f = Math::abs
+                def result = [1, -2, 3].stream().map(f).collect(Collectors.toList())
+
+                assert [1, 2, 3] == result
+            }
+            
+            p()
+        '''
+    }
+
+    // class::new
+    void testFunctionCN_RHS() {
+        assertScript '''
+            import java.util.function.Function
+            import java.util.stream.Stream
+            import java.util.stream.Collectors
+
+            @groovy.transform.CompileStatic
+            void p() {
+                Function<String, Integer> f = Integer::new
+                assert [1, 2, 3] == ["1", "2", "3"].stream().map(f).collect(Collectors.toList())
+            }
+            
+            p()
+
+        '''
+    }
 }