You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2018/02/02 03:07:30 UTC

groovy git commit: Refine the check of functional interface, which must be an interface

Repository: groovy
Updated Branches:
  refs/heads/native-lambda 91448dd1e -> 13eed82a7


Refine the check of functional interface, which must be an interface


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

Branch: refs/heads/native-lambda
Commit: 13eed82a7873052e763e8ecda33d417441ff2e8d
Parents: 91448dd
Author: sunlan <su...@apache.org>
Authored: Fri Feb 2 11:07:23 2018 +0800
Committer: sunlan <su...@apache.org>
Committed: Fri Feb 2 11:07:23 2018 +0800

----------------------------------------------------------------------
 .../org/codehaus/groovy/ast/ClassHelper.java    |  6 +++
 .../groovy/classgen/asm/InvocationWriter.java   |  2 +-
 .../asm/sc/StaticTypesLambdaWriter.java         |  2 +-
 .../stc/StaticTypeCheckingVisitor.java          |  2 +-
 src/test/groovy/transform/stc/LambdaTest.groovy | 50 ++++++++++++++++++++
 5 files changed, 59 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/13eed82a/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 93658d7..7ce72a3 100644
--- a/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/java/org/codehaus/groovy/ast/ClassHelper.java
@@ -395,6 +395,12 @@ public class ClassHelper {
         return findSAM(type) != null;
     }
 
+    public static boolean isFunctionalInterface(ClassNode type) {
+        // Functional interface must be an interface at first, or the following exception will occur:
+        // java.lang.invoke.LambdaConversionException: Functional interface SamCallable is not an interface
+        return type.isInterface() && 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/13eed82a/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 bc56b5a..6ab3fd9 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -494,7 +494,7 @@ public class InvocationWriter {
             return false;
         }
 
-        if (ClassHelper.isSAMType(objectExpression.getType())) {
+        if (ClassHelper.isFunctionalInterface(objectExpression.getType())) {
             return true;
         }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/13eed82a/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 60f8f7d..ab9d0f3 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
@@ -98,7 +98,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter {
     public void writeLambda(LambdaExpression expression) {
         ClassNode lambdaType = getLambdaType(expression);
 
-        if (!ClassHelper.isSAMType(lambdaType.redirect())) {
+        if (!ClassHelper.isFunctionalInterface(lambdaType.redirect())) {
             // if the parameter type is not real FunctionInterface, generate the default bytecode, which is actually a closure
             super.writeLambda(expression);
             return;

http://git-wip-us.apache.org/repos/asf/groovy/blob/13eed82a/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 e9ccffd..c3f0148 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -4121,7 +4121,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 collectAllInterfaceMethodsByName(receiver, name, methods);
                 methods.addAll(OBJECT_TYPE.getMethods(name));
 
-                if (CALL.equals(name) && ClassHelper.isSAMType(receiver)) {
+                if (CALL.equals(name) && ClassHelper.isFunctionalInterface(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());

http://git-wip-us.apache.org/repos/asf/groovy/blob/13eed82a/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 9bf9774..dc47754 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -534,6 +534,56 @@ TestScript0.groovy: 14: [Static type checking] - Cannot find matching method jav
         '''
     }
 
+    void testSamCall() {
+        assertScript '''
+        import groovy.transform.CompileStatic
+        import java.util.stream.Collectors
+        import java.util.stream.Stream
+        
+        @CompileStatic
+        public class Test1 {
+            public static void main(String[] args) {
+                p();
+            }
+            
+            public static void p() {
+                SamCallable c = (int e) -> e
+                assert 1 == c(1)
+            }
+        }
+        
+        @CompileStatic
+        interface SamCallable {
+            int call(int p);
+        }
+        '''
+    }
+
+    void testSamCall2() {
+        assertScript '''
+        import groovy.transform.CompileStatic
+        import java.util.stream.Collectors
+        import java.util.stream.Stream
+        
+        @CompileStatic
+        public class Test1 {
+            public static void main(String[] args) {
+                p();
+            }
+            
+            public static void p() {
+                SamCallable c = (int e) -> e // This is actually a closure(not a native lambda), because "Functional interface SamCallable is not an interface"
+                assert 1 == c(1)
+            }
+        }
+        
+        @CompileStatic
+        abstract class SamCallable {
+            abstract int call(int p);
+        }
+        '''
+    }
+
     void testFunctionWithUpdatingLocalVariable() {
         assertScript '''
         import groovy.transform.CompileStatic