Files
scriptc/tests/corpus/2483-recursive-record-cycles.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

32 lines
1.2 KiB
TypeScript

// Runtime REFERENCE CYCLES through recursive record types: children
// pointing back at ancestors. Reference counting alone cannot free these;
// the cycle collector must — the sanitized lane's RC audit is the proof
// (this program leaks nothing).
interface TreeNode { label: string; children: TreeNode[] }
function makeCycle(tag: string): TreeNode {
const parent: TreeNode = { label: "p" + tag, children: [] };
const child: TreeNode = { label: "c" + tag, children: [] };
parent.children.push(child);
child.children.push(parent); // the back edge closes the cycle
return parent;
}
// Churn: many dead cycles, none reachable after the loop.
let survivors = 0;
for (let i = 0; i < 200; i++) {
const p = makeCycle(String(i));
if (p.children.length === 1) survivors += 1;
}
console.log(survivors);
// A live cycle read through both directions, then dropped before exit.
const ring = makeCycle("live");
console.log(ring.label, ring.children[0].label);
console.log(ring.children[0].children[0] === ring);
// Self-loop: a node whose child is itself.
const solo: TreeNode = { label: "solo", children: [] };
solo.children.push(solo);
console.log(solo.children[0] === solo, solo.children[0].label);