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)