groovy-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From sun...@apache.org
Subject [groovy] 02/04: GROOVY-9347: STC: support "I<? super T> i = lambda/closure"
Date Fri, 20 Dec 2019 17:36:13 GMT
This is an automated email from the ASF dual-hosted git repository.

sunlan pushed a commit to branch GROOVY_3_0_X
in repository https://gitbox.apache.org/repos/asf/groovy.git

commit d5745ad97d80aabe52b412e460e3c398992f6dd4
Author: Eric Milles <eric.milles@thomsonreuters.com>
AuthorDate: Thu Dec 19 13:14:37 2019 -0600

    GROOVY-9347: STC: support "I<? super T> i = lambda/closure"
    
    (cherry picked from commit 4b50ac20ac37960d25896d861a55d1693d3cf891)
---
 .../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 0cc25c9..07d0262 100644
--- a/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/java/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -49,6 +49,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;
@@ -926,7 +927,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
@@ -943,31 +944,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);
     }
 
@@ -978,9 +971,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


Mime
View raw message