flan/test/programs/dev-loop.flan
Joseph Ferano 2fadf82e23 A redefinition carries its own handler clauses
The reload path had never seen a restart-case or a handler-bind: the
acceptance table's dev build proves whole-program codegen with cells, but not
Emit.redefinition, where the callees are declares or cell loads and the restart
frame is an alloca in a module the process was not built with. Driving it found
a hole step 1 left - a lifted clause was numbered by its position in the whole
program's lifted list, so the name was neither stable against an unrelated
handler-bind being added nor attributable to the function it came out of, and
redefining a function that established a handler died in llc with an undefined
value.

A clause is now named after its parent - handler/step/0/Missing - and carries
Tast.fn.fparent, which is what lets a redefinition module emit the clauses
belonging to the bodies it is replacing and nothing else. They are hidden for
the same reason a redefined body is: taking the address of an interposable
symbol would resolve to the host's copy, so the module would install the very
handler it was replacing. A clause is reached by address from its parent and
from nowhere else, so it is kept out of the cell and registry machinery
entirely rather than given a slot nobody uses.

test_dev.ml now sends a third evaluation: step redefined to a restart-case
whose frame is an alloca in the new module, whose guarded call goes through the
host's cell, and whose transfer starts in a handler and crosses probe, which
the host was compiled with. The transcript's fourth line is the clause's value.
2026-09-11 08:17:07 +07:00

32 lines
1019 B
Plaintext

;;;; What [flan dev] launches: a program with a loop, a function to redefine,
;;;; and a way to stop. The daemon overrides the socket path through the
;;;; environment, so the one written here is only what it falls back to.
(import agent "vendor:agent")
(defvar ticks i64)
;;; A condition and something that signals it, so that a body typed in later
;;; can establish a handler and transfer past this frame — spec-conditions.md
;;; §6. It is here rather than in the evaluated form on purpose: the guard that
;;; forwards the transfer has to be one the *host* was compiled with.
(defstruct Missing [id i32])
(defn probe [] i64
(signal (Missing {:id 1}))
0)
(defn step [] i64
(set ticks (+ ticks 1))
ticks)
(defn main [] i32
(agent/start "/tmp/flan-dev-fallback.sock")
(print-i64 (step)) (newline)
(while (= (agent/wait 100) 0) 0)
(print-i64 (step)) (newline)
(while (= (agent/wait 100) 0) 0)
(print-i64 (step)) (newline)
(while (= (agent/wait 100) 0) 0)
(print-i64 (step)) (newline)
0)