Zulip Chat Archive

Stream: new members

Topic: Recursive ForIn/ForM: Stack overflow b/c ForM.forIn inlined


smheidrich (Oct 23 2025 at 06:38):

Would you guys agree that the snippet below should not cause a stack overflow or would it be considered user error if I posted it as a GitHub issue? For a slightly less minimal example, cf. also my Stack Overflow question about it.

inductive Countdown where
  | zero
  | one

-- ForM.forM implementation that does absolutely nothing & should terminate
-- after a single recursive call of itself (indirectly via `for` loop):
partial def Countdown.forM
  [Monad m] (c : Countdown) (_action : Unit  m PUnit) : m PUnit
:= do match c with
  | zero => pure ()
  | one =>
      -- Functions that allow synthesis of local ForM & ForIn instances, as
      -- suggested in "Instances for nested types" example from [1]:
      let {m'} := (Countdown.forM : ForM m' Countdown Unit)
      let {m''} := (ForM.forIn : ForIn m'' Countdown Unit)
      for () in zero do
        return

def main : IO Unit :=
  Countdown.one.forM pure

-- Uncomment to cause stack overflow in Lean 4 Web version:
-- #eval main

-- [1]: https://lean-lang.org/doc/reference/latest//Type-Classes/Instance-Declarations/#recursive-instances

It works fine if you explicitly use a non-inline version of ForM.forIn.

Markus Himmel (Oct 23 2025 at 08:35):

Thank you for the report. This is a miscompilation introduced by the new compiler which was enabled in Lean 4.22.0. I have created an issue with some further minimization at lean4#10925.

smheidrich (Oct 23 2025 at 10:27):

Thank you for looking into it! :slight_smile: So the non-inline thing fixing it was pure luck :sweat_smile:


Last updated: Dec 20 2025 at 21:32 UTC