Paul King created GROOVY-12541:
----------------------------------
Summary: @CompileStatic silently drops type annotations on local
variables
Key: GROOVY-12541
URL: https://issues.apache.org/jira/browse/GROOVY-12541
Project: Groovy
Issue Type: Bug
Affects Versions: 6.0.0
Reporter: Paul King
h3. Problem
Under {{@CompileStatic}}, {{TYPE_USE}} annotations on local variables are not
written to the class file (no {{RuntimeVisibleTypeAnnotations}} entry with
target {{LOCAL_VARIABLE}}). The same source compiled dynamically emits them
correctly. No error or warning is given.
{code:groovy}
@groovy.transform.CompileStatic
class Foo {
static void m() {
@TU Integer n = 0
for (@TU Integer i = 0; i < 3; i++) { }
println n
}
}
{code}
||Code||Dynamic||{{@CompileStatic}}||
|{{for (@TU Integer i = 0; ...)}}|emitted|*not emitted*|
|{{@TU Integer n = 0}}|emitted|*not emitted*|
The same happens whether the annotation targets only {{TYPE_USE}} or
{{LOCAL_VARIABLE, TYPE_USE}}. Tested on 6.0.0-beta-2 and master. (Primitive
locals currently crash instead; see the related {{GroovyBugError}} issue. Once
that is fixed, they show this same drop under {{@CompileStatic}}.)
Tools that read local variable type annotations from bytecode (e.g. TornadoVM's
{{@Parallel}} loop marker) therefore never see them in statically compiled
Groovy.
h3. Cause
{{CompileStack}} writes local variable type annotations from
{{BytecodeVariable.getType()}}, the slot type passed to {{defineVariable}}. For
declarations, {{BinaryExpressionHelper.evaluateEqual}} gets that type from the
type chooser. The dynamic chooser returns the declared type node, which carries
the annotations. {{StaticTypesTypeChooser}} returns the type checker's inferred
type, a different node without them.
h3. Proposed fix
Record the declared type separately from the slot type and emit the annotations
from it:
* {{BytecodeVariable}}: new {{declaredType}} property; {{getDeclaredType()}}
falls back to {{getType()}} when none was recorded.
* {{CompileStack.defineVariable(Variable, ClassNode, boolean)}}:
{{answer.setDeclaredType(v.getOriginType())}}.
* {{CompileStack}} local variable table emission: read type annotations from
{{v.getDeclaredType()}} instead of {{v.getType()}}.
Regression test added to {{TypeAnnotationsTest}}
({{testTypeAnnotationsForLocalVariablesCompileStatic}}): a {{@CompileStatic}}
{{for (@A int i ...)}} loop and an annotated {{Integer}} local both get
{{LOCAL_VARIABLE}} type annotations.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)