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