Repository navigation
-mm=own, phase 3: containers and unions - #403
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A widening or narrowing cast between class, union and optional types, CreateUnionInstance, GetValueFromUnionOp, OptionalValue and Value hand back the block their operand holds. The pass strips them to the root wherever it names a value and looks through them wherever it lists a value's uses, so `let u: C | null = new C(i)` is one owner, not a second reference. An empty optional (`u = undefined`) holds no block, like `null` widened. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the container drops it
`const c = h.c` and `arr[i]` read a value the container owns, and until now nothing
bounded them: an overwrite of the field or element, a pop, an assignment or move of
the owner, or a call given it could free the value while it was still read (rc has
the same hole). Such a read is now a borrow. It may not be kept (a store or a
retain is an error), and no use of it - nor of anything it produces, passed on
through a merge or a local that owns nothing - may be reachable from:
- an overwrite of a place on the way to its root (matched by position and type);
- a pop, shift, splice or length assignment of an array of its element type;
- an end of the root: its releases, assignments and moves;
- a call given something derived from the root, or any call where the root is a
parameter, `this` or a global, whose owner the callee may reach.
A path back to a use through the read is a new borrow.
Testing an optional (`if (d)`, `d?.x`) and `typeof` are reads, not takers.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`let c = h.c` and `let e = arr[j]` take no reference and give none back: the let's RetainSlot and ReleaseSlots go, and its reads join the read's uses, bounded by what may destroy the container's value. An assignment of such a let is an error, as for phase 2's borrowers. tryBorrow's walk over a borrower's slot is collectBorrowerUses, shared by both. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Spec section 14: views, reads out of containers as borrows, let receivers of them; measured flat like rc; teeth; corpus 252 -> 272 of 564; any boxing moved to phase 4 with the rc box leak it found; known limits for phase 4. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… merges The final review found three holes in following a borrow past a merge: - a borrow stored into a local that owns nothing and read on a later iteration, after the overwrite, was taken for the next iteration's borrow and compiled into a read of freed memory; - a merge of two reads was rejected after any earlier call, through the other branch; - a read through a merge of two owning locals saw one root it did not own, with no ends, and compiled an assignment of either local into a read of freed memory. Each borrowed use now carries where its value is made again: the read or the borrowing let for its own uses, the merge's block past a merge, and a local's declaration and assignments past a local that owns nothing. The branch or store that hands the value on is a use bounded by the read. reachableAfter takes a set of kills. A container reached through a merge has each merged value as a root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 3 of
-mm=own(spec §7): containers and unions. OnlyOwnershipInferencePass.cppchanges; gc, rc and none are untouched. Plan:docs/superpowers/plans/2026-09-29-own-phase-3.md. Results: spec §14.What changes
CreateUnionInstance,GetValueFromUnionOp,OptionalValueandValuehand back the block their operand holds.let u: C | null = new C(i),let u: C | string = candlet u: C | undefinednow compile as one owner. Before, they were rejected as "takes a second reference".const c = h.c; h.c = new C(); c.xused to compile into a read of freed memory under own (rc has the same bug). A read may not be kept ('c' borrows 'h.c' and cannot be stored, returned or captured). No use of it, or of what it produces, may be reachable from:pop,shift,spliceorlength =;letdeclared from a read borrows it (let c = h.c,let e = arr[j]): no reference taken, none given back.??merges and through locals that own nothing, each checked against where that value is made again.Verification
test-jit-rc-owned-asyncandtest-jit-none-owned-async, fail on main too (the~AsyncTokendebug-heap assert).ownership-verifier-4was excluded; it also fails on main (the linkname assert).nonegoes up to 582 MB.letborrower's releases kept, theletpositives fail the same way;999(freed memory) under rc and own.${this.color} … ${this.area()}, per the ruling on calls below.Rulings
anyboxing moves to phase 4. Unboxing is a generated___unbox<T>that returns +1, so treating it as a borrow needs phase 4's borrowed-from-argument result. Found along the way: rc never frees the box ofconst a: any = new C(i)(66 MB against gc's 6 MB).this's or a global's field. The callee may reach the owner through a global. This is sound but restrictive until phase 4's callee facts.Final review
A fresh reviewer found two unsound cases and one false error, all fixed with tests that failed first:
cond ? a : bwhereais then assigned;cond ? h.c : h.drejected after any earlier call.Deferred minors:
'this value'naming for temporaries and merges; an extra error for nested reads;u.c ??= new C()is rejected. Also found, not own:const a2 = arr; arr.push(...)in a loop crashes the compiler under every model.🤖 Generated with Claude Code