mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-07 08:33:50 +08:00
A union of exactly one emitted class or record arm and one unit arm (`C | undefined`, `C | null`) now lowers to the arm pointer itself: NULL is the unit arm and no `%ScrUnion` box is allocated. The decision lives in one registry (nullable-unions.ts) computed from the module, so in-memory and serialized-IR emission agree. Unions the runtime inspects as boxes (Map keys, Set elements) keep the tagged representation. Every structural read goes through representation-aware primitives (union-repr.ts, unionTag/unionPeek/unionNewOwned/unitInstanceRef taking the union id), and RC/trace dispatch resolves a nullable union to its arm's NULL-tolerant entry points, so containers, captures, fields, params, returns and promise payloads hold the plain pointer. Optional record fields use a module-scope immortal sentinel for the ABSENT state. Generic helper generators (JSON and join walkers, dyn conversions and checked casts, live stream refs, race/generator adapters, map get widening) handle both representations; fixed library unions assert they stay boxed. The stack-box analyses run over the boxed union table only. On main, the checked-extraction receivers of #781 (checked-narrows.ts) read the tag and payload through the same representation-aware primitives, and the stack-box and optional-array-read paths of #767 run over the boxed union table.