Scott Murphy Heiberg created GROOVY-12698:
---------------------------------------------

             Summary: STC: annotations on a multiple-assignment declaration are 
silently dropped by @CompileStatic
                 Key: GROOVY-12698
                 URL: https://issues.apache.org/jira/browse/GROOVY-12698
             Project: Groovy
          Issue Type: Bug
    Affects Versions: 6.0.0
            Reporter: Scott Murphy Heiberg


*Affects Version:* 6.0.0 (also the GROOVY_6_0_X branch at 6.0.1-SNAPSHOT and 
master at 7.0.0-SNAPSHOT)
*Environment:* macOS 26.5, JDK 21.0.12 (BellSoft Liberica); groovy / groovyc 
command line, same result with GroovyShell

h3. Problem

Inside a {{@CompileStatic}} class (or method), annotations placed on a 
multiple-assignment declaration such as {{def (a, b) = ...}} are lost before 
the class is generated. As a consequence the usual annotation checks are 
skipped for that declaration: a plainly misplaced annotation is accepted 
without any diagnostic.

{code:groovy}
@groovy.transform.CompileStatic
class C {
    void m() {
        @Override def (a, b) = [1, 2]
        println a + b
    }
}
new C().m()
{code}

{noformat}
$ groovy multi.groovy
3
{noformat}

The same declaration in a dynamic class, or a single declaration {{@Override 
def a = 1}} in the static class, is rejected as expected:

{noformat}
multi.groovy: 4: Annotation @java.lang.Override is not allowed on element 
LOCAL_VARIABLE
 @ line 4, column 9.
           @Override def (a, b) = [1, 2]
           ^

1 error
{noformat}

The duplicate-annotation check is skipped in the same way: {{@Deprecated 
@Deprecated def (a, b) = [1, 2]}} compiles and runs in a {{@CompileStatic}} 
class, while the dynamic class reports "Cannot specify duplicate annotation on 
the same member : java.lang.Deprecated".

h3. Expected behaviour

A multiple-assignment declaration under static compilation should keep its 
annotations, so that the static class reports the same diagnostics as the 
dynamic class:

{noformat}
Annotation @java.lang.Override is not allowed on element LOCAL_VARIABLE
{noformat}

A multiple assignment carrying a valid local-variable annotation (for example 
{{@SuppressWarnings('unused') def (a, b) = [1, 2]}}) must of course keep 
compiling.

h3. Cause

{{org.codehaus.groovy.transform.sc.transformers.BinaryExpressionTransformer#transformMultipleAssignment}}
 (instruction selection phase) rewrites {{def (a, b) = [1, 2]}} into one 
{{DeclarationExpression}} per variable ({{def a = 1}}, {{def b = 2}}). Each new 
declaration is built with {{new DeclarationExpression(left, operation, right)}} 
followed only by {{setSourcePosition(right)}}; the annotations of the original 
declaration are not copied, unlike 
{{DeclarationExpression#transformExpression}}, which copies them. 
{{ExtendedVerifier}} runs later (class generation phase) and performs the 
target and duplicate checks on the rebuilt declarations, which by then carry no 
annotations. Any later-phase transformation that inspects annotations on local 
variable declarations is affected in the same way.

Copying the annotations onto each rebuilt single declaration restores the 
checks: the static class then reports the diagnostic once per declared 
variable, which is also what {{@Override def a = 1, b = 2}} reports in both 
dynamic and static classes. A pull request with regression tests follows.

h3. Reproduces on

Groovy 6.0.0 (release), Groovy 6.0.1-SNAPSHOT (GROOVY_6_0_X at 7c0dcf17dd) and 
Groovy 7.0.0-SNAPSHOT (master at d86ea7eb85).



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to