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.
|
* Models the type argument.
|
||||||
*
|
*
|
||||||
|
* @sealedGraph
|
||||||
* @since 22
|
* @since 22
|
||||||
*/
|
*/
|
||||||
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
|
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
|
||||||
public sealed interface TypeArg
|
public sealed interface TypeArg {
|
||||||
permits SignaturesImpl.TypeArgImpl {
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicator for whether a wildcard has default bound, no bound,
|
* Models an unbounded type argument {@code *}.
|
||||||
* an upper bound, or a lower bound
|
* @since 23
|
||||||
*
|
|
||||||
* @since 22
|
|
||||||
*/
|
*/
|
||||||
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
|
@PreviewFeature(feature = PreviewFeature.Feature.CLASSFILE_API)
|
||||||
public enum WildcardIndicator {
|
public sealed interface Unbounded extends TypeArg permits SignaturesImpl.UnboundedTypeArgImpl {
|
||||||
|
|
||||||
/**
|
|
||||||
* default bound wildcard (empty)
|
|
||||||
*/
|
|
||||||
DEFAULT,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* unbounded indicator {@code *}
|
|
||||||
*/
|
|
||||||
UNBOUNDED,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* upper-bounded indicator {@code +}
|
|
||||||
*/
|
|
||||||
EXTENDS,
|
|
||||||
|
|
||||||
/**
|
|
||||||
* lower-bounded indicator {@code -}
|
|
||||||
*/
|
|
||||||
SUPER;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** {@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}
|
* {@return a bounded type arg}
|
||||||
* @param boundType the bound
|
* @param boundType the bound
|
||||||
|
* @since 23
|
||||||
*/
|
*/
|
||||||
public static TypeArg of(RefTypeSig boundType) {
|
public static TypeArg.Bounded of(RefTypeSig boundType) {
|
||||||
requireNonNull(boundType);
|
requireNonNull(boundType);
|
||||||
return of(WildcardIndicator.DEFAULT, Optional.of(boundType));
|
return bounded(Bounded.WildcardIndicator.NONE, boundType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return an unbounded type arg}
|
* {@return an unbounded type arg}
|
||||||
|
* @since 23
|
||||||
*/
|
*/
|
||||||
public static TypeArg unbounded() {
|
public static TypeArg.Unbounded unbounded() {
|
||||||
return of(WildcardIndicator.UNBOUNDED, Optional.empty());
|
return SignaturesImpl.UnboundedTypeArgImpl.INSTANCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return an upper-bounded type arg}
|
* {@return an upper-bounded type arg}
|
||||||
* @param boundType the upper bound
|
* @param boundType the upper bound
|
||||||
|
* @since 23
|
||||||
*/
|
*/
|
||||||
public static TypeArg extendsOf(RefTypeSig boundType) {
|
public static TypeArg.Bounded extendsOf(RefTypeSig boundType) {
|
||||||
requireNonNull(boundType);
|
requireNonNull(boundType);
|
||||||
return of(WildcardIndicator.EXTENDS, Optional.of(boundType));
|
return bounded(Bounded.WildcardIndicator.EXTENDS, boundType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return a lower-bounded type arg}
|
* {@return a lower-bounded type arg}
|
||||||
* @param boundType the lower bound
|
* @param boundType the lower bound
|
||||||
|
* @since 23
|
||||||
*/
|
*/
|
||||||
public static TypeArg superOf(RefTypeSig boundType) {
|
public static TypeArg.Bounded superOf(RefTypeSig boundType) {
|
||||||
requireNonNull(boundType);
|
requireNonNull(boundType);
|
||||||
return of(WildcardIndicator.SUPER, Optional.of(boundType));
|
return bounded(Bounded.WildcardIndicator.SUPER, boundType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@return a bounded type arg}
|
* {@return a bounded type arg}
|
||||||
* @param wildcard the wild card
|
* @param wildcard the wild card
|
||||||
* @param boundType optional bound type
|
* @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);
|
return new SignaturesImpl.TypeArgImpl(wildcard, boundType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -369,11 +369,11 @@ public record ClassRemapperImpl(Function<ClassDesc, ClassDesc> mapFunction) impl
|
|||||||
Signature.ClassTypeSig.of(
|
Signature.ClassTypeSig.of(
|
||||||
cts.outerType().map(this::mapSignature).orElse(null),
|
cts.outerType().map(this::mapSignature).orElse(null),
|
||||||
map(cts.classDesc()),
|
map(cts.classDesc()),
|
||||||
cts.typeArgs().stream()
|
cts.typeArgs().stream().map(ta -> switch (ta) {
|
||||||
.map(ta -> Signature.TypeArg.of(
|
case Signature.TypeArg.Unbounded u -> u;
|
||||||
ta.wildcardIndicator(),
|
case Signature.TypeArg.Bounded bta -> Signature.TypeArg.bounded(
|
||||||
ta.boundType().map(this::mapSignature)))
|
bta.wildcardIndicator(), mapSignature(bta.boundType()));
|
||||||
.toArray(Signature.TypeArg[]::new));
|
}).toArray(Signature.TypeArg[]::new));
|
||||||
default -> signature;
|
default -> signature;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -280,24 +280,29 @@ public final class SignaturesImpl {
|
|||||||
if (!typeArgs.isEmpty()) {
|
if (!typeArgs.isEmpty()) {
|
||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
sb.append('<');
|
sb.append('<');
|
||||||
for (var ta : typeArgs)
|
for (var ta : typeArgs) {
|
||||||
sb.append(((TypeArgImpl)ta).signatureString());
|
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();
|
suffix = sb.append(">;").toString();
|
||||||
}
|
}
|
||||||
return prefix + className + suffix;
|
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() {
|
public static record TypeArgImpl(WildcardIndicator wildcardIndicator, RefTypeSig boundType) implements Signature.TypeArg.Bounded {
|
||||||
return switch (wildcardIndicator) {
|
|
||||||
case DEFAULT -> boundType.get().signatureString();
|
|
||||||
case EXTENDS -> "+" + boundType.get().signatureString();
|
|
||||||
case SUPER -> "-" + boundType.get().signatureString();
|
|
||||||
case UNBOUNDED -> "*";
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static record TypeParamImpl(String identifier, Optional<RefTypeSig> classBound, List<RefTypeSig> interfaceBounds)
|
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) {
|
private void print(StringBuilder sb, Signature.TypeArg ta) {
|
||||||
switch (ta.wildcardIndicator()) {
|
switch (ta) {
|
||||||
case DEFAULT -> print(sb, ta.boundType().get());
|
case Signature.TypeArg.Unbounded _ -> sb.append('?');
|
||||||
case UNBOUNDED -> sb.append('?');
|
case Signature.TypeArg.Bounded bta -> {
|
||||||
case EXTENDS -> {
|
switch (bta.wildcardIndicator()) {
|
||||||
sb.append("? extends ");
|
case NONE -> print(sb, bta.boundType());
|
||||||
print(sb, ta.boundType().get());
|
case EXTENDS -> {
|
||||||
}
|
sb.append("? extends ");
|
||||||
case SUPER -> {
|
print(sb, bta.boundType());
|
||||||
sb.append("? super ");
|
}
|
||||||
print(sb, ta.boundType().get());
|
case SUPER -> {
|
||||||
|
sb.append("? super ");
|
||||||
|
print(sb, bta.boundType());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -183,9 +183,10 @@ class SignaturesTest {
|
|||||||
void testClassSignatureClassDesc() throws IOException {
|
void testClassSignatureClassDesc() throws IOException {
|
||||||
var observerCf = ClassFile.of().parse(Path.of(System.getProperty("test.classes"), "SignaturesTest$Observer.class"));
|
var observerCf = ClassFile.of().parse(Path.of(System.getProperty("test.classes"), "SignaturesTest$Observer.class"));
|
||||||
var sig = observerCf.findAttribute(Attributes.SIGNATURE).orElseThrow().asClassSignature();
|
var sig = observerCf.findAttribute(Attributes.SIGNATURE).orElseThrow().asClassSignature();
|
||||||
var innerSig = (ClassTypeSig) sig.superclassSignature() // ArrayList
|
var arrayListSig = sig.superclassSignature(); // ArrayList
|
||||||
.typeArgs().getFirst() // Outer<String>.Inner<Long>
|
var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer<String>.Inner<Long>
|
||||||
.boundType().orElseThrow(); // assert it's exact bound
|
assertEquals(TypeArg.Bounded.WildcardIndicator.NONE, arrayListTypeArg.wildcardIndicator());
|
||||||
|
var innerSig = (ClassTypeSig) arrayListTypeArg.boundType();
|
||||||
assertEquals("Inner", innerSig.className(), "simple name in signature");
|
assertEquals("Inner", innerSig.className(), "simple name in signature");
|
||||||
assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(),
|
assertEquals(Outer.Inner.class.describeConstable().orElseThrow(), innerSig.classDesc(),
|
||||||
"ClassDesc derived from signature");
|
"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.
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
*
|
*
|
||||||
* This code is free software; you can redistribute it and/or modify it
|
* 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) {
|
public String visitWildcardType(Signature.TypeArg type) {
|
||||||
switch (type.wildcardIndicator()) {
|
return switch (type) {
|
||||||
case UNBOUNDED -> {
|
case Signature.TypeArg.Unbounded _ -> "W{?}";
|
||||||
return "W{?}";
|
case Signature.TypeArg.Bounded b -> switch (b.wildcardIndicator()) {
|
||||||
}
|
case EXTENDS -> "W{e," + print(b.boundType()) + "}";
|
||||||
case EXTENDS -> {
|
case SUPER -> "W{s," + print(b.boundType()) + "}";
|
||||||
return "W{e," + print(type.boundType().get()) + "}";
|
case NONE -> print(b.boundType());
|
||||||
}
|
};
|
||||||
case SUPER -> {
|
};
|
||||||
return "W{s," + print(type.boundType().get()) + "}";
|
|
||||||
}
|
|
||||||
default -> {
|
|
||||||
if (type.boundType().isPresent()) return print(type.boundType().get());
|
|
||||||
else throw new AssertionError();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user