groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sun...@apache.org
Subject groovy git commit: Support callable native lambda
Date Wed, 31 Jan 2018 02:12:42 GMT
Repository: groovy
Updated Branches:
  refs/heads/native-lambda 0b8beb93c -> c24c0b7e6


Support callable native lambda


Project: http://git-wip-us.apache.org/repos/asf/groovy/repo
Commit: http://git-wip-us.apache.org/repos/asf/groovy/commit/c24c0b7e
Tree: http://git-wip-us.apache.org/repos/asf/groovy/tree/c24c0b7e
Diff: http://git-wip-us.apache.org/repos/asf/groovy/diff/c24c0b7e

Branch: refs/heads/native-lambda
Commit: c24c0b7e6a67dcdf277207d4261cfa6f2b55031f
Parents: 0b8beb9
Author: sunlan <sunlan@apache.org>
Authored: Wed Jan 31 10:12:36 2018 +0800
Committer: sunlan <sunlan@apache.org>
Committed: Wed Jan 31 10:12:36 2018 +0800

----------------------------------------------------------------------
 .../org/codehaus/groovy/ast/ClassHelper.java    |  4 ++
 .../groovy/classgen/asm/InvocationWriter.java   | 29 ++++++++
 .../asm/sc/StaticTypesLambdaWriter.java         |  6 +-
 .../stc/StaticTypeCheckingVisitor.java          | 10 ++-
 src/test/groovy/transform/stc/LambdaTest.groovy | 69 +++++++++++++++++++-
 5 files changed, 108 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/c24c0b7e/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
index 9fc8643..ed984ce 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -396,6 +396,10 @@ public class ClassHelper {
         return findSAM(type) != null;
     }
 
