8320575: generic type information lost on mandated parameters of record's compact constructors

Co-authored-by: Chen Liang <liach@openjdk.org>
Reviewed-by: jlahoda
This commit is contained in:
Vicente Romero 2024-05-24 20:43:23 +00:00
parent 253508b03a
commit 7bf1989f59
3 changed files with 399 additions and 29 deletions

View file

@ -255,12 +255,17 @@ public abstract sealed class Executable extends AccessibleObject
* represented by this object. Returns an array of length
* 0 if the underlying executable takes no parameters.
* Note that the constructors of some inner classes
* may have an implicitly declared parameter in addition to
* explicitly declared ones.
* may have an {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} parameter in addition to explicitly
* declared ones.
* Also note that compact constructors of a record class may have
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} parameters.
*
* @return the parameter types for the executable this object
* represents
*/
@SuppressWarnings("doclint:reference") // cross-module links
public abstract Class<?>[] getParameterTypes();
/**
@ -280,18 +285,32 @@ public abstract sealed class Executable extends AccessibleObject
* underlying executable takes no parameters. Note that the
* constructors of some inner classes may have an implicitly
* declared parameter in addition to explicitly declared ones.
* Also note that as a <a
* href="{@docRoot}/java.base/java/lang/reflect/package-summary.html#LanguageJvmModel">modeling
* artifact</a>, the number of returned parameters can differ
* Compact constructors of a record class may also have
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} parameters,
* but they are a special case and thus considered as if they had
* been explicitly declared in the source.
* Finally note that as a {@link java.lang.reflect##LanguageJvmModel
* modeling artifact}, the number of returned parameters can differ
* depending on whether or not generic information is present. If
* generic information is present, only parameters explicitly
* present in the source will be returned; if generic information
* is not present, implicit and synthetic parameters may be
* generic information is present, parameters explicitly
* present in the source or parameters of compact constructors
* of a record class will be returned.
* Note that parameters of compact constructors of a record class are a special case,
* as they are not explicitly present in the source, and its type will be returned
* regardless of the parameters being
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} or not.
* If generic information is not present, implicit and synthetic parameters may be
* returned as well.
*
* <p>If a formal parameter type is a parameterized type,
* the {@code Type} object returned for it must accurately reflect
* the actual type arguments used in the source code.
* the actual type arguments used in the source code. This assertion also
* applies to the parameters of compact constructors of a record class,
* independently of them being
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} or not.
*
* <p>If a formal parameter type is a type variable or a parameterized
* type, it is created. Otherwise, it is resolved.
@ -309,6 +328,7 @@ public abstract sealed class Executable extends AccessibleObject
* the underlying executable's parameter types refer to a parameterized
* type that cannot be instantiated for any reason
*/
@SuppressWarnings("doclint:reference") // cross-module links
public Type[] getGenericParameterTypes() {
if (hasGenericInformation())
return getGenericInfo().getParameterTypes();
@ -335,22 +355,34 @@ public abstract sealed class Executable extends AccessibleObject
// If we have real parameter data, then we use the
// synthetic and mandate flags to our advantage.
if (realParamData) {
final Type[] out = new Type[nonGenericParamTypes.length];
final Parameter[] params = getParameters();
int fromidx = 0;
for (int i = 0; i < out.length; i++) {
final Parameter param = params[i];
if (param.isSynthetic() || param.isImplicit()) {
// If we hit a synthetic or mandated parameter,
// use the non generic parameter info.
out[i] = nonGenericParamTypes[i];
if (getDeclaringClass().isRecord() && this instanceof Constructor) {
/* we could be seeing a compact constructor of a record class
* its parameters are mandated but we should be able to retrieve
* its generic information if present
*/
if (genericParamTypes.length == nonGenericParamTypes.length) {
return genericParamTypes;
} else {
// Otherwise, use the generic parameter info.
out[i] = genericParamTypes[fromidx];
fromidx++;
return nonGenericParamTypes.clone();
}
} else {
final Type[] out = new Type[nonGenericParamTypes.length];
final Parameter[] params = getParameters();
int fromidx = 0;
for (int i = 0; i < out.length; i++) {
final Parameter param = params[i];
if (param.isSynthetic() || param.isImplicit()) {
// If we hit a synthetic or mandated parameter,
// use the non generic parameter info.
out[i] = nonGenericParamTypes[i];
} else {
// Otherwise, use the generic parameter info.
out[i] = genericParamTypes[fromidx];
fromidx++;
}
}
return out;
}
return out;
} else {
// Otherwise, use the non-generic parameter data.
// Without method parameter reflection data, we have
@ -748,13 +780,18 @@ public abstract sealed class Executable extends AccessibleObject
* Returns an array of length 0 if the method/constructor declares no
* parameters.
* Note that the constructors of some inner classes
* may have an implicitly declared parameter in addition to
* explicitly declared ones.
* may have an
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} parameter in addition to explicitly declared ones.
* Also note that compact constructors of a record class may have
* {@linkplain java.compiler/javax.lang.model.util.Elements.Origin#MANDATED
* implicitly declared} parameters.
*
* @return an array of objects representing the types of the
* formal parameters of the method or constructor represented by this
* {@code Executable}
*/
@SuppressWarnings("doclint:reference") // cross-module links
public AnnotatedType[] getAnnotatedParameterTypes() {
return TypeAnnotationParser.buildAnnotatedTypes(getTypeAnnotationBytes0(),
SharedSecrets.getJavaLangAccess().