Skip to content

A case label with several patterns keeps all of them (#171) - #172

Merged
bnaudts merged 2 commits into
develfrom
fix/multi-pattern-case-labels
Oct 26, 2026
Merged

bnaudts merged 2 commits into
develfrom
fix/multi-pattern-case-labels

Conversation

@tomtourwe

Copy link
Copy Markdown
  • This PR's base branch is devel.

What this changes, and why

Fixes #171. A case label with several patterns (JEP 456, case A _, B _ ->) kept only one of them: maddi-java-openjdk the first, maddi-java-parser the last. SwitchEntry.otherPatterns() now holds the patterns after the first. It is a default method returning an empty list, so no implementor or caller has to change. Both front ends fill it, and every reader of a switch entry's pattern takes it into account:

  • SwitchEntryImpl: typesReferenced, the Java printer, translate, rewire, its own walk and its variable streams;
  • SwitchExpressionImpl and SwitchStatementNewStyleImpl: the walk of the whole switch;
  • the Kotlin printer: is A, is B ->. An entry counts as a type-pattern arm only when all its patterns are type patterns;
  • the C# printer, in switch statements and switch expressions: case A or B: / A or B =>, each alternative as its type alone.

The old-style switch needed no change: each label is its own SwitchLabel. The only other reader of a switch entry's pattern found outside maddi, refactor-base's AstToMap, is fixed in refactor-base separately.

Checks

  • ./gradlew build passes. Not run in full locally; left to CI. Run locally: maddi-cst-impl, maddi-java-openjdk and maddi-java-parser tests, 994 tests, 0 failures, before the printer commit; TestJavaToKotlinStructure (118) and TestJavaToCSharpStructure (69), 0 failures, after it.
  • New or changed behaviour has a test, and each one failed before the change: TestSwitchExpression.test3 and test4, TestSwitchNewStyle.testWalkReachesEveryPattern, TestJavaToKotlinStructure.multiPatternCase (the Kotlin compiles), TestJavaToCSharpStructure.multiPatternCase. The golden file of the C# test is the correct translation, written by hand: the first run recorded the defective one.
  • No test parses a real-world corpus.
  • Every commit is signed off (git commit -s).

If this touches the engine

  • Not an engine change — skip this section.
  • FPDUMP A/B run, byte-identical.
  • Verdicts do change, deliberately.

Not run. The change is in the front ends and the model, not in the link engine or the analysis. But the model now holds patterns it used to drop, so an analysis over code with multi-pattern labels can see more references than before. Whether verdicts change on the proving-ground corpora is not established.

If this changes what the analyzer means

  • Not a concept change — skip.

Licence

All touched modules are LGPL-3.0.

Tom Tourwe added 2 commits October 26, 2026 14:49
Java allows several patterns in one label when none binds a variable (JEP 456): case VarcharType _, CharType _ ->.
SwitchEntry held one pattern, and the two front ends lost the rest: maddi-java-openjdk kept the first and dropped
the others, maddi-java-parser set each in turn and kept the last. So the type of every other pattern was missing
from the model. Found on trino 817f7034667, PathEvaluationVisitor: typesReferenced did not report CharType, and a
dead-code removal took the file's import of CharType from under two live uses.

SwitchEntry.otherPatterns() holds the patterns after the first (a default method returning an empty list, so no
implementor or caller has to change), and both front ends fill it. SwitchEntryImpl takes them into
typesReferenced, the Java printer (case A _ alone compiles and no longer matches B), translate, rewire, its own
visit and its variable streams; the walks of SwitchExpressionImpl and SwitchStatementNewStyleImpl visit them too.
The old-style switch already kept every pattern, one SwitchLabel each.

TestSwitchExpression.test3 (types referenced and printing) and test4, TestSwitchNewStyle.testWalkReachesEveryPattern
(the walk): each failed before the change.

Signed-off-by: Tom Tourwe <Tom.Tourwe@codelaser.io>
…e label

case String _, Integer _ -> was translated from its first pattern only: Kotlin's is String -> and C#'s
case string : (and string => in a switch expression). Both compile and no longer match an Integer. Kotlin now
prints is String, is Int ->; an entry counts as a type-pattern arm only when every one of its patterns is a type
pattern, since is T tests the type and a deconstruction does not reduce to that. C# prints the or pattern,
case string or int: and string or int =>, each alternative as its type alone, because C# allows no designation
under or and Java allows none in a multi-pattern label.

TestJavaToKotlinStructure.multiPatternCase (the Kotlin compiles) and TestJavaToCSharpStructure.multiPatternCase,
whose golden file is the correct translation, written by hand: the first run recorded the defective one.

Signed-off-by: Tom Tourwe <Tom.Tourwe@codelaser.io>
@bnaudts
bnaudts merged commit be1bb19 into devel Oct 26, 2026
3 checks passed
bnaudts pushed a commit that referenced this pull request Oct 26, 2026
…imports in the openjdk tests

TestParseSwitchExpression.test4: 'case A _, B _ ->' keeps A as the entry's pattern and B in otherPatterns, references
both and walks both. It fails on CommonParse from before #172, which set each pattern in turn as the entry's only
one and kept B. The tests #172 added in maddi-java-openjdk import RecordPattern, List and ArrayList instead of
writing them out.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XvjJAyRxVxwChWpVMUPTJ7
Signed-off-by: Bart Naudts <Bart.Naudts@codelaser.io>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants