Fix hydration: effect was a no-op primitive, bytecode compiler emitted CALL_PRIM

Root cause: sx_primitives.ml registered "effect" as a native no-op (for SSR).
The bytecode compiler's (primitive? "effect") returned true, so it emitted
OP_CALL_PRIM instead of OP_GLOBAL_GET + OP_CALL. The VM's CALL_PRIM handler
found the native Nil-returning stub and never called the real effect function
from core-signals.sx.

Fix: Remove effect and register-in-scope from the primitives table. The server
overrides them via env_bind in sx_server.ml (after compilation), which doesn't
affect primitive? checks.

Also: VM CALL_PRIM now falls back to cek_call for non-NativeFn values (safety
net for any other functions that get misclassified).

15/15 source mode, 15/15 bytecode mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-31 16:56:31 +00:00
parent 4cb4551753
commit a7efcaf679
28 changed files with 232 additions and 199 deletions

View File

@@ -256,25 +256,6 @@
"sx:afterSwap"
(dict "target" target-el "swap" swap-style)))))))
(define
flush-cssx!
:effects (mutation io)
(fn
()
(let
((rules (collected "cssx")))
(clear-collected! "cssx")
(when
(not (empty? rules))
(let
((style (dom-query "#sx-css")))
(when
style
(dom-set-prop
style
"textContent"
(str (dom-get-prop style "textContent") (join "" rules)))))))))
(define
handle-sx-response
:effects (mutation io)
@@ -527,8 +508,7 @@
(sx-hydrate root)
(sx-hydrate-islands root)
(run-post-render-hooks)
(process-elements root)
(flush-cssx!)))
(process-elements root)))
(define
process-settle-hooks