You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2019/12/19 19:15:13 UTC

[groovy] branch GROOVY-9340 updated: GROOVY-9342: support I i = lambda/closure

This is an automated email from the ASF dual-hosted git repository.

emilles pushed a commit to branch GROOVY-9340
in repository https://gitbox.apache.org/repos/asf/groovy.git


The following commit(s) were added to refs/heads/GROOVY-9340 by this push:
     new bcbaa09  GROOVY-9342: support I<? super T> i = lambda/closure
bcbaa09 is described below

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

    GROOVY-9342: support I<? super T> i = lambda/closure
---
 .../codehaus/groovy/ast/tools/GenericsUtils.java   | 55 ++++++++++++----------
 src/test/groovy/transform/stc/LambdaTest.groovy    | 15 ++++++
 2 files changed, 45 insertions(+), 25 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..bc2eb13 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-9342
+    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 '''