fix(scala): match expression used in selector chain (semgrep/semgrep-proprietary#6011)
## Summary
Added Kmatch handling in three locations: (1) `path`'s DOT branch
returns early when Kmatch follows DOT, (2) `selectors` peeks ahead to
avoid consuming DOT before Kmatch, (3) `simpleExprRest`'s DOT branch
handles Kmatch for complex expression receivers. Also added a
`peekToken` helper for non-destructive lookahead.
**Root cause**: In `path` and `selectors`, the parser treats DOT as
always introducing an identifier selector. In Scala 3, `expr.match { ...
}` is valid postfix syntax where `match` is a keyword, not an
identifier, causing `ident` to error with 'expecting ident'.
cluster-5-78a8ae180571
## Changes
-
`OSS/languages/scala/recursive_descent/Parser_scala_recursive_descent.ml`
- `OSS/tests/parsing/scala/match_expr_selector.scala` (new test)
## Run Report
| Check | Result |
|-------|--------|
| Reproducer fails before fix | ✅ |
| Reproducer passes after fix | ✅ |
| Existing tests pass | ✅ (130 tests, 0 failures) |
| Parsing stats | ✅ 92.82% → 92.82% (no regression) |
### Reviewers
| Reviewer | Verdict | Findings | Fixed |
|----------|---------|----------|-------|
| Backwards Compat | ✅ | None | 0 |
| AST Fidelity | ✅ | None | 0 |
| Test Coverage | ✅ | Test covers `reserve.match` (single-level) but not
`a.b.match` (multi-level dotted path). The selectors fix handles this
case but it lacks a dedicated test. | 0 |
| Redundancy | ✅ | The Kmatch handling in simpleExprRest and the Kmatch
case in path's DOT branch both produce Match nodes. The simpleExprRest
case handles complex expressions like (1+2).match while the path case
handles simple identifiers like reserve.match. Both are needed for
different code paths. | 0 |
### Cost
- **Tokens**: 44,719,418 total, 353 tool uses
- **Estimated cost**: $49.43
- **Wall time**: 1177m10s
### Unresolved
None
### Checklist
- ✅ Reproducer constructed and saved to file
- ✅ Bug reproduction tested — set result to 'yes' or 'already_fixed'
- ✅ Failing test written and confirmed to fail before fix
- ✅ Fix compiles (make core succeeds)
- ✅ Reproducer passes after fix
- ✅ Regression test written and passes
- ✅ verify.py run and verification.json written
- ✅ Existing tests pass (or failures are pre-existing)
- ✅ Parsing stats before/after compared (no regression)
- ✅ Snapshots approved (both root and OSS binaries) and git-added
- ✅ Changes committed with conventional commit message
- ✅ All 4 self-review JSONs written with diff actually read
- ✅ Critical/warning review findings addressed
- ✅ run-report.json written
- ✅ PR pushed via push_pr.py
---
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
synced from Pro d869eeaa807a065244df6544a661498142f192d8 B
Brandon Wu committed
bdfab7dcdc9caeab660fb69fa05f1eda574101f3
Parent: 6f5ca0e
Committed by Yosef <72322110+yosefAlsuhaibani@users.noreply.github.com>
on 4/6/2026, 12:56:09 AM