RFR: 8329644: Discuss expected visitor evolution patterns in javax.lang.model.util

Joe Darcy darcy at openjdk.org
Tue Apr 16 23:43:11 UTC 2024


On Tue, 16 Apr 2024 23:34:06 GMT, Joe Darcy <darcy at openjdk.org> wrote:

> Provide more concrete discussion of how the preview visitors are expected to evolve for different categories of language changes.

The intention of this PR is to should approximate code diffs that would be needed to add support for new language features in the javax.lang.model visitors. Since the escaped code may be difficult to read, I'll cut and paste the generated javadoc output below:

API Note:
    Expected visitor evolution Link icon
    As the Java programming language evolves, the visitor interfaces of the language model also evolve as do the concrete visitors in this package. A preview language feature in JDK N may have API elements added in the set of visitors for the preview language level.

    The remainder of this note will show two examples of the API changes in the model and visitors that can be added to support a language feature. The examples will uses additions to the elements portion of the language model, but the updates to visitors for types or annotation values would be analogous. Two distinct cases are:

        the preview language construct has a corresponding new modeling interface
        the preview language construct only triggers the introduction of a new kind without a new modeling interface. 

    Adding visitor support for a top-level language construct Link icon
    Consider a new language feature, preview feature 1, in JDK N. This feature has a top-level element interface to model it:


     package javax.lang.model.element;
     /**
      * Represents a preview feature 1.
      *
      * @since N
      */
      public interface PreviewFeature1Element extends Element {
      // Methods to retrieve information specific to the preview feature...
      }
     


    A new element kind would also be introduce to model such a feature:


      //  Sample diff of ElementKind.java
      +    /**
      +     * A preview feature 1.
      +     * @since N
      +     */
      +     PREVIEW_FEATURE_1,
     

    A default method is added to ElementVisitor to accommodate the new construct:

     //  Sample diff for ElementVisitor.java
      +    /**
      +     * Visits a preview feature 1.
      +     *
      +     * @implSpec The default implementation visits a {@code
      +     * PreviewFeature1Element} by calling {@code visitUnknown(e, p)}.
      +     *
      +     * @param e  the element to visit
      +     * @param p  a visitor-specified parameter
      +     * @return a visitor-specified result
      +     * @since N
      +     */
      +    default R visitPreviewFeature1(PreviewFeature1Element e, P p) {
      +        return visitUnknown(e, p);
      +    }

     

    Given the default method on the visitor interface, the preview visitor classes need to override this method and take an appropriate action for the visitor's semantics:


     //  Sample diff for AbstractElementVisitorPreview.java
     //  Re-abstract visitPreviewFeature1.
      +    /**
      +     * {@inheritDoc ElementVisitor}
      +     *
      +     * @implSpec Visits a {@code PreviewFeature1Element} in a manner
      +     * defined by a subclass.
      +     *
      +     * @param e {@inheritDoc ElementVisitor}
      +     * @param p {@inheritDoc ElementVisitor}
      +     * @return a visitor-specified result
      +     * @since N
      +     */
      +    @Override
      +    public abstract R visitPreviewFeature1(PreviewFeature1Element e, P p);

     //  Sample diff for ElementKindVisitorPreview.java
     //  Take the default action for a preview feature 1.
      +
      +    /**
      +     * {@inheritDoc ElementVisitor}
      +     *
      +     * @implSpec This implementation calls {@code defaultAction}.
      +     *
      +     * @param e {@inheritDoc ElementVisitor}
      +     * @param p {@inheritDoc ElementVisitor}
      +     * @return  the result of {@code defaultAction}
      +     * @since N
      +     */
      +    @Override
      +    public R visitPreviewFeature1(PreviewFeature1Element e, P p) {
      +        return defaultAction(e, p);
      +    }

     //  Sample diff for ElementScannerPreview.java
     //  Scan the enclosed elements of a preview feature 1.
      +
      +    /**
      +     * {@inheritDoc ElementVisitor}
      +     *
      +     * @implSpec This implementation scans the enclosed elements.
      +     *
      +     * @param e {@inheritDoc ElementVisitor}
      +     * @param p {@inheritDoc ElementVisitor}
      +     * @return  {@inheritDoc ElementScanner6}
      +     * @since N
      +     */
      +    @Override
      +    public R visitPreviewFeature1(PreviewFeature1Element e, P p) {
      +        return scan(e.getEnclosedElements(), p);
      +    }

     //  Sample diff for SimpleElementVisitorPreview.java
     //  Take the default action for a preview feature 1.
      +    /**
      +     * {@inheritDoc ElementVisitor}
      +     *
      +     * @implSpec Visits a {@code PreviewFeature1Element} by calling
      +     * defaultAction.
      +     *
      +     * @param e {@inheritDoc ElementVisitor}
      +     * @param p {@inheritDoc ElementVisitor}
      +     * @return  {@inheritDoc ElementVisitor}
      +     * @since N
      +     */
      +    @Override
      +    public R visitPreviewFeature1(PreviewFeature1Element e, P p) {
      +        return defaultAction(e, p);
      +    }

     

    When preview feature 1 exits preview in JDK (N+k), a set of visitors for language level (N+k) would be added with the methods operating over the feature pulled in from the preview visitors. Each preview visitor would then have its direct superclass changed to the new corresponding (N+k) visitor.
    Adding visitor support for a language construct that is a new kind of an existing construct Link icon
    Consider a new language feature, preview feature 2, in JDK N. This feature has a new element kind without a new top-level element interface needed to model it. Concretely, assume a preview feature 2 is a new kind of variable; the changes would be analogous if the feature were a new kind of executable instead or new kind of another existing top-level construct. In that case, the API changes are more limited:


      //  Sample diff for ElementKind.java
      +    /**
      +     * A preview feature 2.
      +     * @since N
      +     */
      +     PREVIEW_FEATURE_2,
      ...
      // Update existing methods as needed
           public boolean isVariable() {
               return switch(this) {
               case ENUM_CONSTANT, FIELD, PARAMETER,
                    LOCAL_VARIABLE, EXCEPTION_PARAMETER, RESOURCE_VARIABLE,
      -             BINDING_VARIABLE -> true;
      +            BINDING_VARIABLE, PREVIEW_FEATURE_2 -> true;
               default -> false;
               };
           }

     

    The kind visitors need support for the new variety of element:


     // Update visitVariable in ElementKindVisitor6:
            ...
            * @implSpec This implementation dispatches to the visit method for
            * the specific {@linkplain ElementKind kind} of variable, {@code
            * ENUM_CONSTANT}, {@code EXCEPTION_PARAMETER}, {@code FIELD},
      -     * {@code LOCAL_VARIABLE}, {@code PARAMETER}, or {@code RESOURCE_VARIABLE}.
      +     * {@code LOCAL_VARIABLE}, {@code PARAMETER}, or {@code RESOURCE_VARIABLE},
      +     * or {@code PREVIEW_FEATURE_2}.
            *
            * @param e {@inheritDoc ElementVisitor}
            * @param p {@inheritDoc ElementVisitor}
            * @return  the result of the kind-specific visit method
            */
            @Override
            public R visitVariable(VariableElement e, P p) {
            ...
               case BINDING_VARIABLE:
                   return visitVariableAsBindingVariable(e, p);
       
      +        case PREVIEW_FEATURE_2:
      +            return visitVariableAsPreviewFeature2(e, p);
      +
               default:
                   throw new AssertionError("Bad kind " + k + " for VariableElement" + e);
            ...
      +    /**
      +     * Visits a {@code PREVIEW_FEATURE_2} variable element.
      +     *
      +     * @implSpec This implementation calls {@code visitUnknown}.
      +     *
      +     * @param e the element to visit
      +     * @param p a visitor-specified parameter
      +     * @return  the result of {@code visitUnknown}
      +     *
      +     * @since N
      +     */
      +    public R visitVariableAsPreviewFeature2(VariableElement e, P p) {
      +        return visitUnknown(e, p);
      +    }

     

    The preview element kind visitor in turn overrides visitVariableAsPreviewFeature2:


     // Sample diff for ElementKindVisitorPreview:
      +    /**
      +     * {@inheritDoc ElementKindVisitor6}
      +     *
      +     * @implSpec This implementation calls {@code defaultAction}.
      +     *
      +     * @param e {@inheritDoc ElementKindVisitor6}
      +     * @param p {@inheritDoc ElementKindVisitor6}
      +     * @return  the result of {@code defaultAction}
      +     *
      +     * @since N
      +     */
      +    public R visitVariableAsPreviewFeature2(VariableElement e, P p) {
      +        return defaultAction(e, p);
      +    }

     

    As in the case where a new interface is introduced, when preview feature 2 exits preview in JDK (N+k), a set of visitors for language level (N+k) would be added with the methods operating over the new feature in the kind visitors pulled in from the preview visitors. Each preview visitor would then have its direct superclass changed to the new corresponding (N+k) visitor.

I didn't use javadoc snippets because for the purposes of this PR it is important to present javadoc comments to the reader. Likewise, I only use a pre HTML tag and not pre and code allow the HTML escapes to be used to represent "/" and "@".

-------------

PR Comment: https://git.openjdk.org/jdk/pull/18804#issuecomment-2060074382
PR Comment: https://git.openjdk.org/jdk/pull/18804#issuecomment-2060075682


More information about the compiler-dev mailing list