Repository navigation
-mm=own phase 6: the corpus report; globals' initializers, data nothing owns, record literals - #445
Merged
Merged
Conversation
…global
A global's initializer runs in the global's own region, which no
function's inference sees, so rc's retain for its `ts.GlobalResult` was
left behind and the lowering failed the compile ("ownership inference
left a retain behind", with no location). A global is a root: what its
initializer makes moves into it. The signature pass erases a retain in a
global's region when the value is the only reference to its block
(retained once, released nowhere) and is fresh, constant data, or a
record of constants, and every use of it ends in the `ts.GlobalResult`:
directly, through views, as an element of an array literal, or copied
into an object literal's box. Any other retain there is reported by the
global's name.
isConstantData (OwnershipFacts.h): what holds no block, a `ts.Constant`
or a field of one, and a tuple of such.
The phase 6 plan: docs/superpowers/plans/2026-10-02-own-phase-6.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
rc retains a value wherever its type could hold a block. A number or null in a union, a function named by a `ts.SymbolRef`, a string literal, and a tuple of such hold none, so the retain takes nothing: it is erased instead of reported as a second reference. A `ts.RetainSlot` is decided on the slot's initializer, so only while nothing else is ever stored into the slot and no closure captures it. Such data has no use after a move either: under --opt, CSE merges equal literals (the left-out optional field of two tuple literals), and one value then goes into several places (checkValueMoves). isConstantData excludes two things a type-only reading takes for data: a `ts.New`, whose `value_ref` type owns nothing but which is the object its view shows (`00object` stores one into two records), and a value a `ts.NewInterface` view boxes into a block of its own each time (own_err_interface_two_views). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The slot guard for data nothing owns took any use of the slot but a load for a write, and a tuple local's `a[0]` reaches it through a `ts.PropertyRef`. A field ref whose uses only read is a read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ade for
`let a = { item: new C() }` builds the literal in a local a `ts.Constant`
starts, stores the fresh value into its field, and reads the record once
into `a`. That is the record built to be returned (recordRetainOf) with
an owning local in place of the result slot: the fresh value moves into
the record, and the record into `a`, whose `ts.RetainSlot` is rc's
reference for the values moved in. `a`'s scope exit releases it. The
assignment form stores the read into an owning local, and is accepted
the same way.
Measured (AOT, measure.ps1, a loop building and dropping such records):
own 4.2 MB at both 20000 and 200000 iterations, as rc; none 7.7 -> 35.2.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ASDAlexander77
force-pushed
the
own-phase-6
branch
from
October 2, 2026 16:39
c4db121 to
947f721
Compare
This was referenced Oct 2, 2026
A global initialized from another global reads garbage (heap-typed globals; crash with a class)
#446
Closed
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 6 of
-mm=own: the corpus report, and the shapes it says matter. The plan isdocs/superpowers/plans/2026-10-02-own-phase-6.md; the results are in spec §20.Rebased on main after #443 and #444 merged: 5 commits. On the rebased branch, the Release suite passes 3415 of 3416 (the same stale default-library test), and the own corpus is unchanged at 402 compiling files. The corpus now has 592 files; #443's new
00iterator_methodsis rejected under own, as #443's comment documents.The report
After 7b, 227 of the 591 corpus files fail under own. 137 of those stop at the catch-all "takes a second reference", which names no rule. A temporary dump at the catch-all's four report sites (kept out of the tree) split the 137 into shapes. Spec §20.1 has the tables, including how many files have each shape as their only blocker.
What this PR accepts
A global's initializer. It runs in the global's region, which no function's inference sees, so rc's retain for its
ts.GlobalResultreached the lowering's guard ("left a retain behind", 8 files). The signature pass now erases that retain when three things hold:ts.GlobalResult: directly, through a view, as an array-literal element, or copied into an object literal's box.Any other retain there is reported by the global's name.
Data nothing owns (
isConstantData,OwnershipFacts.h): a number or null in a union, ats.Constantor a field of one, a function named by ats.SymbolRef, and a tuple of these.ts.RetainSlotonly qualifies while nothing is stored into the slot or its fields.--opt, CSE merges equal literals.A record literal made for an owning local,
let a = { item: new C() }, anda = {...}. This is 7a's "record built to be returned", with an owning local in place of the result slot.For review
ownsHeaps disagree by design.isConstantDatalives inOwnershipFacts.hand both passes read it. The header'sownsHeaplooks at the type only; the inference pass overrides it for ats.Newseen as its object. That disagreement produced a regression while this PR was being built:00object, one object literal stored into two records, which 7a rightly rejects, compiled again. Hence:ts.Newexclusion, pinned by the new negativeown_err_literal_two_records;ts.NewInterfaceview boxes. Forown_err_interface_two_views, each exclusion alone keeps the test rejected.--opt, but the test runner uses--opt --opt_level=3. The gate (test-runner AOT and JIT on every newly compiling file) caught01optional, which only failed under--opt. The final count is the same either way.Verification
Release suite: 3409 of 3410 pass. The one failure,
test-compile-gc-defaultlib-collector, is the stale installed default library, as on -mm=own phase 5a: a closure that does not escape borrows what it captures #436-A global declared in top-level code owns what it is given (rc; -mm=own phase 6, PR 1) #444.WSL/GCC: builds, and the 2066 tests run there pass (own, rc corpus, none corpus).
Own corpus: 364 → 402 of 591 including A global declared in top-level code owns what it is given (rc; -mm=own phase 6, PR 1) #444 (402 with
--opttoo), none lost. Re-gated on the final build, all 38 pass test-runner-mm=own, AOT and JIT, with gc's output.First errors: the catch-all falls 137 → 101, and "left a retain behind" 8 → 0.
Memory: a loop building and dropping
let a = { item: new Leaf(i) }, AOT,measure.ps1, in MB. This is the only rule here that erases a release.Teeth: each rule was undone with a temporary switch, and its test fails. That covers the global erase, the constant-data erase, the constant-data no-use-after-move check, the
ts.Newexclusion and the record rule. The boxing exclusion is a second guard (above).Tests
own_global_init,own_constant_data,own_record_local.own_err_literal_two_records.Not in this PR (spec §20.4-§20.6)
let b = aat module level). With a class, the program faults.-shared, an exportedconstfrom such a module can't be resolved.🤖 Generated with Claude Code