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 <sun...@apache.org> Authored: Fri Feb 2 11:07:23 2018 +0800 Committer: sunlan <sun...@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