You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2022/06/26 14:39:38 UTC

[groovy] branch GROOVY_4_0_X updated: GROOVY-10153: resolve implicit wildcard bounding once type resolved

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

sunlan 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 e33edbe99d GROOVY-10153: resolve implicit wildcard bounding once type resolved
e33edbe99d is described below

commit e33edbe99d28212640168ed352cf9c6c035c1b43
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Thu Jun 23 15:27:33 2022 -0500

    GROOVY-10153: resolve implicit wildcard bounding once type resolved
    
    (cherry picked from commit 06dd5052edc621278cbc1114ffa593baaa3dc7b4)
---
 .../codehaus/groovy/control/ResolveVisitor.java    | 57 +++++++++++++++-------
 .../groovy/transform/stc/GenericsSTCTest.groovy    | 15 ++++++
 2 files changed, 55 insertions(+), 17 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
index b8d57537df..79e7c4fbec 100644
--- a/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/java/org/codehaus/groovy/control/ResolveVisitor.java
@@ -378,8 +378,11 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     }
 
     protected boolean resolve(final ClassNode type, final boolean testModuleImports, final boolean testDefaultImports, final boolean testStaticInnerClasses) {
-        resolveGenericsTypes(type.getGenericsTypes());
-        if (type.isResolved() || type.isPrimaryClassNode()) return true;
+        GenericsType[] genericsTypes = type.getGenericsTypes();
+        resolveGenericsTypes(genericsTypes);
+
+        if (type.isPrimaryClassNode()) return true;
+        if (type.isResolved()) return true;
         if (type.isArray()) {
             ClassNode element = type.getComponentType();
             boolean resolved = resolve(element, testModuleImports, testDefaultImports, testStaticInnerClasses);
@@ -390,30 +393,33 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             return resolved;
         }
 
-        // test if vanilla name is current class name
-        if (currentClass == type) return true;
-
         String typeName = type.getName();
 
-        GenericsType genericsType = genericParameterNames.get(new GenericsTypeName(typeName));
-        if (genericsType != null) {
-            type.setRedirect(genericsType.getType());
-            type.setGenericsTypes(new GenericsType[]{genericsType});
+        GenericsType typeParameter = genericParameterNames.get(new GenericsTypeName(typeName));
+        if (typeParameter != null) {
+            type.setRedirect(typeParameter.getType());
+            type.setGenericsTypes(new GenericsType[]{typeParameter});
             type.setGenericsPlaceHolder(true);
             return true;
         }
 
+        boolean resolved;
         if (currentClass.getNameWithoutPackage().equals(typeName)) {
             type.setRedirect(currentClass);
-            return true;
+            resolved = true;
+        } else {
+            resolved = (!type.hasPackageName() && resolveNestedClass(type))
+                    || resolveFromModule(type, testModuleImports)
+                    || resolveFromCompileUnit(type)
+                    || (testDefaultImports && !type.hasPackageName() && resolveFromDefaultImports(type))
+                    || resolveToOuter(type)
+                    || (testStaticInnerClasses && type.hasPackageName() && resolveFromStaticInnerClasses(type));
         }
-
-        return  (!type.hasPackageName() && resolveNestedClass(type)) ||
-                resolveFromModule(type, testModuleImports) ||
-                resolveFromCompileUnit(type) ||
-                (testDefaultImports && !type.hasPackageName() && resolveFromDefaultImports(type)) ||
-                resolveToOuter(type) ||
-                (testStaticInnerClasses && type.hasPackageName() && resolveFromStaticInnerClasses(type));
+        // GROOVY-10153: handle "C<? super T>"
+        if (resolved && genericsTypes != null) {
+            resolveWildcardBounding(genericsTypes, type);
+        }
+        return resolved;
     }
 
     protected boolean resolveNestedClass(final ClassNode type) {
@@ -1529,4 +1535,21 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
         return genericsType.isResolved();
     }
+
+    /**
+     * For cases like "Foo&lt;? super Bar> -> Foo&lt;T extends Baz>" there is an
+     * implicit upper bound on the wildcard type argument. It was unavailable at
+     * the time "? super Bar" was resolved but is present in type's redirect now.
+     */
+    private static void resolveWildcardBounding(final GenericsType[] typeArguments, final ClassNode type) {
+        for (int i = 0, n = typeArguments.length; i < n; i += 1) { GenericsType argument= typeArguments[i];
+            if (!argument.isWildcard() || argument.getUpperBounds() != null) continue;
+            GenericsType[] parameters = type.redirect().getGenericsTypes();
+            if (parameters != null && i < parameters.length) {
+                ClassNode implicitBound = parameters[i].getType();
+                if (!isObjectType(implicitBound))
+                    argument.getType().setRedirect(implicitBound);
+            }
+        }
+    }
 }
diff --git a/src/test/groovy/transform/stc/GenericsSTCTest.groovy b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
index 32c463ceb5..1cd5b77102 100644
--- a/src/test/groovy/transform/stc/GenericsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/GenericsSTCTest.groovy
@@ -2935,6 +2935,21 @@ class GenericsSTCTest extends StaticTypeCheckingTestCase {
         '''
     }
 
+    // GROOVY-10153
+    void testCompatibleArgumentsForPlaceholders11() {
+        ['A', 'B', 'C'].each { T ->
+            assertScript """
+                class A {}
+                class B extends A {}
+                class C extends B {}
+                class Foo<T extends A> {}
+
+                Foo<? super C> foo = new Foo<$T>()
+                //  ^ lower bound is C (explicit); upper bound is A (implicit)
+            """
+        }
+    }
+
     void testIncompatibleArgumentsForPlaceholders1() {
         shouldFailWithMessages '''
             def <T extends Number> T test(T one, T two) { }