Skip to content

tracking: interpreter non-tail single-shot resume returns the resumed value (shallow continuation) — needs delimited-continuation/CPS rewrite #623

Description

@hyperpolymath

Context

#555 (closed) fenced effect-handler lowering to fail loud on every compiled backend. The interpreter has one residual, silent shape that survived that fix and now has no open tracker. This is it.

The shape (interpreter path only)

// handler: op() => resume(5)
let x = op();
x + 100        // returns 5, NOT 105

The tree-walking interpreter's continuation is shallow: PerformEffect aborts the whole handle body, and resume(v) returns v as the entire handle result. For a non-tail single-shot resume the bind chain has already unwound, so the post-resume code (x + 100) is discarded and unrecoverable at that point.

What is already correct/loud (not this issue):

Class

residual (pinned) — silent-wrong value, interpreter only. Pinned by an executable test so it cannot regress unnoticed and will flip to failing the day it is fixed:

  • fixture test/e2e/fixtures/handle_resume_nontail.affine
  • test test_resume_nontail_known_shallow in test/test_e2e.ml (asserts the wrong-but-known VInt 5).

Fix + why it's blocked

The correct fix is real delimited continuations = a CPS rewrite of Interp.eval. Blocked: OCaml 4.14 has no native effect handlers, and the interpreter must stay js_of_ocaml-compatible — so it's an architecture-level change against the full suite + the jsoo build. Needs owner steer before starting (see docs/reports/HANDOFF-2026-06-17-soundness.adoc §7.1). Do not silently begin a CPS rewrite.

Status

Canonical, test-anchored status: docs/SOUNDNESS.adoc (the #555 interpreter non-tail row). v1 readiness ledger: #563.

Filed from the docs-soundness pass (PR #622).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions