From c60474b1229b67265acbd709f6ba081303329be4 Mon Sep 17 00:00:00 2001 From: Chen Liang Date: Fri, 3 May 2024 11:08:33 +0000 Subject: [PATCH] 8323707: Adjust Classfile API's type arg model to better represent the embodied type Reviewed-by: asotona --- .../java/lang/classfile/Signature.java | 99 +++++++++++-------- .../classfile/impl/ClassRemapperImpl.java | 10 +- .../classfile/impl/SignaturesImpl.java | 27 ++--- .../com/sun/tools/javap/ClassWriter.java | 24 +++-- test/jdk/jdk/classfile/SignaturesTest.java | 7 +- .../javap/classfile/6888367/T6888367.java | 25 ++--- 6 files changed, 107 insertions(+), 85 deletions(-) diff --git a/src/java.base/share/classes/java/lang/classfile/Signature.java b/src/java.base/share/classes/java/lang/classfile/Signature.java index ad2528fd713..22ca477f4e6 100644 --- a/src/java.base/share/classes/java/lang/classfile/Signature.java +++ b/src/java.base/share/classes/java/lang/classfile/Signature.java @@ -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 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 boundType) { + public static TypeArg.Bounded bounded(Bounded.WildcardIndicator wildcard, RefTypeSig boundType) { + requireNonNull(wildcard); + requireNonNull(boundType); return new SignaturesImpl.TypeArgImpl(wildcard, boundType); } } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java index 6e80e289064..de6128a9f7f 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/ClassRemapperImpl.java @@ -369,11 +369,11 @@ public record ClassRemapperImpl(Function 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; }; } diff --git a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java index 3447e40b258..77f6933a0c2 100644 --- a/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java +++ b/src/java.base/share/classes/jdk/internal/classfile/impl/SignaturesImpl.java @@ -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 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 classBound, List interfaceBounds) diff --git a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java index 028fc480f58..c5ac15ee7da 100644 --- a/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java +++ b/src/jdk.jdeps/share/classes/com/sun/tools/javap/ClassWriter.java @@ -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()); + } + } } } } diff --git a/test/jdk/jdk/classfile/SignaturesTest.java b/test/jdk/jdk/classfile/SignaturesTest.java index cfd3201c95a..f4da2405dcd 100644 --- a/test/jdk/jdk/classfile/SignaturesTest.java +++ b/test/jdk/jdk/classfile/SignaturesTest.java @@ -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.Inner - .boundType().orElseThrow(); // assert it's exact bound + var arrayListSig = sig.superclassSignature(); // ArrayList + var arrayListTypeArg = (TypeArg.Bounded) arrayListSig.typeArgs().getFirst(); // Outer.Inner + 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"); diff --git a/test/langtools/tools/javap/classfile/6888367/T6888367.java b/test/langtools/tools/javap/classfile/6888367/T6888367.java index 05df08b5948..16bc06321ca 100644 --- a/test/langtools/tools/javap/classfile/6888367/T6888367.java +++ b/test/langtools/tools/javap/classfile/6888367/T6888367.java @@ -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()); + }; + }; } };