A frame whose slots are all the compiler's own is compared against the slot count its record carries, so a frame that prints keeps its globals and locals
This commit is contained in:
parent
285bb1047f
commit
c41d27ec45
3
TODO.org
3
TODO.org
@ -1657,9 +1657,6 @@ CLOSED: [2026-09-25]
|
||||
** TODO The inspector holds a value
|
||||
Reading needs no module now, so an address and a type are enough to keep a value on the daemon's side between requests, the way CIDER keeps a JVM object. Nothing holds one yet: the Emacs stack is still a stack of expressions.
|
||||
|
||||
** TODO A frame that prints is skipped from the globals section
|
||||
A frame whose body calls =print= comes back in =:skipped= as "running a body that has been redefined since" though nothing was redefined: its global-reference fingerprint differs between the build and the daemon. test/programs/dev-parity.flan stores each global to itself instead of printing it for this reason.
|
||||
|
||||
** DONE The watch table stays pushed
|
||||
CLOSED: [2026-09-25]
|
||||
The watch table stays pushed, and shares the push channel program output moves to.
|
||||
|
||||
10
lib/dev.ml
10
lib/dev.ml
@ -2588,11 +2588,11 @@ let stopped_frame t ~frame ~what : (string * Tast.fn, string) result =
|
||||
up" is a claim about the body this session holds, and a
|
||||
zero-slot frame whose body has since been replaced by one
|
||||
with slots is a frame that claim is false about. *)
|
||||
if nslots <> Array.length fn.Tast.slots then
|
||||
if nslots <> Emit.recorded_slots fn then
|
||||
Error
|
||||
(Printf.sprintf
|
||||
"%s on the stack has %d slots and the %s this session holds has %d — the frame is running a body that has been redefined since"
|
||||
name nslots name (Array.length fn.Tast.slots))
|
||||
name nslots name (Emit.recorded_slots fn))
|
||||
else if sig_ <> Emit.slot_fingerprint fn then
|
||||
(* The count matching is not the same as the body matching.
|
||||
A redefinition that renames a local, or changes its type
|
||||
@ -2628,7 +2628,7 @@ let eval_expr ?frame ?at_stop t ~code ~origin ~pause =
|
||||
(* A frame with no slots has no locals to bind, and the program
|
||||
has no table to answer for it: the expression sees globals. *)
|
||||
let bound =
|
||||
if Array.length fn.Tast.slots = 0 then Ok []
|
||||
if Emit.recorded_slots fn = 0 then Ok []
|
||||
else bound_slots t ~frame:index
|
||||
in
|
||||
(* [at_stop] is the stop the editor drew the frame at. It is not
|
||||
@ -2677,7 +2677,7 @@ let locals t ~frame =
|
||||
match stopped_frame t ~frame ~what:"locals" with
|
||||
| Error m -> error m
|
||||
| Ok (name, fn) ->
|
||||
if Array.length fn.Tast.slots = 0 then
|
||||
if Emit.recorded_slots fn = 0 then
|
||||
ok
|
||||
[ ":frame " ^ Wire.quote name; ":locals ()"; ":refused ()";
|
||||
":note " ^ Wire.quote "this frame has no named locals" ]
|
||||
@ -3457,7 +3457,7 @@ let globals_op t =
|
||||
"not a function this session holds; a lifted handler clause \
|
||||
has no declaration of its own to read references from"
|
||||
| Some fn ->
|
||||
if nslots <> Array.length fn.Tast.slots then
|
||||
if nslots <> Emit.recorded_slots fn then
|
||||
skip
|
||||
"the frame is running a body that has been redefined \
|
||||
since, so what this session holds is a different body's \
|
||||
|
||||
11
lib/emit.ml
11
lib/emit.ml
@ -2022,6 +2022,17 @@ let slot_fingerprint (fn : Tast.fn) =
|
||||
fn.Tast.slots;
|
||||
Hashtbl.hash (Buffer.contents b) land 0x3fffffff
|
||||
|
||||
(* How many slots a frame's record says it has: all of them when any is named,
|
||||
and none otherwise, since only a function with a named slot gets a slot
|
||||
table (see the shadow stack's push in [emit_fn]). Both backends write it and
|
||||
[Dev] compares a frame against it, so a body whose slots are all the
|
||||
compiler's own — a [print]'s temporaries — reads as the same body at both
|
||||
ends. *)
|
||||
let recorded_slots (fn : Tast.fn) =
|
||||
if Array.exists (fun n -> n <> None) fn.Tast.snames then
|
||||
Array.length fn.Tast.slots
|
||||
else 0
|
||||
|
||||
let fninfo m (fn : Tast.fn) ~nslots =
|
||||
let nid, nlen = fi_bytes m fn.Tast.name in
|
||||
let lid, llen = fi_bytes m (Loc.to_string fn.Tast.floc) in
|
||||
|
||||
@ -54,18 +54,17 @@
|
||||
(defonce pair (Pair i32))
|
||||
|
||||
;; The innermost frame names every global above, so the break loop's section
|
||||
;; holds all of them; then it stops. Each is stored back to itself rather than
|
||||
;; printed: a frame that prints is refused attribution today (TODO.org, "A
|
||||
;; frame that prints is skipped from the globals section"), and this is about
|
||||
;; the values.
|
||||
;; holds all of them; then it stops. It prints them, and a frame whose only
|
||||
;; slots are the printer's temporaries is still attributed its globals.
|
||||
(defn inner [] i64
|
||||
(set small small) (set mid mid) (set large large) (set huge huge)
|
||||
(set neg neg) (set ratio ratio) (set far far) (set odd odd) (set yes yes)
|
||||
(set byte byte) (set text text) (set colour colour) (set stray stray)
|
||||
(set some some) (set none none) (set wide wide) (set deep deep)
|
||||
(set dot dot) (set empty empty) (set row row) (set words words)
|
||||
(set nums nums) (set live live) (set dead dead) (set nowhere nowhere)
|
||||
(set un un) (set anything anything) (set pair pair)
|
||||
(print small) (print mid) (print large) (print huge)
|
||||
(print neg) (print ratio) (print far) (print odd) (print yes)
|
||||
(print byte) (print text) (print colour) (print stray)
|
||||
(print some) (print none) (print wide) (print deep)
|
||||
(print dot) (print empty) (print row) (print words)
|
||||
(print nums) (print live) (print dead) (print nowhere)
|
||||
(print un) (print anything) (print pair)
|
||||
(println "")
|
||||
(error (Boom {.why 3}))
|
||||
0)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user