JDK-8265131 : Make ConstantDesc class hierarchy sealed
  • Type: CSR
  • Component: core-libs
  • Sub-Component: java.lang
  • Priority: P4
  • Status: Closed
  • Resolution: Approved
  • Fix Versions: 17
  • Submitted: 2021-04-13
  • Updated: 2021-06-01
  • Resolved: 2021-06-01
Related Reports
CSR :  
Description
Summary
-------

Change the hierarchy rooted at ConstantDesc to be sealed, as has been described as a possibility in its API since its release.

Problem
-------

The hierarchy rooted at ConstantDesc is carefully specified so that most types have a fixed, known number of subtypes. Its API also mentions that the class hierarchy may become sealed when supported by the Java language. However, the compiler can not verify that the hierarchy matches this specification. 

Solution
--------

Sealing the hierarchy will mean that the compiler can statically verify that it matches its specification. The runtime can also check that the classes satisfy the specification.

Specification
-------------

    diff --git a/src/java.base/share/classes/java/lang/constant/ClassDesc.java b/src/java.base/share/classes/java/lang/constant/ClassDesc.java
    index 39b98659cf5..435d992fa50 100644
    --- a/src/java.base/share/classes/java/lang/constant/ClassDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/ClassDesc.java
    @@ -49,18 +49,15 @@ import static java.util.stream.Collectors.joining;
    * {@linkplain ClassDesc} for the component type and then call the {@link #arrayType()}
    * or {@link #arrayType(int)} methods.
    *
    - * @apiNote In the future, if the Java language permits, {@linkplain ClassDesc}
    - * may become a {@code sealed} interface, which would prohibit subclassing except
    - * by explicitly permitted types.  Non-platform classes should not implement
    - * {@linkplain ClassDesc} directly.
    - *
    * @see ConstantDescs
    *
    * @since 12
    */
    -public interface ClassDesc
    +public sealed interface ClassDesc
            extends ConstantDesc,
    -                TypeDescriptor.OfField<ClassDesc> {
    +                TypeDescriptor.OfField<ClassDesc>
    +        permits PrimitiveClassDescImpl,
    +                ReferenceClassDescImpl {
    
        /**
        * Returns a {@linkplain ClassDesc} for a class or interface type,
    diff --git a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java
    index 9d410e6774b..70c5f8fcb55 100644
    --- a/src/java.base/share/classes/java/lang/constant/ConstantDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/ConstantDesc.java
    @@ -68,15 +68,6 @@ import java.lang.invoke.VarHandle.VarHandleDesc;
    * {@link Object#equals(Object)} method. There is no guarantee that any
    * particular entity will always be represented by the same descriptor instance.
    *
    - * @apiNote In the future, if the Java language permits, {@linkplain ConstantDesc}
    - * may become a {@code sealed} interface, which would prohibit subclassing except by
    - * explicitly permitted types.  Clients can assume that the following
    - * set of subtypes is exhaustive: {@link String}, {@link Integer},
    - * {@link Long}, {@link Float}, {@link Double}, {@link ClassDesc},
    - * {@link MethodTypeDesc}, {@link MethodHandleDesc}, and
    - * {@link DynamicConstantDesc}; this list may be extended to reflect future
    - * changes to the constant pool format as defined in JVMS 4.4.
    - *
    * @see Constable
    * @see ConstantDescs
    *
    @@ -84,7 +75,16 @@ import java.lang.invoke.VarHandle.VarHandleDesc;
    *
    * @since 12
    */
    -public interface ConstantDesc {
    +public sealed interface ConstantDesc
    +        permits ClassDesc,
    +                MethodHandleDesc,
    +                MethodTypeDesc,
    +                Double,
    +                DynamicConstantDesc,
    +                Float,
    +                Integer,
    +                Long,
    +                String {
        /**
        * Resolves this descriptor reflectively, emulating the resolution behavior
        * of JVMS 5.4.3 and the access control behavior of JVMS 5.4.4.  The resolution
    diff --git a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java
    index 6b9e8482442..6136edef58f 100644
    --- a/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/DirectMethodHandleDesc.java
    @@ -46,14 +46,11 @@ import static java.lang.invoke.MethodHandleInfo.REF_putStatic;
    * {@link MethodHandle}.  A {@linkplain DirectMethodHandleDesc} corresponds to
    * a {@code Constant_MethodHandle_info} entry in the constant pool of a classfile.
    *
    - * @apiNote In the future, if the Java language permits, {@linkplain DirectMethodHandleDesc}
    - * may become a {@code sealed} interface, which would prohibit subclassing except
    - * by explicitly permitted types.  Non-platform classes should not implement
    - * {@linkplain DirectMethodHandleDesc} directly.
    - *
    * @since 12
    */
    -public interface DirectMethodHandleDesc extends MethodHandleDesc {
    +public sealed interface DirectMethodHandleDesc
    +        extends MethodHandleDesc
    +        permits DirectMethodHandleDescImpl {
        /**
        * Kinds of method handles that can be described with {@linkplain DirectMethodHandleDesc}.
        *
    diff --git a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
    index 96d7677a567..82f5bd6cfd6 100644
    --- a/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/DynamicConstantDesc.java
    @@ -56,7 +56,7 @@ import static java.util.stream.Collectors.joining;
    *
    * @since 12
    */
    -public abstract class DynamicConstantDesc<T>
    +public abstract non-sealed class DynamicConstantDesc<T>
            implements ConstantDesc {
    
        private final DirectMethodHandleDesc bootstrapMethod;
    diff --git a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
    index a066114de8f..e45f4a9419f 100644
    --- a/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/MethodHandleDesc.java
    @@ -35,15 +35,12 @@ import static java.lang.constant.DirectMethodHandleDesc.Kind.CONSTRUCTOR;
    * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    * {@link MethodHandle} constant.
    *
    - * @apiNote In the future, if the Java language permits, {@linkplain MethodHandleDesc}
    - * may become a {@code sealed} interface, which would prohibit subclassing except
    - * by explicitly permitted types.  Non-platform classes should not implement
    - * {@linkplain MethodHandleDesc} directly.
    - *
    * @since 12
    */
    -public interface MethodHandleDesc
    -        extends ConstantDesc {
    +public sealed interface MethodHandleDesc
    +        extends ConstantDesc
    +        permits AsTypeMethodHandleDesc,
    +                DirectMethodHandleDesc {
    
        /**
        * Creates a {@linkplain MethodHandleDesc} corresponding to an invocation of a
    diff --git a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
    index d5ab684e1d8..4750231ce37 100644
    --- a/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
    +++ b/src/java.base/share/classes/java/lang/constant/MethodTypeDesc.java
    @@ -34,16 +34,12 @@ import java.util.stream.Stream;
    * A <a href="package-summary.html#nominal">nominal descriptor</a> for a
    * {@linkplain MethodType} constant.
    *
    - * @apiNote In the future, if the Java language permits, {@linkplain MethodTypeDesc}
    - * may become a {@code sealed} interface, which would prohibit subclassing except
    - * by explicitly permitted types.  Non-platform classes should not implement
    - * {@linkplain MethodTypeDesc} directly.
    - *
    * @since 12
    */
    -public interface MethodTypeDesc
    +public sealed interface MethodTypeDesc
            extends ConstantDesc,
    -                TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc> {
    +                TypeDescriptor.OfMethod<ClassDesc, MethodTypeDesc>
    +        permits MethodTypeDescImpl {
        /**
        * Creates a {@linkplain MethodTypeDesc} given a method descriptor string.
        *

Comments
Moving to Approved.
01-06-2021

[~gbierman], given a clear corpus run, I think this can proceed for JDK 17; thanks for checking.
26-05-2021

Moving to Provisional.
25-05-2021