[ 
https://issues.apache.org/jira/browse/GROOVY-12702?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18138859#comment-18138859
 ] 

ASF GitHub Bot commented on GROOVY-12702:
-----------------------------------------

testlens-app[bot] commented on PR #3229:
URL: https://github.com/apache/groovy/pull/3229#issuecomment-6661706302

   ## ✅ All tests passed ✅
   
   🏷️ Commit: b58597cd77c5ba268f0811afe180c0486d7820ed
   ▶️ Tests:  128040 executed
   ⚪️ Checks: 26/26 completed
   
   ---
   _Learn more about TestLens at 
[testlens.app/docs](https://testlens.app/docs/features/pr-comment/)._
   




> 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)

Reply via email to