Restore cek_run IO hooks and cek_step_loop error handling lost by bootstrap

bootstrap.py regenerated cek_run as a simple "raise if suspended" without
the _cek_io_resolver and _cek_io_suspend_hook checks. Also lost the
CekPerformRequest catch in cek_step_loop and step_limit checks.

This was the direct cause of "IO suspension in non-IO context" when island
click handlers called perform (via hs-wait). The CEK had no way to propagate
the suspension to the VM/JS boundary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-17 14:01:14 +00:00
parent aef92cc1f3
commit f276c4a56a
5 changed files with 78 additions and 31 deletions

View File

@@ -576,11 +576,34 @@ and expand_macro mac raw_args env =
(* cek-step-loop *)
and cek_step_loop state =
(if sx_truthy ((let _or = (cek_terminal_p (state)) in if sx_truthy _or then _or else (cek_suspended_p (state)))) then state else (cek_step_loop ((cek_step (state)))))
if !step_limit > 0 then begin
step_count := !step_count + 1;
if !step_count > !step_limit then
raise (Sx_types.Eval_error "TIMEOUT: step limit exceeded")
end;
(if sx_truthy ((let _or = (cek_terminal_p (state)) in if sx_truthy _or then _or else (cek_suspended_p (state)))) then state else begin
let next = (try cek_step (state)
with Sx_types.CekPerformRequest request ->
make_cek_suspended request (cek_env state) (cek_kont state))
in cek_step_loop next
end)
(* cek-run *)
(* cek-run — with IO suspension hooks for the OCaml host *)
and cek_run state =
(let final = (cek_step_loop (state)) in (if sx_truthy ((cek_suspended_p (final))) then (raise (Eval_error (value_to_str (String "IO suspension in non-IO context")))) else (cek_value (final))))
let rec run s =
let final = cek_step_loop s in
if sx_truthy (cek_suspended_p final) then
match !Sx_types._cek_io_resolver with
| Some resolver ->
let request = cek_io_request final in
let result = resolver request final in
run (cek_resume final result)
| None ->
(match !Sx_types._cek_io_suspend_hook with
| Some hook -> hook final
| None -> raise (Eval_error (value_to_str (String "IO suspension in non-IO context"))))
else cek_value final
in run state
(* cek-resume *)
and cek_resume suspended_state result' =