mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-26 06:34:20 +08:00
The cycle analysis gave a header to every type that could reach a cycle, and its construction-only facts gave up on a whole hierarchy as soon as a constructor let `this` escape or a type could cross into checked-dynamic code. Four refinements, all derived from the final IR: - A constructor's stores stay construction-only up to the first top-level statement in which `this` escapes. Statements run in order, so earlier stores complete while the object is private; stores from the escaping statement on, and every store of a constructor whose ancestor let `this` escape, are writes. Compound-assignment receiver temporaries count as `this`. An all-immutable cycle is still impossible: each immutable edge a -> b is stored before a escapes while b has escaped already. - Crossing into checked-dynamic code only makes types mutable when the program contains a runtime store into a dynamic value (int32-slots' audit, now shared as dynamicFieldStores): typed-ref capsules write native fields only through such a commit. Without one, hidden property bags stay empty and add no edges. FFI operands and intrinsics other than publish stay conservative. - A type is traced iff it lies in a cycle-capable component or reaches an intrinsic reference. A type that merely holds a cycle cannot be reached back from it: its references are external counts. - Reachability is per class: a slot of static type C reaches C's subtree, not the whole hierarchy; header presence stays uniform per hierarchy. tsc-ts (e469e33): traced classes 603 -> 469 of 700, records 64 -> 10 of 202, unions 344 -> 93 of 482; scr_cyc_alloc sites 659 -> 471. Mutable hierarchy units 243 -> 4. Collector candidates on the self-check (single-threaded) 6.02M -> 5.55M.