[
https://issues.apache.org/jira/browse/GROOVY-12702?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18138780#comment-18138780
]
ASF GitHub Bot commented on GROOVY-12702:
-----------------------------------------
daniellansun opened a new pull request, #3229:
URL: https://github.com/apache/groovy/pull/3229
https://issues.apache.org/jira/browse/GROOVY-12702
A `TYPE_USE` annotation in declaration position applies to the type of the
declared variable and is written to the class file as a local-variable type
annotation (`RuntimeVisibleTypeAnnotations`, target `LOCAL_VARIABLE`). That
already happens for a single declaration (`@TO String a = …`) and for several
declarators (`@TO String a = …, b = …`). A multiple-assignment declaration
(`@TO def (String a, String b) = …`) kept the annotation on the declaration
only, so neither variable received it. An annotation written on one variable
(`def (@TO String a, String b) = …`) was already applied to that variable and
is unchanged.
`ExtendedVerifier` now adds the declaration's `TYPE_USE` annotations to the
origin type of every declared variable, then removes annotations that are
allowed only as `TYPE_USE` from the declaration once. The existing duplicate
check still skips an annotation the type node already carries, including when
variables share a type node.
Static compilation rewrites a multiple assignment whose right-hand side is a
list literal into single declarations before verification. Those declarations
now keep the original annotations, so the same local-variable type annotations
are emitted whether or not that rewrite runs.
The tests read the class file with ASM. They cover dynamic, `@TypeChecked`,
and `@CompileStatic` compilation, declaration position and type position, a
dual `LOCAL_VARIABLE`+`TYPE_USE` target, a `LOCAL_VARIABLE`-only annotation,
primitives, arrays, dynamic variables, closures, and a misplaced `@Override`.
### Testing
- TypeAnnotationsTest coverage for multiple-assignment TYPE_USE annotations
> TYPE_USE annotations on a multiple-assignment declaration are not applied to
> the declared variables' types
> ----------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12702
> URL: https://issues.apache.org/jira/browse/GROOVY-12702
> Project: Groovy
> Issue Type: Bug
> Components: Compiler
> Reporter: Paul King
> Priority: Major
>
> h3. Description
> A TYPE_USE annotation written in declaration position applies to the type of
> the declared variable, and is written to the class file as a local-variable
> type annotation ({{RuntimeVisibleTypeAnnotations}}, target
> {{LOCAL_VARIABLE}}). This works for a single declaration and for several
> declarators, but not for a multiple-assignment declaration:
> {code:groovy}
> import java.lang.annotation.*
> @Retention(RetentionPolicy.RUNTIME)
> @Target(ElementType.TYPE_USE)
> @interface TO {}
> class C {
> def single() { @TO String a = 'x'; a } // 1
> local-variable type annotation
> def declarators() { @TO String a = 'x', b = 'y'; a + b } // 2
> def multiple() { @TO def (String a, String b) = ['x', 'y']; a + b } //
> none
> def typePosition(){ def (@TO String a, String b) = ['x', 'y']; a + b } //
> 1, for a
> }
> {code}
> {{javap -v C.class}} shows {{RuntimeVisibleTypeAnnotations}} entries with
> target {{LOCAL_VARIABLE}} for {{a}} in {{single()}}, for {{a}} and {{b}} in
> {{declarators()}}, and for {{a}} in {{typePosition()}}, but none in
> {{multiple()}}. The same holds with {{@TypeChecked}}. An annotation allowed
> on both TYPE_USE and LOCAL_VARIABLE ({{@Target([TYPE_USE, LOCAL_VARIABLE])}})
> behaves the same way.
> Under {{@CompileStatic}} the result depends on how the multiple assignment is
> compiled. Static compilation rewrites {{def (a, b) = [x, y]}} into single
> declarations when its value is not used, and with GROOVY-12698 those carry
> the annotations of the original declaration. So, once GROOVY-12698 and
> GROOVY-12700 are in:
> * as a statement, {{multiple()}} emits an annotation for both {{a}} and
> {{b}}, like {{declarators()}};
> * where its value is used (for example as the last statement of a method or
> closure), it is not rewritten and emits none.
> So the same declaration produces different class files depending on the
> compilation mode and on where it appears.
> h3. Cause
> {{ExtendedVerifier#visitDeclarationExpression}} handles the two forms
> differently:
> {code:java}
> visitAnnotations(expression, LOCAL_VARIABLE_TARGET);
> if (expression.isMultipleAssignmentDeclaration()) {
> expression.getTupleExpression().forEach(e ->
> visitTypeAnnotations(((VariableExpression) e).getOriginType()));
> } else {
> ClassNode type = expression.getVariableExpression().getOriginType();
> visitTypeAnnotations(type);
> extractTypeUseAnnotations(expression.getAnnotations(), type,
> LOCAL_VARIABLE_TARGET);
> }
> {code}
> For a single declaration, {{extractTypeUseAnnotations}} moves the TYPE_USE
> annotations of the declaration onto the declared type, from where
> {{CompileStack}} writes them as local-variable type annotations. For a
> multiple-assignment declaration, only annotations already on each variable's
> type (written in type position) are checked, and the annotations of the
> declaration itself are never moved onto the variables' types.
> h3. Suggested fix
> In the multiple-assignment branch, add the TYPE_USE annotations of the
> declaration to the origin type of every variable on the left-hand side, as
> the single-declaration branch does for its one variable. Annotations allowed
> only on TYPE_USE should then be removed from the declaration once, after all
> the variables have been handled. Calling {{extractTypeUseAnnotations}} per
> variable as it stands would remove them while handling the first variable, so
> the helper needs splitting into "add to type" and "remove from declaration",
> or a variant that takes several target types. The existing duplicate check in
> {{extractTypeUseAnnotations}} (GROOVY-12434) also guards against adding the
> same annotation twice when variables share a type node.
> With that change, the multiple-assignment form emits the same annotations as
> the declarator form in every mode and position, and the class files no longer
> depend on whether static compilation rewrote the declaration.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)