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() - } }