Skip to content

fix: apply rcases substitution before recording pattern info#13621

Draft
berberman wants to merge 2 commits intoleanprover:masterfrom
berberman:rcases-info
Draft

fix: apply rcases substitution before recording pattern info#13621
berberman wants to merge 2 commits intoleanprover:masterfrom
berberman:rcases-info

Conversation

@berberman
Copy link
Copy Markdown

@berberman berberman commented May 3, 2026

This PR fixes a bug in the rcases-family tactics where the InfoView could give "unknown free variable" errors when the cursor was inside the pattern. It hoists applying the fvar substitution to give addTermInfo' and addLocalVarInfo the correct expression. Previously, the substitution only happened in rfl/typed/tuple/alternative branches, which caused stale free variables to be recorded in the info tree. Repeated applications in recursive cases like .paren should be fine, because the domain of fs should be old fvars and replacement exprs should only refer current-goal fvars, not old-domain fvars. Proof elaboration shouldn't be affected by this PR.

The fix was suggested by @kmill.

Closes #12369

This PR hoists `fs.apply` to let `addTermInfo'` and `addLocalVarInfo` use correct expr.
Previously, the substitution only happened in `rfl`/typed/tuple/alternative branches, which caused stale free variables to be recorded in the info tree.
Repeated applications in recursive cases like `.paren` should be fine, because the domain of `fs` should be old fvars and replacement exprs should only refer current-goal fvars, not old-domain fvars.
Proof elaboration shouldn't be affected by this PR.
@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 May 3, 2026
@mathlib-lean-pr-testing
Copy link
Copy Markdown

mathlib-lean-pr-testing Bot commented May 3, 2026

Mathlib CI status (docs):

  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 030397785c997509dad40e3c17e8793de04ef1ef --onto 0a6c31520b2ebaa6e71227454b46ebfb4986ae7b. You can force Mathlib CI using the force-mathlib-ci label. (2026-05-03 03:36:54)
  • ❗ Batteries/Mathlib CI will not be attempted unless your PR branches off the nightly-with-mathlib branch. Try git rebase 030397785c997509dad40e3c17e8793de04ef1ef --onto fe3c7394fd3acb1faecf6fc26f267eb22058fe66. You can force Mathlib CI using the force-mathlib-ci label. (2026-05-03 22:58:35)

@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 030397785c997509dad40e3c17e8793de04ef1ef --onto 3fc99eef102549c743c6c63547983319bfae6f01. You can force reference manual CI using the force-manual-ci label. (2026-05-03 03:36:56)

cont g fs clears a
| .clear ref =>
Term.addTermInfo' ref (.mdata {} e)
cont g fs (if let .fvar e := e then clears.push e else clears) a
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change potentially affects the clears list, but it might take some work coming up with an example that shows any difference. In any case, Lean.Elab.Tactic.RCases.finish applies the FVarSubst, though I notice it's doing it non-recursively (that's might be another bug).

Here's at least a case that currently fails on the most recent release that you could add to your test file:

example (n m : Nat) (h : n = m) : True := by
  rcases n, h with ⟨_ | _, -⟩
                         --^ unknown free variable `_fvar.1009`
  sorry
  sorry

I suspect you may be able to come up with an example where - doesn't clear things if one of the previous patterns created FVarSubst entries.

It would be nice to have a test case for .alts too demonstrating the fix, to prevent any regressions in the future.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your review. I think clears is OK with this change. Before this patch, - could record the original fvar, but finish maps every recorded clear target through the final FVarSubst, so previous substitutions were accounted for when clearing. Now - should record the current fvar instead, and fs.get in finish should be harmless for those.

Also I think a single fs.get should be enough, because FVarSubst maintains compositional substitutions: insert rewrites existing mapped values, and append preserves (s.append t).apply e = t.apply (s.apply e). So if a cleared variable is later replaced by a new fvar, fs.get gives current fvar which makes - work.

I've added more tests, though multi-branch .alts was not a failure before the patch.

@kmill kmill added the changelog-tactics User facing tactics label May 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

changelog-tactics User facing tactics 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.

unknown free variable in the info-view with rcases patterns

3 participants