Port native lambda to Java7

Just port its implementation and make the code can run on Java7, so when 
running on Java7, native lambda is still closure.


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

Branch: refs/heads/GROOVY_2_6_X
Commit: 727c89a39d6360bb905eac36a68515a78aa78d9c
Parents: af33df8
Author: danielsun1106 <realblue...@hotmail.com>
Authored: Sun Feb 18 13:00:36 2018 +0800
Committer: danielsun1106 <realblue...@hotmail.com>
Committed: Sun Feb 18 13:02:27 2018 +0800

----------------------------------------------------------------------
 .../codehaus/groovy/ast/CodeVisitorSupport.java |  5 ++
 .../codehaus/groovy/ast/GroovyCodeVisitor.java  |  4 +-
 .../groovy/classgen/asm/InvocationWriter.java   | 16 +++--
 .../asm/sc/StaticTypesLambdaWriter.java         | 30 +++++----
 .../customizers/SecureASTCustomizer.java        |  6 ++
 src/test/groovy/transform/stc/LambdaTest.groovy | 65 ++++++++++++++++++++
 6 files changed, 107 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java 
b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
index 523475e..e0b003d 100644
--- a/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
+++ b/src/main/java/org/codehaus/groovy/ast/CodeVisitorSupport.java
@@ -35,6 +35,7 @@ import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.FieldExpression;
 import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.LambdaExpression;
 import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
@@ -227,6 +228,10 @@ public abstract class CodeVisitorSupport implements 
GroovyCodeVisitor {
         expression.getCode().visit(this);
     }
 
+    public void visitLambdaExpression(LambdaExpression expression) {
+        visitClosureExpression(expression);
+    }
+
     public void visitTupleExpression(TupleExpression expression) {
         visitListOfExpressions(expression.getExpressions());
     }

