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 72423b80f7 GROOVY-11192: STC: mapping between source and target type 
parameter(s)
72423b80f7 is described below

commit 72423b80f723c10ef05aedf1a7c38f3803b5ca39
Author: Eric Milles <eric.mil...@thomsonreuters.com>
AuthorDate: Mon Oct 23 07:52:09 2023 -0500

    GROOVY-11192: STC: mapping between source and target type parameter(s)
---
 .../transform/stc/StaticTypeCheckingVisitor.java   | 27 +++++--
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 88 ++++++++++++++++++++++
 2 files changed, 110 insertions(+), 5 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 1b8b69fb73..416ec43f44 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -1138,6 +1138,12 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 genericsTypes[i] = cn.getPlainNodeReference().asGenericsType();
             }
         } else {
+            // GROOVY-11192: mapping between source and target type 
parameter(s)
+            if (!source.equals(target)) {
+                assert source.isInterface() ? 
target.implementsInterface(source) : target.isDerivedFrom(source);
+                ClassNode mapped = adjustForTargetType(target, source);
+                genericsTypes = mapped.getGenericsTypes();
+            }
             genericsTypes = genericsTypes.clone();
             for (int i = 0, n = genericsTypes.length; i < n; i += 1) {
                 GenericsType gt = genericsTypes[i];
@@ -4294,13 +4300,24 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
                 // GROOVY-6126, GROOVY-6558, GROOVY-6564, et al.
                 if (!targetType.isGenericsPlaceHolder()) return targetType;
             } else {
-                // GROOVY-5640, GROOVY-9033, GROOVY-10220, GROOVY-10235, 
GROOVY-10688, et al.
+                // GROOVY-5640, GROOVY-9033, GROOVY-10220, GROOVY-10235, 
GROOVY-10688, GROOVY-11192, et al.
                 Map<GenericsTypeName, GenericsType> gt = new HashMap<>();
-                extractGenericsConnections(gt, resultType, 
resultType.redirect());
                 ClassNode sc = resultType;
-                do { sc = getNextSuperClass(sc, targetType);
-                } while (sc != null && !sc.equals(targetType));
-                extractGenericsConnections(gt, targetType, sc);
+                for (;;) {
+                    sc = getNextSuperClass(sc,targetType);
+                    if (!gt.isEmpty()) {
+                        // propagate resultType's generics
+                        sc = applyGenericsContext(gt, sc);
+                    }
+                    if (sc == null || sc.equals(targetType)) {
+                        gt.clear();
+                        break;
+                    }
+                    // map of sc's type vars to resultType's type vars
+                    extractGenericsConnections(gt, sc, sc.redirect());
+                }
+                extractGenericsConnections(gt, resultType, 
resultType.redirect());
+                extractGenericsConnections(gt, targetType, sc); // maps rt's 
tv(s)
 
                 return applyGenericsContext(gt, resultType.redirect());
             }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 414792cb1d..f35632bac0 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -1722,6 +1722,94 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase 
{
         '''
     }
 
+    // GROOVY-11192
+    void testDiamondInferenceFromConstructor38() {
+        assertScript '''
+            interface I<X,Y> {}
+            class C<Z> implements I<Number,Z> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<java.lang.String>'
+            })
+            I<Number,String> i = new C<>()
+        '''
+
+        assertScript '''
+            interface I<X,Y> {}
+            class C<Z> implements I<Z,String> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<java.lang.Number>'
+            })
+            I<Number,String> i = new C<>()
+        '''
+
+        assertScript '''
+            interface I<X,Y> {}
+            class C<Z> implements I<Z,Z> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<java.lang.String>'
+            })
+            I<String,String> i = new C<>()
+        '''
+
+        assertScript '''
+            interface I<X,Y> {}
+            class C<V,K> implements I<K,V> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<java.lang.String, 
java.lang.Number>'
+            })
+            I<Number,String> i = new C<>()
+        '''
+
+        assertScript '''
+            interface I<X,Y,Z> {}
+            abstract class A<K,V>
+                implements I<K,V,Short> {}
+            class C<T,U> extends A<U,T> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<java.lang.Long, 
java.lang.Integer>'
+            })
+            I<Integer,Long,Short> i = new C<>()
+        '''
+    }
+
+    void testDiamondInferenceFromConstructor39() {
+        // no relation between C's and I's type vars
+
+        assertScript '''
+            interface I<X,Y> {}
+            class C<Z> implements I<Number,String> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<Z>' // TODO: <> or <?>
+            })
+            I<Number,String> i = new C<>() // TODO: Should this be an error?
+        '''
+
+        assertScript '''
+            interface I<X,Y,Z> {}
+            abstract class A<K,V>
+                implements I<K,V,Short> {}
+            class C<T> extends A<Integer,Long> {}
+
+            @ASTTest(phase=INSTRUCTION_SELECTION, value={
+                def type = node.rightExpression.type
+                assert type.toString(false) == 'C<T>' // TODO: <> or <?>
+            })
+            I<Integer,Long,Short> i = new C<>() // TODO: Should this be an 
error?
+        '''
+    }
+
     // GROOVY-10280
     void testTypeArgumentPropagation() {
         assertScript '''

Reply via email to