Behaviour
When a function's effect row contains Async but its body shape isn't recognised by the CPS transform (e.g. an async call not in let-binding head position, like is_ok(get(u))), codegen silently falls back to the pre-existing synchronous lowering (codegen.ml:2000-2010; effect_sites.ml:186-189, the self-described "sound table-miss path").
The result is not a crash — it is a silent wrong value: the Thenable handle i32 flows onward as if it were the resolved value.
Why "zero regression" isn't enough
ADR-016 accepted the fallback as zero-regression vs the pre-CPS world, but post-CPS the contract changed: a declared / Async row now promises async lowering. A shape miss should be a loud UnsupportedFeature (mirroring codegen_gc.ml's fencing discipline) or the shape table should be extended — silent wrong-value is the worst of the options.
Requested
Related: the general handler-dispatch tracking issue (same silent-vs-loud principle, filed same day).
Filed from the 2026-06-11 whole-picture survey.
Behaviour
When a function's effect row contains
Asyncbut its body shape isn't recognised by the CPS transform (e.g. an async call not in let-binding head position, likeis_ok(get(u))), codegen silently falls back to the pre-existing synchronous lowering (codegen.ml:2000-2010;effect_sites.ml:186-189, the self-described "sound table-miss path").The result is not a crash — it is a silent wrong value: the Thenable handle i32 flows onward as if it were the resolved value.
Why "zero regression" isn't enough
ADR-016 accepted the fallback as zero-regression vs the pre-CPS world, but post-CPS the contract changed: a declared
/ Asyncrow now promises async lowering. A shape miss should be a loudUnsupportedFeature(mirroringcodegen_gc.ml's fencing discipline) or the shape table should be extended — silent wrong-value is the worst of the options.Requested
is_ok(get(u))).Related: the general handler-dispatch tracking issue (same silent-vs-loud principle, filed same day).
Filed from the 2026-06-11 whole-picture survey.