8323707: Adjust Classfile API's type arg model to better represent the embodied type

Reviewed-by: asotona
This commit is contained in:
Chen Liang 2024-05-03 11:08:33 +00:00 committed by Adam Sotona
parent f78fa0556d
commit c60474b122
6 changed files with 107 additions and 85 deletions

View File

@ -185,88 +185,107 @@ public sealed interface Signature {
/**
* Models the type argument.
*
* @sealedGraph
* @since 22
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface TypeArg
permits SignaturesImpl.TypeArgImpl {
public sealed interface TypeArg {
/**
* Indicator for whether a wildcard has default bound, no bound,
* an upper bound, or a lower bound
*
* @since 22
* Models an unbounded type argument {@code *}.
* @since 23
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public enum WildcardIndicator {
/**
* default bound wildcard (empty)
*/
DEFAULT,
/**
* unbounded indicator {@code *}
*/
UNBOUNDED,
/**
* upper-bounded indicator {@code +}
*/
EXTENDS,
/**
* lower-bounded indicator {@code -}
*/
SUPER;
public sealed interface Unbounded extends TypeArg permits SignaturesImpl.UnboundedTypeArgImpl {
}
/** {@return the wildcard indicator} */
WildcardIndicator wildcardIndicator();
/**
* Models a type argument with an explicit bound type.
* @since 23
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public sealed interface Bounded extends TypeArg permits SignaturesImpl.TypeArgImpl {
/** {@return the signature of the type bound, if any} */
Optional<RefTypeSig> boundType();
/**
* Models a type argument's wildcard indicator.
* @since 23
*/
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
public enum WildcardIndicator {
/**
* No wildcard (empty), an exact type. Also known as
* {@index invariant}.
*/
NONE,
/**
* Upper-bound indicator {@code +}. Also known as
* {@index covariant}.
*/
EXTENDS,
/**
* Lower-bound indicator {@code -}. Also known as
* {@index contravariant}.
*/
SUPER;
}
/** {@return the kind of wildcard} */
WildcardIndicator wildcardIndicator();
/** {@return the signature of the type bound} */
RefTypeSig boundType();
}
/**
* {@return a bounded type arg}
* @param boundType the bound
* @since 23
*/
public static TypeArg of(RefTypeSig boundType) {
public static TypeArg.Bounded of(RefTypeSig boundType) {
requireNonNull(boundType);
return of(WildcardIndicator.DEFAULT, Optional.of(boundType));
return bounded(Bounded.WildcardIndicator.NONE, boundType);
}
/**
* {@return an unbounded type arg}
* @since 23
*/
public static TypeArg unbounded() {
return of(WildcardIndicator.UNBOUNDED, Optional.empty());
public static TypeArg.Unbounded unbounded() {
return SignaturesImpl.UnboundedTypeArgImpl.INSTANCE;
}
/**
* {@return an upper-bounded type arg}
* @param boundType the upper bound
* @since 23
*/
public static TypeArg extendsOf(RefTypeSig boundType) {
public static TypeArg.Bounded extendsOf(RefTypeSig boundType) {
requireNonNull(boundType);
return of(WildcardIndicator.EXTENDS, Optional.of(boundType));
return bounded(Bounded.WildcardIndicator.EXTENDS, boundType);
}
/**
* {@return a lower-bounded type arg}
* @param boundType the lower bound
* @since 23
*/
public static TypeArg superOf(RefTypeSig boundType) {
public static TypeArg.Bounded superOf(RefTypeSig boundType) {
requireNonNull(boundType);
return of(WildcardIndicator.SUPER, Optional.of(boundType));
return bounded(Bounded.WildcardIndicator.SUPER, boundType);
}
/**
* {@return a bounded type arg}
* @param wildcard the wild card
* @param boundType optional bound type
* @since 23
*/
public static TypeArg of(WildcardIndicator wildcard, Optional<RefTypeSig> boundType) {
public static TypeArg.Bounded bounded(Bounded.WildcardIndicator wildcard, RefTypeSig boundType) {
requireNonNull(wildcard);
requireNonNull(boundType);
return new SignaturesImpl.TypeArgImpl(wildcard, boundType);
}
}

View File

@ -369,11 +369,11 @@ public record ClassRemapperImpl(Function<ClassDesc, ClassDesc> mapFunction) impl
Signature.ClassTypeSig.of(
cts.outerType().map(this::mapSignature).orElse(null),
map(cts.classDesc()),
cts.typeArgs().stream()
.map(ta -> Signature.TypeArg.of(
ta.wildcardIndicator(),
ta.boundType().map(this::mapSignature)))
.toArray(Signature.TypeArg[]::new));
cts.typeArgs().stream().map(ta -> switch (ta) {
case Signature.TypeArg.Unbounded u -> u;
case Signature.TypeArg.Bounded bta -> Signature.TypeArg.bounded(
bta.wildcardIndicator(), mapSignature(bta.boundType()));
}).toArray(Signature.TypeArg[]::new));
default -> signature;
};
}

View File

@ -280,24 +280,29 @@ public final class SignaturesImpl {
if (!typeArgs.isEmpty()) {
var sb = new StringBuilder();
sb.append('<');
for (var ta : typeArgs)
sb.append(((TypeArgImpl)ta).signatureString());
for (var ta : typeArgs) {
switch (ta) {
case TypeArg.Bounded b -> {
switch (b.wildcardIndicator()) {
case SUPER -> sb.append('-');
case EXTENDS -> sb.append('+');
}
sb.append(b.boundType().signatureString());
}
case TypeArg.Unbounded _ -> sb.append('*');
}
}
suffix = sb.append(">;").toString();
}
return prefix + className + suffix;
}
}
public static record TypeArgImpl(WildcardIndicator wildcardIndicator, Optional<RefTypeSig> boundType) implements Signature.TypeArg {
public static enum UnboundedTypeArgImpl implements TypeArg.Unbounded {
INSTANCE;
}
public String signatureString() {
return switch (wildcardIndicator) {
case DEFAULT -> boundType.get().signatureString();
case EXTENDS -> "+" + boundType.get().signatureString();
case SUPER -> "-" + boundType.get().signatureString();
case UNBOUNDED -> "*";
};
}
public static record TypeArgImpl(WildcardIndicator wildcardIndicator, RefTypeSig boundType) implements Signature.TypeArg.Bounded {
}
public static record TypeParamImpl(String identifier, Optional<RefTypeSig> classBound, List<RefTypeSig> interfaceBounds)

View File

@ -366,16 +366,20 @@ public class ClassWriter extends BasicWriter {
}
private void print(StringBuilder sb, Signature.TypeArg ta) {
switch (ta.wildcardIndicator()) {
case DEFAULT -> print(sb, ta.boundType().get());
case UNBOUNDED -> sb.append('?');
case EXTENDS -> {
sb.append("? extends ");
print(sb, ta.boundType().get());
}
case SUPER -> {
sb.append("? super ");
print(sb, ta.boundType().get());
switch (ta) {
case Signature.TypeArg.Unbounded _ -> sb.append('?');
case Signature.TypeArg.Bounded bta -> {
switch (bta.wildcardIndicator()) {
case NONE -> print(sb, bta.boundType());
case EXTENDS -> {
sb.append("? extends ");
print(sb, bta.boundType());
}
case SUPER -> {
sb.append("? super ");
print(sb, bta.boundType());
}
}
}
}
}

View File

@ -183,9 +183,10 @@ class SignaturesTest {
void testClassSignatureClassDesc() throws IOException {
var observerCf = ClassFile.of().parse(Path.of(System.getProperty("test.classes"), "SignaturesTest$Observer.class"));
var sig = observerCf.findAttribute(Attributes.SIGNATURE).orElseThrow().asClassSignature();
var innerSig = (ClassTypeSig) sig.superclassSignature() // ArrayList
.typeArgs().getFirst() // Outer<String>.Inner<Long>
.boundType().orElseThrow(); // assert it's exact bound
var arrayListSig = sig.superclassSignature(); // ArrayList
var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer<String>.Inner<Long>
assertEquals(TypeArg.Bounded.WildcardIndicator.NONE, arrayListTypeArg.wildcardIndicator());
var innerSig = (ClassTypeSig) arrayListTypeArg.boundType();
assertEquals("Inner", innerSig.className(), "simple name in signature");
assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(),
"ClassDesc derived from signature");

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -312,21 +312,14 @@ public class T6888367 {
}
public String visitWildcardType(Signature.TypeArg type) {
switch (type.wildcardIndicator()) {
case UNBOUNDED -> {
return "W{?}";
}
case EXTENDS -> {
return "W{e," + print(type.boundType().get()) + "}";
}
case SUPER -> {
return "W{s," + print(type.boundType().get()) + "}";
}
default -> {
if (type.boundType().isPresent()) return print(type.boundType().get());
else throw new AssertionError();
}
}
return switch (type) {
case Signature.TypeArg.Unbounded _ -> "W{?}";
case Signature.TypeArg.Bounded b -> switch (b.wildcardIndicator()) {
case EXTENDS -> "W{e," + print(b.boundType()) + "}";
case SUPER -> "W{s," + print(b.boundType()) + "}";
case NONE -> print(b.boundType());
};
};
}
};