[
https://issues.apache.org/jira/browse/GROOVY-12190?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King updated GROOVY-12190:
-------------------------------
Description:
Reproducer confirmed: fails on 5.0.6 with `MissingPropertyException`, passes on
4.0.27. Here's the description in JIRA wiki markup:
```
Since the follow-up refactor for GROOVY-11614 (4.0.28, 5.0.0), unqualified enum
constants in {{switch}} case labels under {{@TypeChecked}} (without static
compilation) pass type checking but throw {{MissingPropertyException}} at
runtime. This worked correctly from Groovy 3.0.0 (GROOVY-8444) through 4.0.27.
h3. Reproducer
{code:groovy}
enum Color { RED, GREEN, BLUE }
@groovy.transform.TypeChecked
def m(Color c) {
switch (c) {
case GREEN: return 'matched'
default: return 'default'
}
}
assert m(Color.GREEN) == 'matched'
{code}
*Expected* (and actual on 3.0.0–4.0.27): the assert passes.
*Actual* on 4.0.28+, 5.x and master:
{noformat}
groovy.lang.MissingPropertyException: No such property: GREEN for class: repro
at repro.m(repro.groovy:6)
at repro.run(repro.groovy:10)
{noformat}
The same failure occurs with switch expressions ({{case GREEN -> 'matched'}}) —
same root cause, so both forms are covered by this issue. With
{{@CompileStatic}} both forms work correctly.
h3. Root cause
{{EnumTypeCheckingExtension#handleUnresolvedVariableExpression}} resolves the
bare constant during type checking (so no compile error is reported), and the
follow-up commit for GROOVY-11614 (81098ecb52, "SC: apply enum-case
transformation after STC visitation") moved the {{CONST}} →
{{EnumType.CONST}} rewrite from {{CompilationUnit}} into
{{VariableExpressionTransformer}}, which only runs under static compilation.
So in TC-only mode the type checker vouches for the reference, but the
generated bytecode still performs a dynamic property lookup on the enclosing
class, which fails at runtime. {{Groovy8444.groovy}} only exercises
{{@CompileStatic}}, so no test caught the regression.
h3. Possible fixes
* Apply the enum-case rewrite after STC visitation for type-checked (non-SC)
code as well, restoring the 3.x/4.0.x behaviour; or
* Have {{EnumTypeCheckingExtension}} decline to resolve the constant outside
static compilation, so TC code at least fails at compile time rather than
runtime.
Either way, {{Groovy8444.groovy}} should gain {{@TypeChecked}} variants of the
switch statement and switch expression tests.
h3. Workarounds
Qualify the constant ({{case Color.GREEN:}}), add
{{import static Color.*}}, or use {{@CompileStatic}}.
```
A couple of field suggestions to go with it: affects versions 4.0.28+ and
5.0.0+ (still present on master/6.0.0-SNAPSHOT); link "is caused by"
GROOVY-11614 and "relates to" GROOVY-8444.
> @TypeChecked switch on enum: unqualified case constants pass type checking
> but throw MissingPropertyException at runtime
> ------------------------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12190
> URL: https://issues.apache.org/jira/browse/GROOVY-12190
> Project: Groovy
> Issue Type: Bug
> Reporter: Paul King
> Priority: Major
>
> Reproducer confirmed: fails on 5.0.6 with `MissingPropertyException`, passes
> on 4.0.27. Here's the description in JIRA wiki markup:
> ```
> Since the follow-up refactor for GROOVY-11614 (4.0.28, 5.0.0), unqualified
> enum
> constants in {{switch}} case labels under {{@TypeChecked}} (without static
> compilation) pass type checking but throw {{MissingPropertyException}} at
> runtime. This worked correctly from Groovy 3.0.0 (GROOVY-8444) through 4.0.27.
> h3. Reproducer
> {code:groovy}
> enum Color { RED, GREEN, BLUE }
> @groovy.transform.TypeChecked
> def m(Color c) {
> switch (c) {
> case GREEN: return 'matched'
> default: return 'default'
> }
> }
> assert m(Color.GREEN) == 'matched'
> {code}
> *Expected* (and actual on 3.0.0–4.0.27): the assert passes.
> *Actual* on 4.0.28+, 5.x and master:
> {noformat}
> groovy.lang.MissingPropertyException: No such property: GREEN for class: repro
> at repro.m(repro.groovy:6)
> at repro.run(repro.groovy:10)
> {noformat}
> The same failure occurs with switch expressions ({{case GREEN -> 'matched'}})
> —
> same root cause, so both forms are covered by this issue. With
> {{@CompileStatic}} both forms work correctly.
> h3. Root cause
> {{EnumTypeCheckingExtension#handleUnresolvedVariableExpression}} resolves the
> bare constant during type checking (so no compile error is reported), and the
> follow-up commit for GROOVY-11614 (81098ecb52, "SC: apply enum-case
> transformation after STC visitation") moved the {{CONST}} →
> {{EnumType.CONST}} rewrite from {{CompilationUnit}} into
> {{VariableExpressionTransformer}}, which only runs under static compilation.
> So in TC-only mode the type checker vouches for the reference, but the
> generated bytecode still performs a dynamic property lookup on the enclosing
> class, which fails at runtime. {{Groovy8444.groovy}} only exercises
> {{@CompileStatic}}, so no test caught the regression.
> h3. Possible fixes
> * Apply the enum-case rewrite after STC visitation for type-checked (non-SC)
> code as well, restoring the 3.x/4.0.x behaviour; or
> * Have {{EnumTypeCheckingExtension}} decline to resolve the constant outside
> static compilation, so TC code at least fails at compile time rather than
> runtime.
> Either way, {{Groovy8444.groovy}} should gain {{@TypeChecked}} variants of the
> switch statement and switch expression tests.
> h3. Workarounds
> Qualify the constant ({{case Color.GREEN:}}), add
> {{import static Color.*}}, or use {{@CompileStatic}}.
> ```
> A couple of field suggestions to go with it: affects versions 4.0.28+ and
> 5.0.0+ (still present on master/6.0.0-SNAPSHOT); link "is caused by"
> GROOVY-11614 and "relates to" GROOVY-8444.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)