fix(codegen): close #556 — async CPS table-miss loud-fail fence#596
Merged
Conversation
gen_function previously fell through to synchronous gen_expr whenever the ADR-013 CPS transform did not fire — even for an `Async` fn whose async-call result is consumed by a continuation. That silently ran the continuation against an unsettled Thenable handle (a wrong value, no diagnostic). Add a precise fence: fail loud (UnsupportedFeature) when an `Async` fn performs an async call consumed by a continuation that cannot be CPS-lowered, while still lowering the sound shapes — the `let r = <async-call>; <cont>` base case (transformed), the bare tail-return-Thenable pass-through (#205 convergence protocol), and an `Async` fn that performs no async call. Mirrors the #555/#566 "fail loud, never silent" fence in the same file. Regression tests (test/test_e2e.ml, "E2E Async Fence (#556)"): - async_sync_fallback.affine → loud UnsupportedFeature (negative) - async_passthrough_thenable.affine → still compiles (no over-rejection) - async_no_boundary.affine → still compiles (no over-rejection) Full suite 454/454 green. Closes #556 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 40 issues detected
View findings[
{
"reason": "Action denoland/setup-deno@v2 needs attention",
"type": "unpinned_action",
"file": "publish-jsr.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in scorecard-enforcer.yml",
"type": "scorecard_publish_with_run_step",
"file": "scorecard-enforcer.yml",
"action": "split_scorecard_publish_job",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Issue in instant-sync.yml",
"type": "secret_action_without_presence_gate",
"file": "instant-sync.yml",
"action": "peter-evans/repository-dispatch",
"rule_module": "workflow_audit",
"severity": "high"
},
{
"reason": "Shell execution -- validate input before passing to shell (1 occurrences, CWE-78)",
"type": "js_exec_sync",
"file": "/home/runner/work/affinescript/affinescript/packages/affinescript-cli/mod.js",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "Shell execution -- validate input before passing to shell (2 occurrences, CWE-78)",
"type": "js_exec_sync",
"file": "/home/runner/work/affinescript/affinescript/packages/affine-vscode/mod.js",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "Shell execution -- validate input before passing to shell (1 occurrences, CWE-78)",
"type": "js_exec_sync",
"file": "/home/runner/work/affinescript/affinescript/affinescript-vite/src/affine-plugin-improved.js",
"action": "flag",
"rule_module": "code_safety",
"severity": "high"
},
{
"reason": "expect() in hot path (32 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/affinescript/affinescript/affinescriptiser/src/codegen/wasm_gen.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "expect() in hot path (29 occurrences, CWE-754)",
"type": "expect_in_hot_path",
"file": "/home/runner/work/affinescript/affinescript/affinescriptiser/src/codegen/affine_gen.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unsafe block -- requires SAFETY comment (2 occurrences, CWE-676)",
"type": "unsafe_block",
"file": "/home/runner/work/affinescript/affinescript/runtime/src/panic.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
},
{
"reason": "unsafe block -- requires SAFETY comment (1 occurrences, CWE-676)",
"type": "unsafe_block",
"file": "/home/runner/work/affinescript/affinescript/runtime/src/alloc.rs",
"action": "flag",
"rule_module": "code_safety",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
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.
Summary
T0 operational-soundness fence (sibling of the just-closed #554).
gen_functionpreviously fell through to synchronousgen_exprwhenever the ADR-013 async CPS transform did not fire — even for anAsyncfn whose async-call result is consumed by a continuation. That silently ran the continuation against an unsettledThenablehandle: a wrong runtime value, no diagnostic.Fix
A precise loud-fail guard in
lib/codegen.ml::gen_function: fail withUnsupportedFeaturewhen anAsyncfn performs an async call consumed by a continuation that cannot be CPS-lowered (thenableThennot importable / unrecognised shape / effect side-table miss), while still lowering the sound shapes:let r = <async-call>; <cont>base case (transformed as before),Thenablepass-through (Wasm-path thenable-resolution: guest consuming a host Thenable result (blocks #103 pilot data path) #205 convergence protocol — the host awaits the handle),Asyncfn that performs no async call at all.This mirrors the #555/#566 "fail loud, never silent" fence already in the same file. The narrow guard was deliberate: the broader
fn_is_async-only guard would have wrongly rejected the validtests/codegen/http_thenable_skeleton.affinepass-through (verified — all 7 existing async fixtures still compile).Tests
New
E2E Async Fence (#556)group:async_sync_fallback.affine→ loudUnsupportedFeature(negative)async_passthrough_thenable.affine→ still compiles (no over-rejection)async_no_boundary.affine→ still compiles (no over-rejection)Full suite 454/454 green.
Closes #556
🤖 Generated with Claude Code