Files
scriptc/tests/corpus/3077-optional-union-array-reads.ts
Chris Tate 7a30a159eb feat(compiler): enable native IR construction for self-hosting (#491)
- Compile native collection views and recursive discriminated IR structures.
- Preserve optional-chain behavior and union payload ownership across C and LLVM.
- Exercise real IR builders and analyses in native executables with differential coverage.
2026-09-27 11:41:52 -05:00

74 lines
2.5 KiB
TypeScript

export {};
// An optional receiver contains several array representations. Each array
// element has its own tag layout, distinct from the joined result union.
type Payload = { name: string; values: number[] };
type Source = (Payload | null)[] | (string | null)[] | undefined;
const shared: Payload = { name: "shared", values: [1] };
const records: (Payload | null)[] = [shared, null];
const strings: (string | null)[] = ["text", null];
let evaluations = 0;
let indexes = 0;
function source(mode: number): Source {
evaluations++;
if (mode === 0) return records;
if (mode === 1) return strings;
return undefined;
}
function index(value: number): number {
indexes++;
return value;
}
function show(mode: number, offset: number): void {
const value = source(mode)?.[index(offset)];
if (value === undefined) console.log("undefined");
else if (value === null) console.log("null");
else if (typeof value === "string") console.log("string", value);
else {
value.values.push(2);
console.log("payload", value.name, value.values.join(","));
}
}
for (let mode = 0; mode < 3; mode++) {
show(mode, 0);
show(mode, 1);
}
console.log("evaluations", evaluations, indexes);
console.log("shared", shared.values.join(","));
// Index evaluation may replace the receiver's original binding. The
// optional-chain guard and widened result each retain the right owner.
let active: Source = records;
function current(): Source { return active; }
function replace(): number {
active = strings;
return 0;
}
const before = current()?.[replace()];
if (before && typeof before !== "string") console.log("before", before.name);
console.log("after", current()?.[0]);
// An owned temporary array disappears after the read. The widened box
// must retain its reference payload before releasing the original box.
function fresh(mode: number): (Payload | null)[] | (string | null)[] {
if (mode === 0) return [{ name: "fresh", values: [7, 8] }];
return ["fresh text"];
}
let total = 0;
for (let i = 0; i < 200; i++) {
const value = fresh(i % 2)[0];
if (typeof value === "string") total += value.length;
else if (value !== null) total += value.values.length;
}
console.log("temporary total", total);
// A missing receiver and a present null element take different unit
// paths; a lazy default runs once for each and never for present strings.
let defaults = 0;
function fallback(): string { defaults++; return "fallback"; }
console.log(source(1)?.[0] ?? fallback());
console.log(source(1)?.[1] ?? fallback());
console.log(source(2)?.[0] ?? fallback());
console.log("defaults", defaults);