Files
scriptc/tests/corpus/2482-recursive-union-tree.ts
Chris Tate b49052a389 Recursive record types compile statically as named recursive shapes
- mapType back-references mint placeholder shapes/unions finalized at frame exit; identity is per checker type, and context-sensitive (generic/mixin) knots stay fenced
- every type walk survives cyclic shape graphs: coinductive JSON/dyn-safety predicates, guarded formatIrType/jsvalLiftable, cycle headers via the existing collector fixpoint on both backends
- JSON.stringify throws V8's byte-exact circular TypeError (hop lines, ellipsis rule); cyclic values crossing into checked-dynamic slots trap instead of hanging
- console.log/util.inspect render <ref *N>/[Circular *N] exactly (SEMANTICS 129 resolved; depth:null lowers) and deepStrictEqual terminates through Node's pair memo
- corpus 2480-2488 green on C, LLVM, and the sanitized RC-audit lane, which proves child->parent cycles collect
2026-07-23 13:24:13 -05:00

31 lines
963 B
TypeScript

// Recursion through a UNION: the knot enters at a union type (a JSON-like
// value alias) whose record arm carries the union in an array. The union
// interns as a named recursive union; narrowing works arm by arm.
type Tree = string | { children: Tree[] };
const t: Tree = { children: ["a", { children: ["b", "c"] }, "d"] };
function flatten(n: Tree): string {
if (typeof n === "string") return n;
let out = "";
for (const c of n.children) out += flatten(c);
return out;
}
console.log(flatten(t));
console.log(flatten("solo"));
// A linked list through an optional-flavored union field.
interface ListNode { value: number; next: ListNode | null }
const list: ListNode = { value: 1, next: { value: 2, next: { value: 3, next: null } } };
function sum(n: ListNode | null): number {
let total = 0;
let cur = n;
while (cur !== null) {
total += cur.value;
cur = cur.next;
}
return total;
}
console.log(sum(list));
console.log(sum(null));