feat(codegen): #225 PR2 — WasmGC CPS transform, Async base case (ADR-013)#233
Merged
Conversation
…013) Transparent async on the WasmGC backend for the recognised base case: an Async fn whose body is `let r = <async-call>; <cont>` with no live-local capture beyond the result binder. The author writes no thenableThen/closure plumbing — the backend synthesises it. lib/codegen.ml: - eff_expr_has_async/fn_is_async: trigger iff Async in fd_eff. Bare effects parse as EffVar (not EffCon — only Throws[E] is EffCon); both spellings checked. - detect_async_base_case: recognises the expression-let and the block-statement (StmtLet :: rest) desugarings; conservative — any unrecognised shape or extra live-local capture falls back to the pre-existing synchronous lowering verbatim (zero behaviour change). - gen_async_base_case: reifies <cont> as a zero-arg continuation via the existing #199 ExprLambda path (binder auto-captured into the [fnId@0,envPtr@4] env — no new closure code); once-resumption guard module-global traps on a second entry (ADR-013 obligation 1). - wired into gen_function, gated on fn_is_async + detector + thenableThen resolvable; else the old path, untouched. Two root-cause fixes in the #199 closure path, which until now had only ever been static-verified (PR1's skeleton was pure pass-through); PR2 is its first real end-to-end wasm exercise and surfaced both: - export the function table as __indirect_function_table (the host ABI dispatches through it; was unexported). Guarded on a non-empty table so closure-free modules are byte-identical. - closure_code used LocalTee where the surrounding code assumes LocalSet, leaving a dangling pointer (two stack values); corrected. stdlib/Http.affine: + pub extern fn thenableThen (the wasm-path continuation-registration primitive the transform targets, mirroring the proven #205 Vscode.thenableThen). Conforms to typed-wasm ADR-005 / spec/async-convergence-abi.adoc as amended (accessor model, (env_ptr)->i32) — see that spec's Conformance — AffineScript section. typed Response reader is PR3 (strict ADR-013 PR2 scope). New wasm e2e tests/codegen/http_cps_base.{affine,mjs}: host re-enters the continuation, reads the settled scalar via a minimal accessor (=200), fires exactly once, second entry traps. Full tools/run_codegen_wasm_tests.sh green; dune test --force 258 green. Refs #225 #160
🔍 Hypatia Security ScanFindings: 44 issues detected
View findings[
{
"reason": "Stray AI.a2ml in root -- use 0-AI-MANIFEST.a2ml only",
"type": "banned",
"file": "AI.a2ml",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "high"
},
{
"reason": "Superseded by 0-AI-MANIFEST.a2ml",
"type": "banned",
"file": "AI.djot",
"action": "delete",
"rule_module": "root_hygiene",
"severity": "high"
},
{
"reason": "Issue in quality.yml",
"type": "missing_workflow",
"file": "quality.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in security-policy.yml",
"type": "missing_workflow",
"file": "security-policy.yml",
"action": "create",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Action hyperpolymath/standards/.github/workflows/governance-reusable.yml@main needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/example/smoke_driver.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/cli.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/mod.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/compile.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
},
{
"reason": "TypeScript file detected -- banned language",
"type": "banned_language_file",
"file": "/home/runner/work/affinescript/affinescript/affinescript-deno-test/lib/runner.ts",
"action": "flag",
"rule_module": "cicd_rules",
"severity": "critical"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
hyperpolymath
added a commit
that referenced
this pull request
May 19, 2026
…lete) Both targets of the portable Http primitive are green: - Deno-ESM #160 — PR #226 (shipped). - typed-wasm #225 — the ADR-013 CPS line PR1..PR3d all merged: #227 (PR1 verified Thenable foundation), #233 (PR2 base case), #236 (PR3a env capture), #237 (PR3b affine-capture obligation), #238 (PR3c Async→Async chaining), #266 (PR3d typed Response reader + http_fetch-parity wasm e2e). The transparent `fetch/get -> Response` source surface is delivered on both targets; ADR-013's delivery plan is complete. Ledger STDLIB-01 + the ADR-013 delivery plan truthed. Two follow-ups remain independently tracked (NOT part of this slice): effect-threaded boundary generalisation #234; estate-wide #199/#205 re-validation #235. Gate: `dune test --force` 278/278 (docs only; zero regression). Closes #160 Closes #225
hyperpolymath
added a commit
that referenced
this pull request
May 19, 2026
…lete) (#268) Both targets of the portable Http primitive are green: - Deno-ESM #160 — PR #226 (shipped). - typed-wasm #225 — the ADR-013 CPS line PR1..PR3d all merged: #227 (PR1 verified Thenable foundation), #233 (PR2 base case), #236 (PR3a env capture), #237 (PR3b affine-capture obligation), #238 (PR3c Async→Async chaining), #266 (PR3d typed Response reader + http_fetch-parity wasm e2e). The transparent `fetch/get -> Response` source surface is delivered on both targets; ADR-013's delivery plan is complete. Ledger STDLIB-01 + the ADR-013 delivery plan truthed. Two follow-ups remain independently tracked (NOT part of this slice): effect-threaded boundary generalisation #234; estate-wide #199/#205 re-validation #235. Gate: `dune test --force` 278/278 (docs only; zero regression). Closes #160 Closes #225
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#225 PR 2 — WasmGC CPS transform, Async base case (ADR-013)
Transparent async on the WasmGC backend for the base case: an
Asyncfn whose body islet r = <async-call>; <cont>with no live-local capture beyond the result binder. The author writes nothenableThen/closure plumbing — the backend synthesises it. Pure/unrecognised fns are untouched (verbatim old lowering — zero behaviour change).What's here
eff_*_has_async/fn_is_async,detect_async_base_case(expr-let + block-stmt forms; conservative fallback),gen_async_base_case(continuation via the existing Deno source-to-source host→guest callback ABI (blocks withProgress/registerCommand/onDidSave) #199ExprLambdapath; once-resumption trap per ADR-013 obligation 1), wired intogen_functionbehind the trigger gate.__indirect_function_table(host ABI dispatches through it); (b)closure_codeLocalTee→LocalSet(dangling-pointer / 2-value stack imbalance). Both guarded/minimal.stdlib/Http.affine:+ pub extern fn thenableThen(wasm-path continuation-registration primitive, mirrors proven Wasm-path thenable-resolution: guest consuming a host Thenable result (blocks #103 pilot data path) #205).Conformance
Conforms to typed-wasm ADR-005 /
spec/async-convergence-abi.adocas amended on 2026-05-19 (accessor model,(env_ptr)->i32; PR #32 merged to typed-wasmmain; typed-wasm#31 closed). See that spec's Conformance — AffineScript section for the section-by-section marry-up. TypedResponsereader + live-local capture + Async→Async chaining are PR3 (strict ADR-013 PR2 scope, owner-confirmed).Verification
tests/codegen/http_cps_base.{affine,mjs}: host re-enters the continuation, reads settled scalar via a minimal accessor (=200), fires exactly once, second entry traps.tools/run_codegen_wasm_tests.shfully green;dune test --force258, zero regression.Refs #225 #160 (NOT Closes — joint-close is PR4).
🤖 Generated with Claude Code