Skip to content

feat(codegen): #225 PR2 — WasmGC CPS transform, Async base case (ADR-013)#233

Merged
hyperpolymath merged 1 commit into
mainfrom
stage-c/225-pr2-cps-base
May 19, 2026
Merged

feat(codegen): #225 PR2 — WasmGC CPS transform, Async base case (ADR-013)#233
hyperpolymath merged 1 commit into
mainfrom
stage-c/225-pr2-cps-base

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

#225 PR 2 — WasmGC CPS transform, Async base case (ADR-013)

Transparent async on the WasmGC backend for the 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. Pure/unrecognised fns are untouched (verbatim old lowering — zero behaviour change).

What's here

Conformance

Conforms to typed-wasm ADR-005 / spec/async-convergence-abi.adoc as amended on 2026-05-19 (accessor model, (env_ptr)->i32; PR #32 merged to typed-wasm main; typed-wasm#31 closed). See that spec's Conformance — AffineScript section for the section-by-section marry-up. Typed Response reader + live-local capture + Async→Async chaining are PR3 (strict ADR-013 PR2 scope, owner-confirmed).

Verification

  • New e2e 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.sh fully green; dune test --force 258, zero regression.

Refs #225 #160 (NOT Closes — joint-close is PR4).

🤖 Generated with Claude Code

…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
@hyperpolymath hyperpolymath merged commit 62e16df into main May 19, 2026
11 of 12 checks passed
@hyperpolymath hyperpolymath deleted the stage-c/225-pr2-cps-base branch May 19, 2026 07:33
@github-actions
Copy link
Copy Markdown

🔍 Hypatia Security Scan

Findings: 44 issues detected

Severity Count
🔴 Critical 12
🟠 High 21
🟡 Medium 11

⚠️ Action Required: Critical security issues found!

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
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