Fix reactive regression: seed all primitives unconditionally into both tables

The conditional seeding left gaps — sync_env_to_vm() would wipe entries
from vm_globals that weren't also in global_env. Unconditional seeding
into both tables ensures CALL_PRIM always finds native primitives.

Also prevents SX definitions (stdlib.sx has-key?) from overwriting native
primitives via the env_bind hook on the server.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-02 11:23:17 +00:00
parent dea1879e27
commit 8ab7e367d8

View File

@@ -857,13 +857,14 @@ let () =
let () = ignore (env_bind global_env "enable-jit!" (NativeFn ("enable-jit!", fun _ -> _jit_enabled := true; Nil)))
(* Seed _vm_globals with all primitives as NativeFn values.
This makes _vm_globals the single source of truth for CALL_PRIM dispatch.
OP_DEFINE and registerNative naturally override entries here. *)
(* Seed BOTH _vm_globals AND global_env with ALL primitives as NativeFn values.
Unconditional — native primitives are authoritative for CALL_PRIM dispatch.
Must be in both because sync_env_to_vm() copies global_env → _vm_globals. *)
let () =
Hashtbl.iter (fun name fn ->
if not (Hashtbl.mem _vm_globals name) then
Hashtbl.replace _vm_globals name (NativeFn (name, fn))
let v = NativeFn (name, fn) in
Hashtbl.replace _vm_globals name v;
Hashtbl.replace global_env.bindings (intern name) v
) Sx_primitives.primitives
(* ================================================================== *)