Zulip Chat Archive

Stream: general

Topic: v4.18.0 regression on well-founded recursion


pandaman (Apr 02 2025 at 10:37):

I'm updating lean-regex from v4.17.0 to v4.18.0, but Lean started to fail typecheck a function with a well-founded recursion. Here is a minimized example

#eval Lean.versionString

-- REPRO: SparseSet needs to take a parameter to reproduce.
structure SparseSet (n : Nat) where

def SparseSet.insert {n} (set : SparseSet n) (v : Fin n) : SparseSet n := sorry

inductive Node where
  | epsilon (next : Nat)

structure NFA where
  nodes : Array Node

def NFA.get (nfa : NFA) (i : Nat) (h : i < nfa.nodes.size) : Node :=
  nfa.nodes[i]

structure Strategy' where
  T : Type

def εClosure (σ : Strategy') (nfa : NFA) (states : SparseSet nfa.nodes.size) (stack : List (Fin nfa.nodes.size)) :
  -- REPRO: using `σ.T` is necessary to reproduce.
  Option σ.T :=
  match stack with
  | [] => .none
  | state :: stack' =>
    -- REPRO: removing this `if` fixes the error.
    if true then
      εClosure σ nfa states stack'
    else
      -- REPRO: this insert is necessary to reproduce.
      let states' := states.insert state
      match nfa.get state state.isLt with
      | .epsilon state' =>
        -- REPRO: this line is also necessary to reproduce.
        have isLt : state' < nfa.nodes.size := sorry
        sorry
-- REPRO: using well-founded recursion is necessary to reproduce.
-- NOTE: the original code uses well-founded recursion to take visited states (`states`) into account.
termination_by /-structural-/ stack

The εClosure definition emits an error like this:

application type mismatch
  let_congr (Eq.refl ((wfParam states).insert (wfParam state))) fun states' =>
    congrArg
      (εClosure.match_1 (fun x => Option (wfParam σ.T))
        ((wfParam nfa).get (wfParam state) (id (Eq.refl (wfParam state))  (wfParam state).isLt)))
      (funext fun state' => letFun_body_congr sorry fun isLt => Eq.refl sorry)
argument
  fun states' =>
    congrArg
      (εClosure.match_1 (fun x => Option (wfParam σ.T))
        ((wfParam nfa).get (wfParam state) (id (Eq.refl (wfParam state))  (wfParam state).isLt)))
      (funext fun state' => letFun_body_congr sorry fun isLt => Eq.refl sorry)
has type
  SparseSet (wfParam nfa).nodes.size 
    (match (wfParam nfa).get (wfParam state)  with
      | Node.epsilon x => sorry) =
      match (wfParam nfa).get (wfParam state)  with
      | Node.epsilon x => sorry : Prop
but is expected to have type
   (x : SparseSet (wfParam nfa.nodes).size), ?b x = ?b' x : Prop

pandaman (Apr 02 2025 at 10:41):

@Joachim Breitner As well-founded recursion is necessary to reproduce and I see wfParam in the errors, this issue might be introduced by auto-attach https://github.com/leanprover/lean4/issues/5471. It would be great if you could take a look!

pandaman (Apr 05 2025 at 10:37):

Filed https://github.com/leanprover/lean4/issues/7826


Last updated: May 02 2025 at 03:31 UTC