Paul King created GROOVY-12540:
----------------------------------

             Summary: GroovyBugError when a primitive local variable has a 
TYPE_USE annotation
                 Key: GROOVY-12540
                 URL: https://issues.apache.org/jira/browse/GROOVY-12540
             Project: Groovy
          Issue Type: Bug
    Affects Versions: 6.0.0, 5.1.3
            Reporter: Paul King


h3. Problem

Compiling a local variable of primitive type that carries a {{TYPE_USE}} 
annotation fails with a {{GroovyBugError}}. The failure happens in dynamic and 
in {{@CompileStatic}} code, and for plain locals as well as {{for}}-loop 
variables.

{code:java}
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) public 
@interface TU {}
{code}

{code:groovy}
class Foo {
    static void m() {
        @TU int x = 0          // also: @TU long, @TU double, for (@TU int i = 
0; ...)
        println x
    }
}
{code}

{noformat}
BUG! exception in phase 'class generation' in source unit 'Foo.groovy'
Adding type annotation @TU to non-redirect node: java.lang.Integer
    at org.codehaus.groovy.ast.ClassNode.addTypeAnnotation(ClassNode.java)
    at org.codehaus.groovy.ast.ClassNode.addTypeAnnotations(ClassNode.java)
    at 
org.codehaus.groovy.classgen.ExtendedVerifier.extractTypeUseAnnotations(ExtendedVerifier.java)
    at 
org.codehaus.groovy.classgen.ExtendedVerifier.visitDeclarationExpression(ExtendedVerifier.java)
{noformat}

||Declaration||Result||
|{{@TU int x}} / {{@TU long x}} / {{@TU double x}} (local or for-loop)|crash 
(reports {{java.lang.Integer}} / {{Long}} / {{Double}})|
|{{@TU Integer x}}, {{@TU String s}}, {{@TU int[] x}} (local)|OK, annotation 
emitted|
|{{@TU int p}} (parameter), {{@TU int f}} (field)|OK, annotation emitted|

Tested: crashes on 5.0.6, 6.0.0-beta-2 and master. 4.0.32 compiles but emits no 
type annotation for the variable.

A real-world trigger is TornadoVM's {{@Parallel}} ({{@Target}} includes 
{{TYPE_USE}}), whose documented usage is {{for (@Parallel int i = 0; i < n; 
i++)}}.

h3. Cause

{{ExtendedVerifier.visitDeclarationExpression}} attaches the annotation to 
{{expression.getLeftExpression().getType()}}. For a primitive local, 
{{VariableExpression.getType()}} returns the boxed type, which is the shared 
{{ClassHelper.Integer_TYPE}} node (hence {{java.lang.Integer}} in the message 
for an {{int}}). That node is resolved and not a redirect, so 
{{ClassNode.addTypeAnnotation}} throws. The declared type is available from 
{{getOriginType()}}, a per-declaration redirect node (e.g. {{int -> int}}) that 
can safely carry the annotation.

h3. Proposed fix

In {{ExtendedVerifier.visitDeclarationExpression}}, use the variable's origin 
type, for both single and multiple-assignment declarations:

{code:java}
ClassNode type = expression.getVariableExpression().getOriginType();
{code}

Regression test added to {{TypeAnnotationsTest}} 
({{testTypeAnnotationsForPrimitiveLocalVariables}}): 
{{int}}/{{long}}/{{double}} locals each get a {{LOCAL_VARIABLE}} type 
annotation in the bytecode.



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

Reply via email to