[
https://issues.apache.org/jira/browse/GROOVY-12702?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12702.
--------------------------------
Fix Version/s: 7.0.0-alpha-1
6.0.1
Assignee: Paul King
Resolution: Fixed
> 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
> Assignee: Paul King
> Priority: Major
> Fix For: 7.0.0-alpha-1, 6.0.1
>
>
> 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)