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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5946717  GROOVY-10055: STC: handle raw type incl. self-referential 
type parameter
5946717 is described below

commit 5946717d13b6f8df8b6dfbc3edff902126304587
Author: Eric Milles <[email protected]>
AuthorDate: Mon Oct 18 12:36:47 2021 -0500

    GROOVY-10055: STC: handle raw type incl. self-referential type parameter
---
 src/main/groovy/groovy/grape/GrapeIvy.groovy       |  2 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   | 51 +++++++++++-----------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 29 ++++++++++++
 .../classgen/asm/sc/BugsStaticCompileTest.groovy   |  2 +-
 4 files changed, 57 insertions(+), 27 deletions(-)

diff --git a/src/main/groovy/groovy/grape/GrapeIvy.groovy 
b/src/main/groovy/groovy/grape/GrapeIvy.groovy
index 4bb7950..4afe525 100644
--- a/src/main/groovy/groovy/grape/GrapeIvy.groovy
+++ b/src/main/groovy/groovy/grape/GrapeIvy.groovy
@@ -594,7 +594,7 @@ class GrapeIvy implements GrapeEngine {
 
     URI[] resolve(ClassLoader loader, Map args, List depsInfo, Map... 
dependencies) {
         // check for mutually exclusive arguments
-        Set<String> keys = args.keySet()
+        Set<String> keys = (Set<String>) args.keySet()
         keys.each { key ->
             Set<String> badArgs = MUTUALLY_EXCLUSIVE_KEYS[key]
             if (badArgs && !badArgs.disjoint(keys)) {
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 3d051da..2fc0998 100644
--- 
a/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ 
b/src/main/java/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -5663,7 +5663,7 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
     }
 
     private static Map<GenericsTypeName, GenericsType> 
extractPlaceHolders(final MethodNode method, ClassNode receiver, final 
ClassNode declaringClass) {
-        Map<GenericsTypeName, GenericsType> resolvedPlaceholders = null;
+        Map<GenericsTypeName, GenericsType> resolvedPlaceHolders = null, 
currentPlaceHolders = new HashMap<>();
         if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
             receiver = getWrapper(receiver);
         }
@@ -5676,54 +5676,55 @@ public class StaticTypeCheckingVisitor extends 
ClassCodeVisitorSupport {
         for (ClassNode type : todo) {
             ClassNode current = type;
             while (current != null) {
-                boolean continueLoop = true;
-                // extract the place holders
-                Map<GenericsTypeName, GenericsType> currentPlaceHolders = new 
HashMap<>();
-                if (isGenericsPlaceHolderOrArrayOf(declaringClass) || 
declaringClass.equals(current)) {
+                currentPlaceHolders.clear();
+                // GROOVY-10055: handle diamond or raw
+                if (current.getGenericsTypes() != null
+                        ? current.getGenericsTypes().length == 0
+                        : current.redirect().getGenericsTypes() != null) {
+                    for (GenericsType gt : 
current.redirect().getGenericsTypes()) {
+                        ClassNode cn = gt.getUpperBounds() != null ? 
gt.getUpperBounds()[0] : gt.getType().redirect();
+                        currentPlaceHolders.put(new 
GenericsTypeName(gt.getName()), cn.getPlainNodeReference().asGenericsType());
+                    }
+                }
+
+                boolean currentIsDeclaring = current.equals(declaringClass) || 
isGenericsPlaceHolderOrArrayOf(declaringClass);
+                if (currentIsDeclaring) {
                     extractGenericsConnections(currentPlaceHolders, current, 
declaringClass);
-                    if (method != null) addMethodLevelDeclaredGenerics(method, 
currentPlaceHolders);
-                    continueLoop = false;
+                    if (method != null)
+                        addMethodLevelDeclaredGenerics(method, 
currentPlaceHolders);
                 } else {
                     GenericsUtils.extractPlaceholders(current, 
currentPlaceHolders);
                 }
 
-                if (resolvedPlaceholders != null) {
-                    // merge maps
+                if (resolvedPlaceHolders != null) { // merge maps
                     for (Map.Entry<GenericsTypeName, GenericsType> entry : 
currentPlaceHolders.entrySet()) {
                         GenericsType gt = entry.getValue();
                         if (!gt.isPlaceholder()) continue;
-                        GenericsType referenced = resolvedPlaceholders.get(new 
GenericsTypeName(gt.getName()));
+                        GenericsType referenced = resolvedPlaceHolders.get(new 
GenericsTypeName(gt.getName()));
                         if (referenced == null) continue;
                         entry.setValue(referenced);
                     }
                 }
-                resolvedPlaceholders = currentPlaceHolders;
+                resolvedPlaceHolders = currentPlaceHolders;
 
                 // we are done if we are now in the declaring class
-                if (!continueLoop) break;
+                if (currentIsDeclaring) break;
 
-                boolean isRawType = (current.getGenericsTypes() == null
-                        && current.redirect().getGenericsTypes() != null);
                 current = getNextSuperClass(current, declaringClass);
                 if (current == null && isClassType(declaringClass)) {
                     // this can happen if the receiver is Class<Foo>, then
                     // the actual receiver is Foo and declaringClass is Class
                     current = declaringClass;
-                } else if (isRawType) {
-                    current = current.getPlainNodeReference();
+                } else {
+                    current = applyGenericsContext(currentPlaceHolders, 
current);
                 }
             }
         }
-        if (resolvedPlaceholders == null) {
-            String descriptor = "<>";
-            if (method != null) descriptor = method.getTypeDescriptor();
-            throw new GroovyBugError(
-                    "Declaring class for method call to '" +
-                            descriptor + "' declared in " + 
declaringClass.getName() +
-                            " was not matched with found receiver " + 
receiver.getName() + "." +
-                            " This should not have happened!");
+        if (resolvedPlaceHolders == null) {
+            throw new GroovyBugError("Declaring class for method call to '" + 
(method != null ? method.getTypeDescriptor() : "<>") +
+                    "' declared in " + declaringClass.getName() + " was not 
matched with found receiver " + receiver.getName() + ". This should not have 
happened!");
         }
-        return resolvedPlaceholders;
+        return resolvedPlaceHolders;
     }
 
     protected boolean typeCheckMethodsWithGenericsOrFail(final ClassNode 
receiver, final ClassNode[] arguments, final MethodNode candidateMethod, final 
Expression location) {
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy 
b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index c49b4a6..259a8a9 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -3898,6 +3898,35 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase 
{
         }
     }
 
+    // GROOVY-10055
+    void testSelfReferentialTypeParameter2() {
+        assertScript '''
+            abstract class A<Self extends A<Self>> {
+                Self foo(inputs) {
+                    // ...
+                    this
+                }
+            }
+            abstract class B<Self extends B<Self>> extends A<Self> {
+                Self bar(inputs) {
+                    // ...
+                    this
+                }
+            }
+            class C<Self extends C<Self>> extends B<Self> { // see 
org.testcontainers.containers.PostgreSQLContainer
+                Self baz(inputs) {
+                    // ...
+                    this
+                }
+            }
+
+            new C<>()
+            .foo('x')
+            .bar('y') // error
+            .baz('z') // error
+        '''
+    }
+
     // GROOVY-7804
     void testParameterlessClosureToGenericSAMTypeArgumentCoercion() {
         assertScript '''
diff --git 
a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy 
b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
index 0377642..5576b16 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/BugsStaticCompileTest.groovy
@@ -1170,7 +1170,7 @@ assert it.next() == 1G
             @ASTTest(phase=INSTRUCTION_SELECTION, value={
                 def ift = node.getNodeMetaData(INFERRED_TYPE)
                 assert ift == SET_TYPE
-                assert ift.genericsTypes == null
+                assert ift.genericsTypes[0].type == OBJECT_TYPE
             })
             def set = map.keySet()
             def key = set[0]

Reply via email to