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 2019/12/20 10:10:03 UTC
[groovy] 02/02: GROOVY-9347: STC: support "I super T> i =
lambda/closure"
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 4b50ac20ac37960d25896d861a55d1693d3cf891
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Dec 19 13:14:37 2019 -0600
GROOVY-9347: STC: support "I<? super T> i = lambda/closure"
---
.../codehaus/groovy/ast/tools/GenericsUtils.java | 55 ++++++++++++----------
src/test/groovy/transform/stc/LambdaTest.groovy | 17 ++++++-
2 files changed, 46 insertions(+), 26 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 3ce6be7..19261e7 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -48,6 +48,7 @@ import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
+import java.util.function.Function;
import java.util.function.Predicate;
import static groovy.lang.Tuple.tuple;
@@ -925,7 +926,7 @@ public class GenericsUtils {
}
/**
- * Get the parameter and return types of the abstract method of SAM
+ * Gets the parameter and return types of the abstract method of SAM.
*
* If the abstract method is not parameterized, we will get generics placeholders, e.g. T, U
* For example, the abstract method of {@link java.util.function.Function} is
@@ -942,31 +943,23 @@ public class GenericsUtils {
* we can get parameter types and return type of the above abstract method,
* i.e. ClassNode {@code ClassHelper.STRING_TYPE} and {@code ClassHelper.Integer_TYPE}
*
- * @param sam the class node which contains only one abstract method
- * @return the parameter and return types
- * @since 3.0.0
+ * @param samType the class node which contains only one abstract method
*
+ * @since 3.0.0
*/
- public static Tuple2<ClassNode[], ClassNode> parameterizeSAM(ClassNode sam) {
- MethodNode methodNode = ClassHelper.findSAM(sam);
- final Map<GenericsType, GenericsType> map = makeDeclaringAndActualGenericsTypeMapOfExactType(methodNode.getDeclaringClass(), sam);
-
- ClassNode[] parameterTypes =
- Arrays.stream(methodNode.getParameters())
- .map(e -> {
- ClassNode originalParameterType = e.getType();
- return originalParameterType.isGenericsPlaceHolder()
- ? findActualTypeByGenericsPlaceholderName(originalParameterType.getUnresolvedName(), map)
- : originalParameterType;
- })
- .toArray(ClassNode[]::new);
-
- ClassNode originalReturnType = methodNode.getReturnType();
- ClassNode returnType =
- originalReturnType.isGenericsPlaceHolder()
- ? findActualTypeByGenericsPlaceholderName(originalReturnType.getUnresolvedName(), map)
- : originalReturnType;
+ public static Tuple2<ClassNode[], ClassNode> parameterizeSAM(final ClassNode samType) {
+ MethodNode abstractMethod = ClassHelper.findSAM(samType);
+
+ Map<GenericsType, GenericsType> generics = makeDeclaringAndActualGenericsTypeMapOfExactType(abstractMethod.getDeclaringClass(), samType);
+ Function<ClassNode, ClassNode> resolver = t -> {
+ if (t.isGenericsPlaceHolder()) {
+ return findActualTypeByGenericsPlaceholderName(t.getUnresolvedName(), generics);
+ }
+ return t;
+ };
+ ClassNode[] parameterTypes = Arrays.stream(abstractMethod.getParameters()).map(Parameter::getType).map(resolver).toArray(ClassNode[]::new);
+ ClassNode returnType = resolver.apply(abstractMethod.getReturnType());
return tuple(parameterTypes, returnType);
}
@@ -977,9 +970,21 @@ public class GenericsUtils {
* @param genericsPlaceholderAndTypeMap the result of {@link #makeDeclaringAndActualGenericsTypeMap(ClassNode, ClassNode)}
*/
public static ClassNode findActualTypeByGenericsPlaceholderName(final String placeholderName, final Map<GenericsType, GenericsType> genericsPlaceholderAndTypeMap) {
+ Function<GenericsType, ClassNode> resolver = gt -> {
+ if (gt.isWildcard()) {
+ if (gt.getLowerBound() != null) {
+ return gt.getLowerBound();
+ }
+ if (gt.getUpperBounds() != null) {
+ return gt.getUpperBounds()[0];
+ }
+ }
+ return gt.getType();
+ };
+
return genericsPlaceholderAndTypeMap.entrySet().stream()
- .filter(entry -> entry.getKey().getName().equals(placeholderName))
- .map(entry -> entry.getValue().getType()).findFirst().orElse(null);
+ .filter(e -> e.getKey().getName().equals(placeholderName))
+ .map(Map.Entry::getValue).map(resolver).findFirst().orElse(null);
}
private static class ParameterizedTypeCacheKey {
diff --git a/src/test/groovy/transform/stc/LambdaTest.groovy b/src/test/groovy/transform/stc/LambdaTest.groovy
index 4b2960b..0f33f84 100644
--- a/src/test/groovy/transform/stc/LambdaTest.groovy
+++ b/src/test/groovy/transform/stc/LambdaTest.groovy
@@ -741,6 +741,21 @@ final class LambdaTest {
'''
}
+ @Test // GROOVY-9347
+ void testConsumer7() {
+ assertScript '''
+ @groovy.transform.CompileStatic
+ void test() {
+ int sum = 0
+ java.util.function.Consumer<? super Integer> add = i -> sum += i
+
+ [1, 2, 3].forEach(add)
+ assert sum == 6
+ }
+ test()
+ '''
+ }
+
@Test
void testFunctionalInterface1() {
assertScript '''
@@ -1066,7 +1081,7 @@ final class LambdaTest {
'''
}
- @Test @NotYetImplemented // GROOVY-9342
+ @Test @NotYetImplemented // GROOVY-9347
void testStaticInitializeBlocks2() {
assertScript '''
@groovy.transform.CompileStatic