pub struct DebugFrame {
pub kind: &'static str,
pub location: Option<String>,
pub position: Option<DebugPosition>,
pub temps: usize,
pub locals: Option<Vec<DebugLocal>>,
}Expand description
One call frame, resolved to a knot/stitch path.
Fields§
§kind: &'static strFrame kind: root / function / tunnel / thread / external / eval.
location: Option<String>Nearest named container for this frame, if resolvable.
position: Option<DebugPosition>This frame’s current (container_idx, offset) — the next
instruction that will execute if/when this frame becomes active
again. None for a frame whose container stack is empty (exhausted,
nothing left to run in it) — which includes every
CallFrameType::External frame: those are pushed with an empty
container_stack (there is no bytecode position “inside” a
deferred external call), so a frame with kind == "external"
always carries position: None. The call site that invoked it
lives on this frame’s own return_address, or equivalently on the
position of the caller frame just below it.
temps: usizeNumber of temporary (local) variables in this frame.
locals: Option<Vec<DebugLocal>>D7 (docs/debugger-spec.md §3, #3185): this frame’s named locals —
every declared parameter/~ temp slot in the frame’s own scope,
bound to its live value. Additive alongside temps (D4’s bare
count stays, unchanged, for any existing consumer). None when
this artifact carries no DebugInfo (a release-exported story, or
one compiled before D6) or the frame’s container stack is
empty (nothing left to run in it — e.g. every external frame, or
an exhausted frame — so there is no current position to resolve a
scope from). A frame with a DebugInfo-backed program, a live
position, but genuinely zero declared locals reports Some(vec![]),
not None, so a consumer can tell “no debug info available” (or
“nothing to resolve from”) apart from “this frame really has no
locals.”
Resolved via crate::program::Program::scope_debug_locals against
the frame’s current leaf container, grouping by lexical scope
(ContainerDef::scope_id) rather than by whatever containers
currently happen to be on container_stack — deliberately: a call
frame’s container_stack can legitimately shrink back to a single
entry mid-frame (vm::goto_target’s “target not already on the
stack” branch clears and replaces it wholesale, e.g. entering a
{? … } choice-target body from its enclosing knot), which would
silently drop an enclosing container’s own parameters/~ temps
from view the instant the leaf position moved into a sibling
child container — even though the call frame’s temps are
completely unaffected by that navigation (docs/debugger-spec.md
§3: VM temp slots “are allocated per active call frame, not
lexically nested”). On a slot collision (only possible if a future
codegen change reuses a slot number across sibling scopes — not
confirmed to happen today, same spec section) the entry from
whichever sibling container was iterated last wins; see
scope_debug_locals’s own doc for the full reasoning.