8323707: Adjust Classfile API's type arg model to better represent the embodied type
Reviewed-by: asotona
This commit is contained in:
parent
f78fa0556d
commit
c60474b122
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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");
|
||||
|
@ -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());
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user