+    public static boolean isFunctionInterface(ClassNode type) {
+        return type.isInterface() && !type.getAnnotations(FunctionalInterface_Type).isEmpty()
&& isSAMType(type);
+    }
+
     /**
      * Returns the single abstract method of a class node, if it is a SAM type, or null otherwise.
      *

http://git-wip-us.apache.org/repos/asf/groovy/blob/c24c0b7e/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index 10a82ed..0d8cc1b 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -479,11 +479,25 @@ public class InvocationWriter {
         return methodName;
     }
 
+    private boolean isFunctionInterfaceCall(MethodCallExpression call) {
+        ClassNode type = call.getObjectExpression().getType();
+
+        if (ClassHelper.isFunctionInterface(type)) {
+            return true;
+        }
+
+        return false;
+    }
+
     public void writeInvokeMethod(MethodCallExpression call) {
         if (isClosureCall(call)) {
             // let's invoke the closure method
             invokeClosure(call.getArguments(), call.getMethodAsString());
         } else {
+            if (isFunctionInterfaceCall(call)) {
+                call = transformToRealMethodCall(call);
+            }
+
             boolean isSuperMethodCall = usesSuper(call);
             MethodCallerMultiAdapter adapter = invokeMethod;
             if (isSuperMethodCall && call.isSafe()) {
@@ -498,6 +512,21 @@ public class InvocationWriter {
         }
     }
 
+    private MethodCallExpression transformToRealMethodCall(MethodCallExpression call) {
+        ClassNode type = call.getObjectExpression().getType();
+        final MethodNode methodNode = ClassHelper.findSAM(type);
+
+        call = (MethodCallExpression) call.transformExpression(expression -> {
+            if (!(expression instanceof ConstantExpression)) {
+                return expression;
+            }
+
+            return new ConstantExpression(methodNode.getName());
+        });
+        call.setMethodTarget(methodNode);
+        return call;
+    }
+
     private boolean isClosureCall(MethodCallExpression call) {
         // are we a local variable?
         // it should not be an explicitly "this" qualified method call

http://git-wip-us.apache.org/repos/asf/groovy/blob/c24c0b7e/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
index 7f44c90..2d877ec 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesLambdaWriter.java
@@ -102,7 +102,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter {
                         .filter(MethodNode::isAbstract)
                         .collect(Collectors.toList());
 
-        if (!(isFunctionInterface(lambdaType) && abstractMethodNodeList.size() ==
1)) {
+        if (!(ClassHelper.isFunctionInterface(lambdaType.redirect()) && abstractMethodNodeList.size()
== 1)) {
             // if the parameter type is not real FunctionInterface, generate the default
bytecode, which is actually a closure
             super.writeLambda(expression);
             return;
@@ -302,10 +302,6 @@ public class StaticTypesLambdaWriter extends LambdaWriter {
         );
     }
 
-    private boolean isFunctionInterface(ClassNode parameterType) {
-        return parameterType.redirect().isInterface() && !parameterType.redirect().getAnnotations(ClassHelper.FunctionalInterface_Type).isEmpty();
-    }
-
     public ClassNode getOrAddLambdaClass(LambdaExpression expression, int mods, MethodNode
abstractMethodNode) {
         ClassNode lambdaClass = lambdaClassMap.get(expression);
         if (lambdaClass == null) {

http://git-wip-us.apache.org/repos/asf/groovy/blob/c24c0b7e/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
----------------------------------------------------------------------
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 4688e3b..d2e9bb2 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -133,7 +133,6 @@ import static org.codehaus.groovy.ast.ClassHelper.GROOVY_OBJECT_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.GSTRING_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Integer_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Iterator_TYPE;
-import static org.codehaus.groovy.ast.ClassHelper.LAMBDA_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.LIST_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.Long_TYPE;
 import static org.codehaus.groovy.ast.ClassHelper.MAP_TYPE;
@@ -4100,8 +4099,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport
{
                 collectAllInterfaceMethodsByName(receiver, name, methods);
                 methods.addAll(OBJECT_TYPE.getMethods(name));
 
-                if (!receiver.getAnnotations(ClassHelper.FunctionalInterface_Type).isEmpty())
{
-                    methods.addAll(LAMBDA_TYPE.getDeclaredMethods("call"));
+                if (ClassHelper.isFunctionInterface(receiver)) {
+                    MethodNode sam = ClassHelper.findSAM(receiver);
+                    MethodNode callMethodNode = new MethodNode("call", sam.getModifiers(),
sam.getReturnType(), sam.getParameters(), sam.getExceptions(), sam.getCode());
+                    callMethodNode.setDeclaringClass(sam.getDeclaringClass());
+                    callMethodNode.setSourcePosition(sam);
+
+                    methods.addAll(Collections.singletonList(callMethodNode));
                 }
             }
             // TODO: investigate the trait exclusion a bit further, needed otherwise

http://git-wip-us.apache.org/repos/asf/groovy/blob/c24c0b7e/src/test/groovy/transform/stc/LambdaTest.groovy
----------------------------------------------------------------------
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 1a0b1ab..560ab77 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -403,8 +403,6 @@ TestScript0.groovy: 14: [Static type checking] - Cannot find matching
method jav
     }
 
     void testFunctionCall() {
-        if (SKIP_ERRORS) return
-
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -425,6 +423,73 @@ TestScript0.groovy: 14: [Static type checking] - Cannot find matching
method jav
         '''
     }
 
+    void testFunctionCall2() {
+        assertScript '''
+        import groovy.transform.CompileStatic
+        import java.util.stream.Collectors
+        import java.util.stream.Stream
+        import java.util.function.Function
+        
+        @CompileStatic
+        public class Test1 {
+            public static void main(String[] args) {
+                new Test1().p();
+            }
+        
+            public void p() {
+                Function<Integer, Integer> f = (Integer e) -> (Integer) (e + 1)
// Casting is required...  [Static type checking] - Incompatible generic argument types. Cannot
assign java.util.function.Function <java.lang.Integer, int> to: java.util.function.Function
<Integer, Integer>
+                assert 2 == f(1)
+            }
+        }
+        '''
+    }
+
+    void testConsumerCall() {
+        assertScript '''
+        import groovy.transform.CompileStatic
+        import java.util.stream.Collectors
+        import java.util.stream.Stream
+        import java.util.function.Consumer
+        
+        @CompileStatic
+        public class Test1 {
+            public static void main(String[] args) {
+                p();
+            }
+        
+            public static void p() {
+                int r = 1
+                Consumer<Integer> c = (Integer e) -> { r += e }
+                c(2)
+                assert 3 == r
+            }
+        }
+        '''
+    }
+
+    void testConsumerCall2() {
+        assertScript '''
+        import groovy.transform.CompileStatic
+        import java.util.stream.Collectors
+        import java.util.stream.Stream
+        import java.util.function.Consumer
+        
+        @CompileStatic
+        public class Test1 {
+            public static void main(String[] args) {
+                new Test1().p();
+            }
+        
+            public void p() {
+                int r = 1
+                Consumer<Integer> c = (Integer e) -> { r += e }
+                c(2)
+                assert 3 == r
+            }
+        }
+        '''
+    }
+
     void testFunctionWithUpdatingLocalVariable() {
         assertScript '''
         import groovy.transform.CompileStatic


Mime
View raw message