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 100db21fc938440f9ed691c81c9847c7afad9232
Author: Daniel Sun <sun...@apache.org>
AuthorDate: Sat Mar 9 02:52:13 2019 +0800

    Clone the parameters to avoid impacting the original parameter type of SAM
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 84 ++++------------------
 ...StaticTypesMethodReferenceExpressionWriter.java |  6 +-
 src/test/groovy/transform/stc/LambdaTest.groovy    | 15 +++-
 .../groovy/ast/tools/GenericsUtilsTest.groovy      | 44 +-----------
 4 files changed, 34 insertions(+), 115 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java 
b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 7a68d35..b28771a 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -20,7 +20,6 @@ package org.codehaus.groovy.ast.tools;
 
 import antlr.RecognitionException;
 import antlr.TokenStreamException;
-import groovy.lang.Tuple;
 import groovy.lang.Tuple2;
 import groovy.transform.stc.IncorrectTypeHintException;
 import org.apache.groovy.util.SystemUtil;
@@ -961,82 +960,25 @@ public class GenericsUtils {
      */
     public static Tuple2<ClassNode[], ClassNode> parameterizeSAM(ClassNode 
sam) {
         MethodNode methodNode = ClassHelper.findSAM(sam);
-        return parameterizeMethodNode(methodNode, sam);
-    }
-
-    /**
-     * Get the parameter and return types of the specified method node
-     *
-     * @param parameterizedClassNode the class node which contains the 
specified method node
-     * @param methodNode the specified method node to parameterize
-     * @return the parameter and return types
-     * @since 3.0.0
-     */
-    public static Tuple2<ClassNode[], ClassNode> 
parameterizeMethodNode(MethodNode methodNode, ClassNode parameterizedClassNode) 
{
-        final Map<GenericsType, GenericsType> map = 
makeDeclaringAndActualGenericsTypeMapOfExactType(methodNode.getDeclaringClass(),
 parameterizedClassNode);
+        final Map<GenericsType, GenericsType> map = 
makeDeclaringAndActualGenericsTypeMapOfExactType(methodNode.getDeclaringClass(),
 sam);
 
         ClassNode[] parameterTypes =
                 Arrays.stream(methodNode.getParameters())
-                    .map(e -> findActualType(e.getType(), map))
+                    .map(e -> {
+                        ClassNode originalParameterType = e.getType();
+                        return originalParameterType.isGenericsPlaceHolder()
+                                ? 
findActualTypeByGenericsPlaceholderName(originalParameterType.getUnresolvedName(),
 map)
+                                : originalParameterType;
+                    })
                     .toArray(ClassNode[]::new);
 
-        ClassNode returnType = findActualType(methodNode.getReturnType(), map);
-        return tuple(parameterTypes, returnType);
-    }
-
-    private static ClassNode findActualType(ClassNode originalParameterType, 
Map<GenericsType, GenericsType> map) {
-        if (originalParameterType.isGenericsPlaceHolder()) {
-            return 
findActualTypeByGenericsPlaceholderName(originalParameterType.getUnresolvedName(),
 map);
-        }
-
-        if (null != originalParameterType.getGenericsTypes()) {
-            return findGenericsActualType(originalParameterType, map);
-        }
-
-        return originalParameterType;
-    }
+        ClassNode originalReturnType = methodNode.getReturnType();
+        ClassNode returnType =
+                originalReturnType.isGenericsPlaceHolder()
+                        ? 
findActualTypeByGenericsPlaceholderName(originalReturnType.getUnresolvedName(), 
map)
+                        : originalReturnType;
 
-    private static ClassNode findGenericsActualType(ClassNode 
classNodeWithGenerics, Map<GenericsType, GenericsType> map) {
-        Tuple2<ClassNode, Boolean> genericsActualTypeTuple = 
doFindGenericsActualType(classNodeWithGenerics, map);
-        return genericsActualTypeTuple.getV1();
-    }
-
-    private static Tuple2<ClassNode, Boolean> 
doFindGenericsActualType(ClassNode classNodeWithGenerics, Map<GenericsType, 
GenericsType> map) {
-        GenericsType[] genericsTypes = 
classNodeWithGenerics.getGenericsTypes();
-        if (null != genericsTypes) {
-            List<GenericsType> newGenericsTypeList = new LinkedList<>();
-            boolean hasPlaceHolders = false;
-            for (GenericsType gt : genericsTypes) {
-                ClassNode type;
-                if (gt.isPlaceholder()) {
-                    type = 
findActualTypeByGenericsPlaceholderName(gt.getType().getUnresolvedName(), map);
-                    hasPlaceHolders = true;
-                } else {
-                    Tuple2<ClassNode, Boolean> genericsActualTypeTuple = 
doFindGenericsActualType(gt.getType(), map);
-                    type = genericsActualTypeTuple.getV1();
-                    hasPlaceHolders = genericsActualTypeTuple.getV2();
-                }
-
-                if (null == type) { // TODO handle method generics, e.g. 
Stream.map
-                    return Tuple.tuple(classNodeWithGenerics, hasPlaceHolders);
-                }
-
-                GenericsType genericsType = new GenericsType(type);
-                genericsType.setSourcePosition(gt);
-                newGenericsTypeList.add(genericsType);
-            }
-
-            if (hasPlaceHolders) {
-                ClassNode newClassNodeWithGenerics = 
ClassHelper.makeWithoutCaching(classNodeWithGenerics.getTypeClass(), false);
-                
newClassNodeWithGenerics.setGenericsTypes(newGenericsTypeList.toArray(GenericsType.EMPTY_ARRAY));
-                
newClassNodeWithGenerics.setRedirect(classNodeWithGenerics.redirect());
-                
newClassNodeWithGenerics.setSourcePosition(classNodeWithGenerics);
-
-                return Tuple.tuple(newClassNodeWithGenerics, true);
-            }
-        }
-
-        return Tuple.tuple(classNodeWithGenerics, false);
+        return tuple(parameterTypes, returnType);
     }
 
     /**
diff --git 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
index 20a3d63..a64b604 100644
--- 
a/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
+++ 
b/src/main/java/org/codehaus/groovy/classgen/asm/sc/StaticTypesMethodReferenceExpressionWriter.java
@@ -24,6 +24,7 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.MethodReferenceExpression;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
 import org.codehaus.groovy.ast.tools.ParameterUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.classgen.asm.MethodReferenceExpressionWriter;
@@ -83,7 +84,10 @@ public class StaticTypesMethodReferenceExpressionWriter 
extends MethodReferenceE
     }
 
     private Parameter[] createParametersWithExactType(MethodNode 
abstractMethodNode, ClassNode[] inferredParameterTypes) {
-        Parameter[] parameters = abstractMethodNode.getParameters();
+        Parameter[] originalParameters = abstractMethodNode.getParameters();
+
+        // We MUST clone the parameters to avoid impacting the original 
parameter type of SAM
+        Parameter[] parameters = GeneralUtils.cloneParams(originalParameters);
         if (parameters == null) {
             parameters = Parameter.EMPTY_ARRAY;
         }
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy 
b/src/test/groovy/transform/stc/LambdaTest.groovy
index 7bf7fff..24cb562 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -892,5 +892,18 @@ class LambdaTest extends GroovyTestCase {
         '''
     }
 
-
+    void testMixingLambdaAndMethodReference() {
+        assertScript '''
+            import java.util.stream.Collectors
+            
+            @groovy.transform.CompileStatic
+            void p() {
+                assert ['1', '2', '3'] == [1, 2, 
3].stream().map(Object::toString).collect(Collectors.toList())
+                assert [2, 3, 4] == [1, 2, 3].stream().map(e -> e.plus 
1).collect(Collectors.toList())
+                assert ['1', '2', '3'] == [1, 2, 
3].stream().map(Object::toString).collect(Collectors.toList())
+            }
+            
+            p()
+        '''
+    }
 }
diff --git a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy 
b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
index 8484648..1373f4f 100644
--- a/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/GenericsUtilsTest.groovy
@@ -22,12 +22,13 @@ package org.codehaus.groovy.ast.tools
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
 import org.codehaus.groovy.ast.GenericsType
-import org.codehaus.groovy.ast.MethodNode
 import org.codehaus.groovy.control.CompilationUnit
 import org.codehaus.groovy.control.Phases
 
 import java.util.function.BiFunction
 
+import static groovy.lang.Tuple.tuple
+
 class GenericsUtilsTest extends GroovyTestCase {
     void testFindParameterizedType1() {
         def code = '''
@@ -320,45 +321,4 @@ class GenericsUtilsTest extends GroovyTestCase {
         assert ClassHelper.Integer_TYPE == typeInfo.getV1()[1]
         assert ClassHelper.Integer_TYPE == typeInfo.getV2()
     }
-
-    void testParameterizeMethodNode() {
-        def code = '''
-        import java.util.function.*
-        interface T extends Function<String, Integer> {}
-        '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode parameterizedClassNode = findClassNode('T', 
classNodeList).getAllInterfaces().find { 
it.name.equals('java.util.function.Function') }
-        MethodNode methodNode = parameterizedClassNode.getMethods('apply')[0]
-        Tuple2<ClassNode[], ClassNode> typeInfo = 
GenericsUtils.parameterizeMethodNode(methodNode, parameterizedClassNode)
-        assert 1 == typeInfo.getV1().length
-        assert ClassHelper.STRING_TYPE == typeInfo.getV1()[0]
-        assert ClassHelper.Integer_TYPE == typeInfo.getV2()
-    }
-
-    void testParameterizeMethodNode2() {
-        def code = '''
-        import java.util.stream.*
-        interface T extends Stream<Integer> {}
-        '''
-        def ast = new CompilationUnit().tap {
-            addSource 'hello.groovy', code
-            compile Phases.SEMANTIC_ANALYSIS
-        }.ast
-
-        def classNodeList = ast.getModules()[0].getClasses()
-        ClassNode parameterizedClassNode = findClassNode('T', 
classNodeList).getAllInterfaces().find { 
it.name.equals('java.util.stream.Stream') }
-        MethodNode methodNode = parameterizedClassNode.getMethods('reduce')[0]
-        Tuple2<ClassNode[], ClassNode> typeInfo = 
GenericsUtils.parameterizeMethodNode(methodNode, parameterizedClassNode)
-//        println typeInfo
-        assert 2 == typeInfo.getV1().length
-        assert ClassHelper.Integer_TYPE == typeInfo.getV1()[0]
-        assert ClassHelper.make(java.util.function.BinaryOperator) == 
typeInfo.getV1()[1]
-        assert ClassHelper.Integer_TYPE == 
typeInfo.getV1()[1].getGenericsTypes()[0].getType()
-        assert ClassHelper.Integer_TYPE == typeInfo.getV2()
-    }
 }

Reply via email to