[
https://issues.apache.org/jira/browse/GROOVY-12289?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Paul King resolved GROOVY-12289.
--------------------------------
Fix Version/s: 6.0.0-beta-3
Resolution: Fixed
> Switch expressions with duplicate case labels compile under @TypeChecked but
> fail under @CompileStatic
> ------------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12289
> URL: https://issues.apache.org/jira/browse/GROOVY-12289
> Project: Groovy
> Issue Type: Bug
> Reporter: Paul King
> Assignee: Paul King
> Priority: Minor
> Fix For: 6.0.0-beta-3
>
>
> Switch expressions with duplicate constant case labels compile under
> {{@TypeChecked}} (and dynamic Groovy) but fail under {{@CompileStatic}}:
> {code:groovy}
> def m(int x) {
> def r = switch (x) {
> case 1 -> 'a'
> case 1 -> 'b' // dead code: first match wins
> default -> 'c'
> }
> r
> }
> {code}
> Dynamic and {{@TypeChecked}}: compiles; sequential {{isCase}} semantics mean
> the first matching arm wins. {{@CompileStatic}}: fails with {{Duplicate case
> label: 1}}, raised from {{StaticTypesSwitchExpressionWriter}} when the
> tableswitch/lookupswitch optimizer finds a repeated key. Reproduces for
> int-family, String and enum constant labels.
> Two problems:
> # *Mode divergence.* Whether the code compiles should not depend on the
> compilation mode (or on whether a bytecode optimizer happens to apply —
> mixing a duplicated constant with a dynamic label, e.g. {{case 1; case 1;
> case foo()}}, silently disabled the optimizer and compiled fine under
> {{@CompileStatic}}).
> # *Broken error reporting.* The writer reports the error mid-codegen and then
> continues, so ASM also reports a processing error on the truncated method —
> the user sees a confusing secondary failure.
> *Fix:* detect repeated constant labels (int-family, String and enum constants
> — the same keys the optimizers use, via the shared {{SwitchExpressionUtils}}
> extractors) in {{StaticTypeCheckingVisitor}}, so {{@TypeChecked}} and
> {{@CompileStatic}} both report {{[Static type checking] - Duplicate case
> label: ...}} at the offending label. The static writer no longer errors: a
> duplicate key just skips the optimizer like any other non-optimizable shape
> and falls back to sequential first-match-wins dispatch. That path is only
> reachable when type checking is bypassed ({{TypeCheckingMode.SKIP}} or a
> type-checking extension), where dynamic semantics are the intent — previously
> it crashed codegen.
> Unchanged: dynamic Groovy, switch *statements*, and non-constant labels
> (GStrings, calls, ranges) — those cannot be proven duplicated statically.
> Note one deliberate tightening: duplicated constants mixed with dynamic
> labels now error in both modes (previously accepted under {{@CompileStatic}}
> because the optimizer bailed out silently).
> *Escape hatch:* a DSL that wants first-match-wins duplicate labels under
> {{@TypeChecked}} can opt affected methods out via a type-checking extension
> ({{beforeVisitMethod \{ mn -> handled = true \}}}); the method then compiles
> and dispatches dynamically. This is method-granular — there is no per-switch
> waiver. Covered by a new test using {{Groovy12289Extension.groovy}}.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)