Skip to content

fix: format choice nodes from duplicate syntax without uncaught backtrack - #14696

Open
jcreinhold wants to merge 1 commit into
leanprover:masterfrom
jcreinhold:fix-formatter-choice-node
Open

fix: format choice nodes from duplicate syntax without uncaught backtrack#14696
jcreinhold wants to merge 1 commit into
leanprover:masterfrom
jcreinhold:fix-formatter-choice-node

Conversation

@jcreinhold

Copy link
Copy Markdown
Contributor

This PR fixes the pretty printer throwing format: uncaught backtrack exception on binders whose type is a doubly-declared notation (fixes #14611), and fixes tactic blocks and other sepByIndent sequences being silently truncated when a separator swallowed the same failure.

Declaring the same notation tokens twice (e.g. mathlib's ) makes the parser pack both parses into a choice node. The two choice branches in Formatter.lean each mishandled it:

  • categoryFormatterCore left the cursor on the previous alternative instead of past the choice, so the enclosing walk looked for the next token (e.g. a binder's :) in the wrong place.
  • orelse.formatter re-ran its own productions on the bare alternative. Those productions expect siblings that live outside the choice, so this always backtracked — unless the choice was the orelse's own (an antiquot choice), the case the branch exists for.

The fix adds visitChosenChoice, which formats the last alternative and restores the cursor to the choice's left sibling. The orelse branch falls back to running its right-hand production at the choice itself, routing the choice to its own position's formatter. The "format only last choice" heuristic and the output of all previously-successful inputs are unchanged.

Adds tests/elab/formatChoiceNode.lean covering the binder crash, the previously-working positions, and the silent truncation.

…ktrack

This PR fixes the pretty printer throwing `format: uncaught backtrack
exception` on commands with a binder whose whole type is a doubly-declared
notation (leanprover#14611), and `sepByIndent` sequences (e.g. tactic blocks) being
silently truncated when the same backtrack was swallowed by a separator.

A `choice` node packs every successful parse of one byte range as siblings,
and the two choice branches each broke the traversal protocol differently:
`categoryFormatterCore` left the cursor on another alternative instead of
past the choice, and `orelse.formatter` re-ran its own productions on a
bare alternative whose required siblings live outside the choice. Add
`visitChosenChoice`, which formats the last alternative and restores the
cursor to the choice's left sibling, and let the `orelse` branch fall back
to running its right side at the choice itself, routing ambiguous inner
choices to their own formatter.
@jcreinhold
jcreinhold requested a review from kmill as a code owner August 5, 2026 21:29
@github-actions github-actions Bot added the toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN label Aug 5, 2026
@mathlib-lean-pr-testing

Copy link
Copy Markdown

Mathlib CI status (docs):

  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 16fafca7fe94ea23edc0ddab9bb2f98f603df7d5 --onto f2bcf2e8660ab2d16cf3cb50c8e127de0439a337. You can force Mathlib CI using the force-mathlib-ci label. (2026-08-05 21:54:44)

@leanprover-bot

Copy link
Copy Markdown
Collaborator

Reference manual CI status:

  • ❗ Reference manual CI will not be attempted unless your PR branches off the nightly-with-manual branch. Try git rebase 16fafca7fe94ea23edc0ddab9bb2f98f603df7d5 --onto 23393b959b33e3a8d15796b2397f8a04c315b9f4. You can force reference manual CI using the force-manual-ci label. (2026-08-05 21:54:46)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

toolchain-available A toolchain is available for this PR, at leanprover/lean4-pr-releases:pr-release-NNNN

Projects

None yet

Development

Successfully merging this pull request may close these issues.

formatCommand throws uncaught backtrack exception when a binder's type uses a doubly-declared notation

2 participants