Goal
Eliminate the Menhir parser conflicts that print on every dune build
(currently 75 shift/reduce + 10 reduce/reduce, post-#214) — they
alarm users into thinking the toolchain is broken when it is not. This
Menhir (20260209) has no %expect/--expect mechanism (verified
via --help), so there is no honest "declare reviewed" silencer: the
warnings can only be removed by genuinely resolving each conflict
(explicit precedence / token de-overload / left-factoring) with
provably-identical parse behaviour — the full dune test --force
gate (257/257) must stay green at every step.
Dedicated, rigorous, one-conflict-family-per-PR effort. STAGE-C (#160)
is paused until this lands or is explicitly de-prioritised.
Root-cause families (from menhir --explain)
- A. Effect-row
MINUS overload — type_expr_arrow legacy form
T -{ E }-> U (parser.mly:410) shares the MINUS token with
arithmetic minus; conflicts with the base reduce
type_expr_arrow -> type_expr_primary (parser.mly:419) on lookahead
MINUS/ARROW (state 41). A newer SLASH-based effect-row form
(parser.mly:219/230) already exists specifically to avoid this. Menhir's
shift is always correct (no subtraction in type position).
- B. Bare
return <expr> greedy operator-continuation — return e
where e can continue with a binary operator; single root, many
operator-token states (217/220/226/228/236/247…).
- C.
{ block-vs-record-literal after try/match/if/return/
resume (states 101/108/109/134/206…).
- D. Block-expression vs block-statement reduce/reduce (states
185/362/369/401).
Ordered plan (one PR per family; 257-gate + conflict-count delta each)
- PR-1 — Family A (effect-row MINUS) (user-prioritised first):
make the state-41 resolution explicit via precedence that codifies
the already-correct shift; behaviour-preserving, no surface-syntax
change. If precedence cannot fully clear it, escalate the legacy
-{E}-> removal as a surface-syntax design fork (separate decision).
- PR-2 — Family B (return greedy): restructure
return/resume
to take a full expr so the operator-continuation is unambiguous.
- PR-3 — Family C (
{ block/record): left-factor the
block-vs-record decision (the well-known Rust/Swift-style fix).
- PR-4 — Family D (block expr/stmt R/R): resolve the residual
reduce/reduce.
- PR-5 — sweep: re-run
menhir --explain, confirm zero conflicts,
remove now-stale conflict commentary, document in docs/.
Each PR: rigorous root-cause (not suppression), dune test --force
257/257 before commit, conflict-count reported in the PR body, and a
note if any generated-automaton behaviour could differ (it must not).
Done when
dune build prints zero conflict warnings, gate green, no
surface-syntax regression (or any surface change explicitly approved).
🤖 Generated with Claude Code
Goal
Eliminate the Menhir parser conflicts that print on every
dune build(currently 75 shift/reduce + 10 reduce/reduce, post-#214) — they
alarm users into thinking the toolchain is broken when it is not. This
Menhir (20260209) has no
%expect/--expectmechanism (verifiedvia
--help), so there is no honest "declare reviewed" silencer: thewarnings can only be removed by genuinely resolving each conflict
(explicit precedence / token de-overload / left-factoring) with
provably-identical parse behaviour — the full
dune test --forcegate (257/257) must stay green at every step.
Dedicated, rigorous, one-conflict-family-per-PR effort. STAGE-C (#160)
is paused until this lands or is explicitly de-prioritised.
Root-cause families (from
menhir --explain)MINUSoverload —type_expr_arrowlegacy formT -{ E }-> U(parser.mly:410) shares theMINUStoken witharithmetic minus; conflicts with the base reduce
type_expr_arrow -> type_expr_primary(parser.mly:419) on lookaheadMINUS/ARROW(state 41). A newer SLASH-based effect-row form(parser.mly:219/230) already exists specifically to avoid this. Menhir's
shift is always correct (no subtraction in type position).
return <expr>greedy operator-continuation —return ewhere
ecan continue with a binary operator; single root, manyoperator-token states (217/220/226/228/236/247…).
{block-vs-record-literal aftertry/match/if/return/resume(states 101/108/109/134/206…).185/362/369/401).
Ordered plan (one PR per family; 257-gate + conflict-count delta each)
make the state-41 resolution explicit via precedence that codifies
the already-correct shift; behaviour-preserving, no surface-syntax
change. If precedence cannot fully clear it, escalate the legacy
-{E}->removal as a surface-syntax design fork (separate decision).return/resumeto take a full
exprso the operator-continuation is unambiguous.{block/record): left-factor theblock-vs-record decision (the well-known Rust/Swift-style fix).
reduce/reduce.
menhir --explain, confirm zero conflicts,remove now-stale conflict commentary, document in
docs/.Each PR: rigorous root-cause (not suppression),
dune test --force257/257 before commit, conflict-count reported in the PR body, and a
note if any generated-automaton behaviour could differ (it must not).
Done when
dune buildprints zero conflict warnings, gate green, nosurface-syntax regression (or any surface change explicitly approved).
🤖 Generated with Claude Code