`grind`: kernel error because `abstractGroundMismatches?` passes the abstracted terms in reverse order
Maintainers usually reply within 1 day
A pull request for this has already been merged.
- #15829 by @leodemoura — merged
Assessment
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Newbie friendliness
- 35/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Domain
- compilers
Research direction
Start in Lean/Meta/Tactic/Grind/ProveEq.lean, in abstractGroundMismatches? and the go helper whose (lhs, rhs) cache ignores offset. Reproduce with the headPos example, where the kernel reports an argument-order mismatch, and with the dep example. Done when both examples are accepted by the kernel, the abstracted terms are bound in the right order, and the cache key includes offset.
Written by the indexing model from the issue text.
Description
Prerequisites
- Check that your issue is not already filed:
https://github.com/leanprover/lean4/issues - Reduce the issue to a minimal, self-contained, reproducible test case.
Avoid dependencies to Mathlib or Batteries. - Test your test case against the latest nightly release, for example on
https://live.lean-lang.org/#project=lean-nightly
(You can also use the settings there to switch to “Lean nightly”)
Description
The kernel rejects proofs produced by grind because an internal helper, abstractGroundMismatches?, passes the abstracted terms to its auxiliary function in reverse order. Ordinary code triggers it: grind [f], where f has a precondition such as "all elements are positive", stated by index.
Context
The goal is true: subst hx; rfl proves it, and so does subst hx; grind [headPos]. grind [headPos] also succeeds when the precondition mentions xs only once, for example ∀ i, i < xs.length → 0 < i + 1.
Steps to Reproduce
Run this file (no imports):
def headPos (xs : List Nat) (h : ∀ i, i < xs.length → 0 < xs[i]!) : Nat :=
match xs with
| a :: _ => a
| [] => 1
example (xs : List Nat) (h : ∀ i, i < xs.length → 0 < xs[i]!) (hx : xs = [3]) : headPos xs h = 3 := by
grind [headPos]
Expected behavior: grind proves the goal.
Actual behavior: The kernel rejects the generated proof:
error: (kernel) application type mismatch
Lean.Grind.abstractFn (fun _x_0 _x_0_1 => ∀ (i : Nat), i < _x_0_1 → 0 < _x_0 i) xs.length
argument has type
Nat
but function has type
(Nat → Nat) → Nat → Prop
Versions
4.36.0-nightly-2026-10-14
Additional Information
In abstractGroundMismatches? (Lean/Meta/Tactic/Grind/ProveEq.lean), the k-th abstracted term is bound by the k-th innermost binder of the auxiliary lambda, but mkAppN f s.lhss / mkAppN f s.rhss pass the first term to the outermost one. With two or more abstracted terms (here xs.length and getElem! xs), the arguments are reversed. Suggested fix:
return some (mkAppN f s.lhss.reverse, mkAppN f s.rhss.reverse)
Related: the (lhs, rhs) cache in go ignores offset, so a pair met again under more binders reuses a stale de Bruijn index, and grind throws an internal error. Suggested fix: add offset to the cache key.
def dep (x : Option Nat) (h : ∀ a, x = some a → ∀ b, x = some b → a = b) : Nat :=
match x with
| some a => a
| none => 0
example (x : Option Nat) (hx : x = some 1) (H : ∀ a, x = some a → ∀ b, x = some b → a = b) :
dep x H = 1 := by
grind [dep]
Impact
Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.
- Dominant language
- Lean
- Stars
- 9.8k
- Forks
- 1.1k
- Avg merge
- 14h 41m
- Merged PRs (30d)
- 338
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from leanprover/lean4
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
leanprover/lean4#15982 · 2 comments ·
Maintainers usually reply within 1 day
-
`IO.appPath` fails when `/proc` belongs to another PID namespacePossibly taken @treiher claimed this 14 days ago. Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
leanprover/lean4#15692 · 3 reactions ·
Maintainers usually reply within 1 day
-
`IO.FS.realPath` reports every failure as `noFileOrDirectory` instead of classifying by `errno`Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 66/100
leanprover/lean4#15683 ·
Maintainers usually reply within 1 day
-
`Child.pid` leaks the `Child` and its pipe file descriptors (owned argument treated as borrowed)Openbug
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
leanprover/lean4#15681 ·
Maintainers usually reply within 1 day
-
`Child.takeStdin` loses `setsid`, so `Child.kill` only signals the child, not its process groupOpenbug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
leanprover/lean4#15674 ·
Maintainers usually reply within 1 day
All issues in leanprover/lean4
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
needs-triage type: bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
pytorch/executorch#24434 ·
Maintainers usually reply within 1 day
-
bug devex good first issue
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
calcit-lang/calcit#2538 ·
Maintainers usually reply within 1 day