You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by pa...@apache.org on 2021/04/10 23:37:27 UTC

[groovy] 01/02: GROOVY-9996: infer return type generics using declared type of variables (port to 3_0_X)

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

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

commit e538c6f6a9edfae2e1651361d2652943b7467b23
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Tue Mar 23 10:20:45 2021 -0500

    GROOVY-9996: infer return type generics using declared type of variables (port to 3_0_X)
---
 .../groovy/transform/stc/StaticTypeCheckingVisitor.java | 10 +++++++++-
 src/test/groovy/transform/stc/GenericsSTCTest.groovy    | 17 +++++++++++++++++
 2 files changed, 26 insertions(+), 1 deletion(-)

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 5d4bc3f..e025180 100644
--- a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5183,7 +5183,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             for (int i = 0; i < paramLength; i += 1) {
                 boolean lastArg = (i == paramLength - 1);
                 ClassNode paramType = parameters[i].getType();
-                ClassNode argumentType = getType(expressions.get(i));
+                ClassNode argumentType = getDeclaredOrInferredType(expressions.get(i));
                 while (paramType.isArray() && argumentType.isArray()) {
                     paramType = paramType.getComponentType();
                     argumentType = argumentType.getComponentType();
@@ -5446,6 +5446,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return resolveClassNodeGenerics(resolvedPlaceholders, placeholdersFromContext, currentType);
     }
 
+    private ClassNode getDeclaredOrInferredType(final Expression expression) {
+        // in case of "T t = new ExtendsOrImplementsT()", return T for the expression type
+        if (expression instanceof Variable && !((Variable) expression).isDynamicTyped()) {
+            return getOriginalDeclarationType(expression); // GROOVY-9996
+        }
+        return getInferredTypeFromTempInfo(expression, getType(expression));
+    }
+
     private static ClassNode getDeclaringClass(final MethodNode method, final Expression arguments) {
         ClassNode declaringClass = method.getDeclaringClass();
 
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 2c0b7bd..b5020e3 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -196,6 +196,23 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-9996
+    void testDiamondInferrenceFromConstructor8a() {
+        assertScript '''
+            @groovy.transform.TupleConstructor(defaults=false)
+            class C<T> {
+                T p
+            }
+            interface I { }
+            class D implements I { }
+            void test(C<I> c) { assert c.p instanceof D }
+
+            I i = new D() // infers D for "i"
+            def ci = new C<>(i) // infers C<D> for "ci"
+            test(ci)
+        '''
+    }
+
     void testLinkedListWithListArgument() {
         assertScript '''
             List<String> list = new LinkedList<String>(['1','2','3'])