;; Letrec + perform/resume regression tests — Step 2 ;; Verifies sibling bindings survive across an IO suspension when the ;; suspended call goes through call_closure_reuse (JIT path). ;; The browser/WASM kernel reuses the host VM via call_closure_reuse; ;; if restore_reuse drops the caller's saved sp, sibling letrec bindings ;; come back as nil after resume. (defsuite "letrec-resume" (deftest "single binding survives perform/resume" (let ((state (cek-step-loop (make-cek-state (quote (letrec ((f (fn () (perform {:op "io"})))) (f))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 7))) (assert (cek-terminal? final)) (assert= (cek-value final) 7)))) (deftest "sibling bindings survive perform/resume" (let ((state (cek-step-loop (make-cek-state (quote (letrec ((g (fn () 100)) (f (fn () (perform {:op "io"})))) (+ (f) (g)))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 5))) (assert (cek-terminal? final)) (assert= (cek-value final) 105)))) (deftest "mutual recursion sibling preserved across resume" (let ((state (cek-step-loop (make-cek-state (quote (letrec ((even? (fn (n) (if (= n 0) true (odd? (- n 1))))) (odd? (fn (n) (if (= n 0) false (even? (- n 1))))) (fetch (fn () (perform {:op "io"})))) (let ((x (fetch))) (even? x)))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 4))) (assert (cek-terminal? final)) (assert= (cek-value final) true)))) (deftest "nested letrec — outer sibling survives inner perform" (let ((state (cek-step-loop (make-cek-state (quote (letrec ((outer-val (fn () 99)) (inner-call (fn () (letrec ((suspend-fn (fn () (perform {:op "io"})))) (suspend-fn))))) (+ (inner-call) (outer-val)))) (make-env) (list))))) (assert (cek-suspended? state)) (let ((final (cek-resume state 1))) (assert (cek-terminal? final)) (assert= (cek-value final) 100)))))