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 2022/06/17 14:11:23 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-10436: STC: closure parameter as type witness for SAM-type target

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

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


The following commit(s) were added to refs/heads/GROOVY_4_0_X by this push:
     new 8635ff87ea GROOVY-10436: STC: closure parameter as type witness for SAM-type target
8635ff87ea is described below

commit 8635ff87ea52ebe5fe962fa64faaa33e86a5a66f
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jun 16 15:32:35 2022 -0500

    GROOVY-10436: STC: closure parameter as type witness for SAM-type target
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 10 ++-
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 72 +++++++++++++---------
 2 files changed, 52 insertions(+), 30 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index b4a14fc16f..bebfef2e1c 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -2965,11 +2965,19 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     // check for implicit type arguments
                     int i = -1; Parameter[] p = method.getParameters();
                     for (Expression argument : (ArgumentListExpression) arguments) { i += 1;
-                        if (argument instanceof ClosureExpression || isNullConstant(argument)) continue;
+                        if (isNullConstant(argument)) continue;
 
                         ClassNode pType = p[Math.min(i, p.length - 1)].getType();
                         Map<GenericsTypeName, GenericsType> gc = new HashMap<>();
                         extractGenericsConnections(gc, wrapTypeIfNecessary(getType(argument)), pType);
+                        // GROOVY-10436: extract generics connections from closure parameter declaration(s)
+                        if (argument == expression || (argument instanceof ClosureExpression && isSAMType(pType))) {
+                            Parameter[] q = getParametersSafe((ClosureExpression) argument);
+                            ClassNode[] r = extractTypesFromParameters(q); // maybe typed
+                            ClassNode[] s = GenericsUtils.parameterizeSAM(pType).getV1();
+                            for (int j = 0; j < r.length && j < s.length; j += 1)
+                                if (!q[j].isDynamicTyped()) extractGenericsConnections(gc, r[j], s[j]);
+                        }
 
                         gc.forEach((key, gt) -> {
                             for (GenericsType tp : typeParameters) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 47f9297329..7776a15992 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2498,7 +2498,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
             r.bindings2['a'] = 'A'
             r.bindings2.put('b', 'B')
-
         '''
     }
     void testInferDiamondForAssignment() {
@@ -3604,30 +3603,30 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
     void testReturnTypeInferenceWithClosure() {
         assertScript '''import org.codehaus.groovy.ast.expr.ClosureExpression
             class CTypeTest {
-              public static void test1(String[] args) {
-                // Cannot assign value of type java.lang.Object to variable of type CTypeTest
-                @ASTTest(phase=INSTRUCTION_SELECTION,value={
-                    def cl = node.rightExpression.arguments[0]
-                    assert cl instanceof ClosureExpression
-                    def type = cl.getNodeMetaData(INFERRED_TYPE)
-                    assert type == make(Closure)
-                    assert type.isUsingGenerics()
-                    assert type.genericsTypes
-                    assert type.genericsTypes[0].type.name == 'CTypeTest'
-
-                    type = node.getNodeMetaData(INFERRED_TYPE)
-                    assert type.name == 'CTypeTest'
-                })
-                def s1 = cache  {
-                  return new CTypeTest();
+                static test(String[] args) {
+                    // Cannot assign value of type Object to variable of type CTypeTest
+                    @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                        def cl = node.rightExpression.arguments[0]
+                        assert cl instanceof ClosureExpression
+                        def type = cl.getNodeMetaData(INFERRED_TYPE)
+                        assert type == make(Closure)
+                        assert type.isUsingGenerics()
+                        assert type.genericsTypes
+                        assert type.genericsTypes[0].type.name == 'CTypeTest'
+
+                        type = node.getNodeMetaData(INFERRED_TYPE)
+                        assert type.name == 'CTypeTest'
+                    })
+                    def s1 = cache {
+                        new CTypeTest()
+                    }
+                    CTypeTest s2 = cache {
+                        new CTypeTest()
+                    }
                 }
-                CTypeTest s2 = cache {
-                    new CTypeTest()
+                static <T> T cache(Closure<T> closure) {
+                    return closure.call();
                 }
-              }
-              static <T> T cache(Closure<T> closure) {
-                return closure.call();
-              }
             }
             1
         '''
@@ -3638,7 +3637,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         assertScript '''
             import java.util.function.Function
             class C {
-                final <T> T m(Function<Reader,T> function)  {
+                def <T> T m(Function<Reader,T> function)  {
                     new StringReader("").withCloseable { reader ->
                         function.apply(reader)
                     }
@@ -3650,6 +3649,25 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10436
+    void testReturnTypeInferenceWithClosure3() {
+        String method = '''import java.util.function.BiConsumer
+
+            def <T> BiConsumer<String, List<T>> m(BiConsumer<String, ? super T> consumer) {
+                return (String text, List<T> list) -> {
+                    for (T item : list) consumer.accept(text, item)
+                }
+            }
+        '''
+        assertScript method + '''
+            this.<Number>m { string, number -> number.toBigDecimal() }
+        '''
+        assertScript method + '''
+            // the only type witness for T is the closure parameter
+            m { string, Number number -> number.toBigDecimal() }
+        '''
+    }
+
     // GROOVY-6129
     void testShouldNotThrowNPE() {
         assertScript '''
@@ -4019,7 +4037,7 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
-    //GROOVY-6723, GROOVY-6415
+    // GROOVY-6723, GROOVY-6415
     void testIndirectMethodLevelGenerics() {
         assertScript '''
             class C1<A> {
@@ -4087,10 +4105,6 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
 
     void testConcreteTypeInsteadOfGenerifiedInterface() {
         assertScript '''
-            import groovy.transform.ASTTest
-            import static org.codehaus.groovy.transform.stc.StaticTypesMarker.*
-            import static org.codehaus.groovy.ast.ClassHelper.*
-
             interface Converter<F, T> {
             T convertC(F from)
             }