http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
----------------------------------------------------------------------
diff --git a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java 
b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
index db793cc..f2f8027 100644
--- a/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
+++ b/src/main/java/org/codehaus/groovy/ast/GroovyCodeVisitor.java
@@ -139,9 +139,7 @@ public interface GroovyCodeVisitor {
 
     void visitClosureExpression(ClosureExpression expression);
 
-    default void visitLambdaExpression(LambdaExpression expression) {
-        visitClosureExpression(expression);
-    }
+    void visitLambdaExpression(LambdaExpression expression);
 
     void visitTupleExpression(TupleExpression expression);
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/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 6ab3fd9..b9c5b62 100644
--- a/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/java/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -32,6 +32,7 @@ import org.codehaus.groovy.ast.expr.ClassExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.SpreadExpression;
@@ -528,13 +529,18 @@ public class InvocationWriter {
         ClassNode type = call.getObjectExpression().getType();
         final MethodNode methodNode = ClassHelper.findSAM(type);
 
-        call = (MethodCallExpression) call.transformExpression(expression -> {
-            if (!(expression instanceof ConstantExpression)) {
-                return expression;
-            }
+        call = (MethodCallExpression) call.transformExpression(new 
ExpressionTransformer() {
+            @Override
+            public Expression transform(Expression expression) {
+                if (!(expression instanceof ConstantExpression)) {
+                    return expression;
+                }
 
-            return new ConstantExpression(methodNode.getName());
+                return new ConstantExpression(methodNode.getName());
+            }
         });
+
+
         call.setMethodTarget(methodNode);
         return call;
     }

http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/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 ab45f9c..6184181 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
@@ -42,6 +42,7 @@ import org.codehaus.groovy.classgen.asm.WriterController;
 import org.codehaus.groovy.classgen.asm.WriterControllerFactory;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
 import org.objectweb.asm.Handle;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
@@ -52,7 +53,6 @@ import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
-import java.util.stream.Collectors;
 
 import static 
org.codehaus.groovy.transform.stc.StaticTypesMarker.INFERRED_LAMBDA_TYPE;
 import static 
org.codehaus.groovy.transform.stc.StaticTypesMarker.PARAMETER_TYPE;
@@ -78,6 +78,7 @@ public class StaticTypesLambdaWriter extends LambdaWriter {
     public static final String IS_GENERATED_CONSTRUCTOR = 
"__IS_GENERATED_CONSTRUCTOR";
     public static final String LAMBDA_WRAPPER = "__lambda_wrapper";
     public static final String SAM_NAME = "__SAM_NAME";
+    private static final boolean PRE_JAVA8 = 
VMPluginFactory.getPlugin().getVersion() < 8;
     private StaticTypesClosureWriter staticTypesClosureWriter;
     private WriterController controller;
     private WriterControllerFactory factory;
@@ -98,8 +99,8 @@ public class StaticTypesLambdaWriter extends LambdaWriter {
     public void writeLambda(LambdaExpression expression) {
         ClassNode lambdaType = getLambdaType(expression);
 
-        if (!ClassHelper.isFunctionalInterface(lambdaType.redirect())) {
-            // if the parameter type is not real FunctionInterface, generate 
the default bytecode, which is actually a closure
+        if (PRE_JAVA8 || 
!ClassHelper.isFunctionalInterface(lambdaType.redirect())) {
+            // if running on pre8 JVM or the parameter type is not real 
FunctionInterface, generate the default bytecode, which is actually a closure
             super.writeLambda(expression);
             return;
         }
@@ -203,10 +204,14 @@ public class StaticTypesLambdaWriter extends LambdaWriter 
{
 
         loadSharedVariables(syntheticLambdaMethodNode);
 
-        List<ConstructorNode> constructorNodeList =
-                lambdaWrapperClassNode.getDeclaredConstructors().stream()
-                        .filter(e -> 
Boolean.TRUE.equals(e.getNodeMetaData(IS_GENERATED_CONSTRUCTOR)))
-                        .collect(Collectors.toList());
+        List<ConstructorNode> constructorNodeList = new LinkedList<>();
+        for (ConstructorNode e : 
lambdaWrapperClassNode.getDeclaredConstructors()) {
+            if 
(!Boolean.TRUE.equals(e.getNodeMetaData(IS_GENERATED_CONSTRUCTOR))) {
+                continue;
+            }
+
+            constructorNodeList.add(e);
+        }
 
         if (constructorNodeList.size() == 0) {
             throw new GroovyBugError("Failed to find the generated 
constructor");
@@ -268,16 +273,19 @@ public class StaticTypesLambdaWriter extends LambdaWriter 
{
                         
BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode),
                         lambdaClassNode.isInterface()
                 ),
-                
Type.getType(BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode.getReturnType(),
 
syntheticLambdaMethodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE)))
+                
Type.getType(BytecodeHelper.getMethodDescriptor(syntheticLambdaMethodNode.getReturnType(),
 (Parameter[]) 
syntheticLambdaMethodNode.getNodeMetaData(ORIGINAL_PARAMETERS_WITH_EXACT_TYPE)))
         };
     }
 
     private String createMethodDescriptor(MethodNode abstractMethodNode) {
+        List<Class> typeClassList = new LinkedList<>();
+        for (Parameter e : abstractMethodNode.getParameters()) {
+            typeClassList.add(e.getType().getTypeClass());
+        }
+
         return BytecodeHelper.getMethodDescriptor(
                 abstractMethodNode.getReturnType().getTypeClass(),
-                Arrays.stream(abstractMethodNode.getParameters())
-                        .map(e -> e.getType().getTypeClass())
-                        .toArray(Class[]::new)
+                typeClassList.toArray(new Class[0])
         );
     }
 

http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
----------------------------------------------------------------------
diff --git 
a/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
 
b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
index 1bb302b..c839e7e 100644
--- 
a/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
+++ 
b/src/main/java/org/codehaus/groovy/control/customizers/SecureASTCustomizer.java
@@ -42,6 +42,7 @@ import org.codehaus.groovy.ast.expr.ElvisOperatorExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.FieldExpression;
 import org.codehaus.groovy.ast.expr.GStringExpression;
+import org.codehaus.groovy.ast.expr.LambdaExpression;
 import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.expr.MapEntryExpression;
 import org.codehaus.groovy.ast.expr.MapExpression;
@@ -989,6 +990,11 @@ public class SecureASTCustomizer extends 
CompilationCustomizer {
             expression.getCode().visit(this);
         }
 
+        @Override
+        public void visitLambdaExpression(LambdaExpression expression) {
+            visitClosureExpression(expression);
+        }
+
         public void visitTupleExpression(final TupleExpression expression) {
             assertExpressionAuthorized(expression);
             visitListOfExpressions(expression.getExpressions());

http://git-wip-us.apache.org/repos/asf/groovy/blob/727c89a3/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 a24e3c1..0e2345f 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -19,10 +19,15 @@
 
 package groovy.transform.stc
 
+import org.codehaus.groovy.vmplugin.VMPluginFactory
+
 class LambdaTest extends GroovyTestCase {
     private static final boolean SKIP_ERRORS = true;
+    private static final boolean PRE_JAVA8 = 
VMPluginFactory.getPlugin().getVersion() < 8;
 
     void testFunction() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -42,6 +47,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionScript() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -57,6 +64,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testBinaryOperator() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -76,6 +85,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testConsumer() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -96,6 +107,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testPredicate() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -117,6 +130,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testUnaryOperator() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -138,6 +153,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testBiConsumer() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -158,6 +175,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithLocalVariables() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -179,6 +198,8 @@ class LambdaTest extends GroovyTestCase {
 
 
     void testFunctionWithLocalVariables2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -200,6 +221,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithLocalVariables4() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -221,6 +244,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithStaticMethodCall() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -246,6 +271,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithStaticMethodCall2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -271,6 +298,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithInstanceMethodCall() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -294,6 +323,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionInConstructor() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -317,6 +348,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithInstanceMethodCall2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -340,6 +373,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithInstanceMethodCall3() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -363,6 +398,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionCall() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -384,6 +421,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionCall2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -405,6 +444,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionCall3() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -426,6 +467,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testConsumerCall() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -449,6 +492,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testConsumerCall2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -472,6 +517,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testConsumerCall3() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -495,6 +542,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testSamCall() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -520,6 +569,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testSamCall2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -545,6 +596,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithUpdatingLocalVariable() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -566,6 +619,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithUpdatingLocalVariable2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -587,6 +642,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithVariableDeclaration() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -609,6 +666,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithMixingVariableDeclarationAndMethodInvocation() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -637,6 +696,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithNestedLambda() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -664,6 +725,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithNestedLambda2() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors
@@ -689,6 +752,8 @@ class LambdaTest extends GroovyTestCase {
     }
 
     void testFunctionWithNestedLambda3() {
+        if (PRE_JAVA8) return;
+
         assertScript '''
         import groovy.transform.CompileStatic
         import java.util.stream.Collectors

Reply via email to