Files
scriptc/tests
Malte UblandClaude Opus 5.5 ea23feeb21 Merge a union's promise arms into one promise of their payload union
`void | Promise<A> | Promise<void> | Decision` (the agent-loop `finishTurn`
hook, codemode's remote client) had no representation: a union arm's index is
its runtime tag and a promise arm's tag IS the `instanceof Promise` test, so a
second promise arm had no tag. The union was refused (SC2009) and every use
site inherited the blocker.

JavaScript cannot tell the arms apart: `instanceof Promise` answers true for
both and `await` settles to either payload. The union therefore maps to one
promise arm `Promise<A | undefined>`: payloads join like union arms (`void`
becomes the undefined unit, an already-union payload flattens, identical
payloads dedupe, a checked-dynamic payload absorbs the arms the dynamic
representation holds faithfully). A payload with no union arm home (a RegExp
payload, a promise-of-a-promise) keeps the whole union fenced, and the
refusal now says why.

A `Promise<A>` value flowing into the merged arm converts with the existing
checked promise-payload widening (promisePayloadWidens / promiseWiden): the
promise keeps its identity and its settlement turn, and the settled payload
is checked against the payload slot.

Cost: the merge only runs for a union that already has two promise arms,
which is refused today. Every other union interns the same arms in the same
order, so a fully typed program without such a union compiles to identical
IR.

Corpus 8414-promise-union-arms pins identity through the union slot,
`instanceof Promise` narrowing, `await`, `.then`, the void arm, the rejection
path and a non-promise data arm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 13:17:05 -07:00
..
…