You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by em...@apache.org on 2023/08/25 14:18:37 UTC

[groovy] 01/02: GROOVY-10756: fix erasure (like `ResolveVisitor#resolveGenericsHeader`)

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

commit f5bb31c4b6709b2e7a850dc380bfab712ccc1cb8
Author: Eric Milles <er...@thomsonreuters.com>
AuthorDate: Fri Aug 25 08:22:33 2023 -0500

    GROOVY-10756: fix erasure (like `ResolveVisitor#resolveGenericsHeader`)
---
 .../groovy/ast/decompiled/TypeSignatureParser.java | 10 +--
 .../org/codehaus/groovy/vmplugin/v8/Java8.java     | 73 +++++++++++-----------
 .../stc/ClosureParamTypeInferenceSTCTest.groovy    |  5 ++
 .../groovy/ast/decompiled/AsmDecompilerTest.groovy | 15 +++--
 4 files changed, 54 insertions(+), 49 deletions(-)

diff --git a/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
index fd9b38e9c3..c623f61b79 100644
--- a/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
+++ b/src/main/java/org/codehaus/groovy/ast/decompiled/TypeSignatureParser.java
@@ -121,11 +121,11 @@ abstract class TypeSignatureParser extends SignatureVisitor {
                 try {
                     // GROOVY-10153, GROOVY-10651, GROOVY-10671: "?" or "? super T" (see ResolveVisitor#resolveWildcardBounding)
                     for (int i = 0, n = arguments.size(); i < n; i += 1) { GenericsType argument = arguments.get(i);
-                    if (!argument.isWildcard() || argument.getUpperBounds() != null) continue; //
-                    ClassNode[] implicitBounds = baseType.getGenericsTypes()[i].getUpperBounds();
-                    if (implicitBounds != null && !ClassHelper.isObjectType(implicitBounds[0])) {
-                        argument.getType().setRedirect(implicitBounds[0]); // bound is not Object
-                    }
+                        if (!argument.isWildcard() || argument.getUpperBounds() != null) continue; //
+                        ClassNode[] implicitBounds = baseType.getGenericsTypes()[i].getUpperBounds();
+                        if (implicitBounds != null && !ClassHelper.isObjectType(implicitBounds[0])) {
+                            argument.getType().setRedirect(implicitBounds[0]); // bound is not Object
+                        }
                     }
                 } catch (StackOverflowError ignore) {
                     // TODO: self-referential type parameter
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
index 31d66923cf..9fa4d5cd6d 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v8/Java8.java
@@ -59,6 +59,7 @@ import java.lang.reflect.Field;
 import java.lang.reflect.GenericArrayType;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.MalformedParameterizedTypeException;
+import java.lang.reflect.Member;
 import java.lang.reflect.Method;
 import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.ReflectPermission;
@@ -83,14 +84,16 @@ public class Java8 implements VMPlugin {
     private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
     private static final Permission ACCESS_PERMISSION = new ReflectPermission("suppressAccessChecks");
 
-    public static GenericsType configureTypeVariableDefinition(final ClassNode base, final ClassNode[] cBounds) {
+    public static GenericsType configureTypeVariableDefinition(final ClassNode base, final ClassNode[] bounds) {
         ClassNode redirect = base.redirect();
         base.setRedirect(null);
         GenericsType gt;
-        if (cBounds == null || cBounds.length == 0) {
+        if (bounds == null || bounds.length == 0) {
             gt = new GenericsType(base);
         } else {
-            gt = new GenericsType(base, cBounds, null);
+            // GROOVY-10756: fix erasure -- ResolveVisitor#resolveGenericsHeader
+            if (!ClassHelper.isObjectType(bounds[0])) redirect = bounds[0];
+            gt = new GenericsType(base, bounds, null);
             gt.setName(base.getName());
             gt.setPlaceholder(true);
         }
@@ -98,25 +101,25 @@ public class Java8 implements VMPlugin {
         return gt;
     }
 
-    private static ClassNode configureClass(final Class<?> c) {
-        if (c.isPrimitive()) {
-            return ClassHelper.make(c);
-        } else {
-            return ClassHelper.makeWithoutCaching(c, false);
-        }
-    }
-
     public static ClassNode configureTypeVariableReference(final String name) {
         ClassNode cn = ClassHelper.makeWithoutCaching(name);
         cn.setGenericsPlaceHolder(true);
         ClassNode cn2 = ClassHelper.makeWithoutCaching(name);
         cn2.setGenericsPlaceHolder(true);
-        GenericsType[] gts = new GenericsType[]{new GenericsType(cn2)};
-        cn.setGenericsTypes(gts);
+
+        cn.setGenericsTypes(new GenericsType[]{new GenericsType(cn2)});
         cn.setRedirect(ClassHelper.OBJECT_TYPE);
         return cn;
     }
 
+    private static ClassNode configureClass(final Class<?> c) {
+        if (c.isPrimitive()) {
+            return ClassHelper.make(c);
+        } else {
+            return ClassHelper.makeWithoutCaching(c, false);
+        }
+    }
+
     private static void setRetentionPolicy(final RetentionPolicy value, final AnnotationNode node) {
         switch (value) {
           case RUNTIME:
@@ -152,27 +155,7 @@ public class Java8 implements VMPlugin {
 
     @Override
     public void setAdditionalClassInformation(final ClassNode cn) {
-        setGenericsTypes(cn);
-    }
-
-    private void setGenericsTypes(final ClassNode cn) {
-        TypeVariable[] tvs = cn.getTypeClass().getTypeParameters();
-        GenericsType[] gts = configureTypeVariable(tvs);
-        cn.setGenericsTypes(gts);
-    }
-
-    private GenericsType[] configureTypeVariable(final TypeVariable[] tvs) {
-        final int n = tvs.length;
-        if (n == 0) return null;
-        GenericsType[] gts = new GenericsType[n];
-        for (int i = 0; i < n; i += 1) {
-            gts[i] = configureTypeVariableDefinition(tvs[i]);
-        }
-        return gts;
-    }
-
-    private GenericsType configureTypeVariableDefinition(final TypeVariable tv) {
-        return configureTypeVariableDefinition(configureTypeVariableReference(tv.getName()), configureTypes(tv.getBounds()));
+        cn.setGenericsTypes(configureTypeParameters(cn.getTypeClass().getTypeParameters()));
     }
 
     private ClassNode[] configureTypes(final Type[] types) {
@@ -193,7 +176,7 @@ public class Java8 implements VMPlugin {
         } else if (type instanceof GenericArrayType) {
             return configureGenericArray((GenericArrayType) type);
         } else if (type instanceof TypeVariable) {
-            return configureTypeVariableReference(((TypeVariable) type).getName());
+            return configureTypeVariableReference(((TypeVariable<?>) type).getName());
         } else if (type instanceof Class) {
             return configureClass((Class<?>) type);
         } else if (type == null) {
@@ -251,6 +234,18 @@ public class Java8 implements VMPlugin {
         return gts;
     }
 
+    private GenericsType[] configureTypeParameters(final TypeVariable<?>[] tp) {
+        final int n = tp.length;
+        if (n == 0) return null;
+        GenericsType[] gt = new GenericsType[n];
+        for (int i = 0; i < n; i += 1) {
+            ClassNode t = configureTypeVariableReference(tp[i].getName());
+            ClassNode[] bounds = configureTypes(tp[i].getBounds());
+            gt[i] = configureTypeVariableDefinition(t, bounds);
+        }
+        return gt;
+    }
+
     //
 
     @Override
@@ -404,7 +399,7 @@ public class Java8 implements VMPlugin {
                     mn.setAnnotationDefault(true); // GROOVY-10862
                     mn.setCode(new ReturnStatement(new ConstantExpression(m.getDefaultValue(), true)));
                 }
-                mn.setGenericsTypes(configureTypeVariable(m.getTypeParameters()));
+                mn.setGenericsTypes(configureTypeParameters(m.getTypeParameters()));
                 mn.setSynthetic(m.isSynthetic());
                 classNode.addMethod(mn);
             }
@@ -534,7 +529,7 @@ public class Java8 implements VMPlugin {
         return back.getPlainNodeReference();
     }
 
-    private Parameter[] makeParameters(final CompileUnit cu, final Type[] types, final Class<?>[] cls, final Annotation[][] parameterAnnotations, final java.lang.reflect.Member member) {
+    private Parameter[] makeParameters(final CompileUnit cu, final Type[] types, final Class<?>[] cls, final Annotation[][] parameterAnnotations, final Member member) {
         Parameter[] params = Parameter.EMPTY_ARRAY;
         final int n = types.length;
         if (n > 0) {
@@ -549,7 +544,7 @@ public class Java8 implements VMPlugin {
         return params;
     }
 
-    protected void fillParameterNames(final String[] names, final java.lang.reflect.Member member) {
+    protected void fillParameterNames(final String[] names, final Member member) {
         try {
             java.lang.reflect.Parameter[] parameters = ((java.lang.reflect.Executable) member).getParameters();
             for (int i = 0, n = names.length; i < n; i += 1) {
@@ -560,6 +555,8 @@ public class Java8 implements VMPlugin {
         }
     }
 
+    //--------------------------------------------------------------------------
+
     /**
      * The following scenarios can not set accessible, i.e. the return value is false
      * 1) SecurityException occurred
diff --git a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
index 9aa74d2317..3edaff876b 100644
--- a/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosureParamTypeInferenceSTCTest.groovy
@@ -764,6 +764,11 @@ class ClosureParamTypeInferenceSTCTest extends StaticTypeCheckingTestCase {
             def file = Pogo10756.files[0]
             file?.name
         """
+
+        assertScript """import ${Pogo10756.name.replace('$','.')}
+            def files = Pogo10756.files
+            files*.name
+        """
     }
 
     static class Pogo10756 {
diff --git a/src/test/org/codehaus/groovy/ast/decompiled/AsmDecompilerTest.groovy b/src/test/org/codehaus/groovy/ast/decompiled/AsmDecompilerTest.groovy
index 69e5b7ccad..3f8e1bf9e0 100644
--- a/src/test/org/codehaus/groovy/ast/decompiled/AsmDecompilerTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/decompiled/AsmDecompilerTest.groovy
@@ -34,18 +34,18 @@ final class AsmDecompilerTest {
     @Test
     void "basic class"() {
         ClassNode node = decompile()
-        assert AsmDecompilerTestData.name == node.name
-        assert isPublic(node.modifiers)
 
+        assert node.name == AsmDecompilerTestData.name
         assert !node.genericsPlaceHolder
+        assert isPublic(node.modifiers)
         assert node.usingGenerics
 
         def t = node.genericsTypes[0]
         assert t.name == 'T'
         assert t.placeholder
-        assert t.type.name == Object.name
         assert t.type.genericsPlaceHolder
-        assert !t.lowerBound
+        assert t.type.name == List.name // erasure of "T extends List<? super T>"
+        assert t.lowerBound == null
 
         def list = t.upperBounds[0]
         assert list.name == List.name
@@ -54,19 +54,22 @@ final class AsmDecompilerTest {
 
         def wildcard = list.genericsTypes[0]
         assert wildcard.wildcard
-        assert !wildcard.type.genericsPlaceHolder //todo?
+        assert !wildcard.type.genericsPlaceHolder
+        assert wildcard.type.name == Object.name // erasure of "? super T"
         assert !wildcard.upperBounds
 
         def tRef = wildcard.lowerBound
         assert tRef.genericsPlaceHolder
         assert tRef.usingGenerics
         assert tRef.name == Object.name
+        assert tRef.unresolvedName == 'T'
         assert tRef.genericsTypes[0].name == 'T'
 
         def v = node.genericsTypes[1]
         assert v.name == 'V'
         assert v.placeholder
-        assert v.upperBounds[0].toString() == Object.name
+        assert v.type.name == Object.name
+        assert v.upperBounds[0].name == Object.name
     }
 
     @Test