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 '''