leanprover / leanprover/lean4

`Lean.Meta.Sym.Simp.toHave` reverses dependencies when reconstructing `have` telescopes

Open Beginner friendly
#14,804 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P-medium
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Prerequisites
Description

Lean.Meta.Sym.Simp.toHave reverses dependencies when reconstructing have telescopes which, under the right circumstances, causes a kernel application type mismatch.

Context

When Lean.Meta.Sym.Simp.simpHave reconstructs a have telescope after simplification, it calls toHave. In toHave, dependencies are passed to Expr.betaRev in forward order (ys), but betaRev expects arguments in reversed order (revArgs).

As a result, any have binding whose value depends on two or more earlier bindings in the same telescope has its dependencies applied in reverse order, producing an ill-typed term that fails kernel type checking with an application type mismatch.

Steps to Reproduce

This self-contained reproduction requires no external dependencies or imports beyond Init:

def f (a : Nat) (b : Bool) : Nat := if b then a else 0

theorem test (y : Bool) :
    (have a := 1 + 1
     have b := y
     have c := f a b
     c = 0) := by
  sym =>
    simp
    sorry

Expected behavior: No error: (kernel) application type mismatch.

Actual behavior: We get the following error:

error: (kernel) application type mismatch
  f b
argument has type
  Bool
but function has type
  Nat → Bool → Nat
Versions

Tested on Lean 4.35.0-nightly-2026-08-17.

Additional Information

During simplification of have a := 1 + 1 to have a := 2, c := f a b is reconstructed as c := f b a. Because f has type Nat → Bool → Nat, b : Bool is passed where a : Nat is expected, causing the kernel to reject the proof term.

In Lean/Meta/Sym/Simp/Have.lean:255-258:

      let varPos := varDeps[i]
      let ys := varPos.map fun i => xs[i]!
      let type := consumeForallN t varPos.size
      let val ← share <| args[i].betaRev ys
  1. varDeps[i] and ys are ordered forward (e.g. #[a, b]).
  2. args[i] is fun a b => f a b.
  3. args[i].betaRev #[a, b] reduces to f b a because betaRev treats its argument array as revArgs (i.e., args.reverse).

To fix this, one could pass ys.reverse to betaRev (or use betaS/beta I suppose):

-      let val ← share <| args[i].betaRev ys
+      let val ← share <| args[i].betaRev ys.reverse
Impact

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in Lean/Meta/Sym/Simp/Have.lean at lines 255-258 and inspect how varDeps, ys, and betaRev order arguments during have-telescope reconstruction. Run the self-contained Init-only reproduction, then verify that simplification no longer produces the kernel application type mismatch.

Written by the indexing model from the issue text.

Assessment

Domain
compilers
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.