Skip to content

refactor(interpreter): invert frame composition ownership - #723

Open
zhenrongliew wants to merge 2 commits into
dl/generalize-bodyfrom
dl/interp-frame-composition
Open

refactor(interpreter): invert frame composition ownership#723
zhenrongliew wants to merge 2 commits into
dl/generalize-bodyfrom
dl/interp-frame-composition

Conversation

@zhenrongliew

@zhenrongliew zhenrongliew commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #684. Make each interpreter engine's private stack enum own conversion from reusable member frames.

Problem:

Concrete member frames depended on the total enum that stores them. BlockFrame required F: FrameBuild<V, E> and re-wrapped itself with F::from_block(self), so the dependency ran:

BlockFrame -> FrameBuild -> total enum -> BlockFrame
The cause was in the frame protocol itself. Frame<I, F>'s three methods all returned FrameEffect<F, C> — over F, never over Self. A reusable frame was therefore obliged to construct the enclosing enum's variant for itself, which it could only do through a construction trait the enum had to implement. That forced a chain of scaffolding: a FrameBuild derive per engine family, a Build* construction trait per dialect frame.

Fix:

Split the parent from the child in FrameEffect:

pub enum FrameEffect<P, C, F = P> {
    Continue(P),                    // P = this frame's own next state
    Push { parent: P, child: F },   // F = configured representation of a child
    Done,
    Complete(C),
}

pub trait Frame<I: FrameEngine, F = Self> {
    fn step_into(self, interp: &mut I) -> Result<FrameEffect<Self, Self::Completion, F>, I::Error>;
    // ...
}

A member continuation now returns itself for Continue and as the suspended parent of Push. A private closed stack-item enum is the composition root: it owns the From<Member> conversions, dispatches exhaustively, and lifts member state into its own variant with the new FrameEffect::map_next.

Make each composition root own conversion of reusable member frames into its private stack-item enum.

Remove FrameBuild, StandardFrame, UnGraphEntry, the FrameBuild derive, and the concrete SCF injection traits. Replace member-side factory calls with narrow From<Member> conversions while keeping callable-body walker selection in CallBodyTraversal and DefaultCallBodyTraversal.

This reverses the dependency from member to factory to total enum to member, without changing concrete execution semantics.
…engines

Extend the concrete ownership rule to sparse-forward, sparse-backward, dense-backward, SCF, and the shared fixpoint adapters.

Each private stack-item enum now owns its From<Member> conversions and wraps member effects at the dispatch boundary. Reusable frames no longer name or construct the total enum that contains them.

The fixpoint and liveness changes are mechanical adaptations to the corrected Frame and FrameEffect contracts; their analysis equations are unchanged.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant