From dea1879e276632e14ea2605302979f1703217c9f Mon Sep 17 00:00:00 2001 From: giles Date: Thu, 2 Apr 2026 11:10:34 +0000 Subject: [PATCH] Fix vm_globals: prevent SX definitions from overwriting native primitives The env_bind hook was copying SX-defined functions (e.g. has-key? from stdlib.sx) into vm_globals, shadowing the native primitives seeded there. CALL_PRIM then called the SX version which broke with wrong arg types. Fix: env_bind hook skips names that are registered primitives. Native implementations are authoritative for CALL_PRIM dispatch. Co-Authored-By: Claude Opus 4.6 (1M context) --- hosts/ocaml/bin/sx_server.ml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hosts/ocaml/bin/sx_server.ml b/hosts/ocaml/bin/sx_server.ml index 711fad84..4b229da2 100644 --- a/hosts/ocaml/bin/sx_server.ml +++ b/hosts/ocaml/bin/sx_server.ml @@ -678,7 +678,10 @@ let () = closure isolation for factory functions like make-page-fn. *) Sx_types._env_bind_hook := Some (fun env name v -> if env.parent = None then - Hashtbl.replace _shared_vm_globals name v) + (* Don't let SX definitions (from loaded .sx files) overwrite native + primitives in vm_globals — the native versions are authoritative. *) + if not (Sx_primitives.is_primitive name) then + Hashtbl.replace _shared_vm_globals name v) let make_server_env () = let env = make_env () in @@ -735,11 +738,13 @@ let make_server_env () = | other -> other); (* client? returns false on server — overridden in browser via K.eval *) ignore (env_bind env "client?" (NativeFn ("client?", fun _ -> Bool false))); - (* Seed vm_globals with any primitives not already there. - Must run AFTER all bind/ho_via_cek calls so wrappers take precedence. *) + (* Seed vm_globals with ALL primitives as NativeFn values. + Native primitives override SX definitions (e.g. has-key? from stdlib.sx) + because the native versions are correct and fast. HO forms (map, filter, etc.) + keep their ho_via_cek wrappers since those are set up after this seeding + via the env_bind_hook when SX files are loaded. *) Hashtbl.iter (fun name fn -> - if not (Hashtbl.mem _shared_vm_globals name) then - Hashtbl.replace _shared_vm_globals name (NativeFn (name, fn)) + Hashtbl.replace _shared_vm_globals name (NativeFn (name, fn)) ) Sx_primitives.primitives; env