Repository navigation
-mm=own: untyped literals given later, fields taken out of temporaries; rc branch-temporary fix - #724
Merged
Merged
Conversation
…aries
An object literal a variable is declared with, with no type, makes its
this-free arrows closures when they name no local around them (spec 62):
`const o = { w: (x: number) => x * 2 }; apply(o); o.w(1)` compiles under
own. MLIRGen marks such a literal UntypedVariableInitializer. A literal
returned or given with no receiver keeps its methods, which an interface's
vtable takes, and so does an arrow that may capture a local.
A field read out of a call's own result in one branch of `??` or `?:`,
retained right after the read and the result released after that, is a
move out of the field under own (spec 63): `let result = initial ??
next(xs, 0).value`. The retain goes, and an empty value is stored into the
field before the release.
rc: a branch that yields a field read out of a temporary it made now
retains it before the temporary goes (consumeConditionalResults). Before,
`const item = given ?? pair(n).item` read freed memory, and with `let`
the program died.
Tests: own_literal_variable_closures, own_temporary_field_take (own, rc,
gc, none).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… null for null An object literal boxed as it is (typeof 'object' or 'tuple') was read as the interface's (this, vtable) pair, and the call through it crashed under every model. The box says only that it holds a literal, not which fields, so no vtable can be laid out: ___unbox_interface now throws "Can't cast from any: an object literal has no vtable for interface ...". An interface value made of a literal before it was boxed still round-trips. A boxed null (or undefined) cast to an interface was not null under rc, none and own, where it is a box of its own; it now gives the null interface. Test: 00any_literal_to_interface. 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.
The two -mm=own items left open after #723, plus an rc bug found on the way.
An untyped object literal given later to a function-typed field (own spec §62).
const o = { w: (x: number) => x * 2 }; apply(o); o.w(1)was rejected under own: the literal's arrow was a method bound to the literal, and reading it intoapply's field handed out the literal. Arrows in a literal given to a variable declared with no type are now closures, as #722 made them for literals with an object-type receiver, when they say nothisand name no local around them. An arrow that may capture a local stays a method: copied out of the literal by a cast to an interface, its captures would still be the literal's. A literal returned or given with no receiver keeps its methods, which an interface's vtable takes (00interface_type_tag_in_vtable).A field taken out of a temporary in a branch (own spec §63).
let result = initial ?? next(xs, 0).value(DefaultLib'sreduceshape) was rejected: the branch reads the field ofnext's result, and the result is released before the branch ends. When rc retains the read right after it, and the result is released after that and read nowhere else, own now moves the value out: the retain goes, and an empty value is stored into the field before the release. String fields too.rc: a field read out of a temporary in one branch of
??/?:was freed with it.const item = given ?? pair(n).itemread 0 under rc, and withletthe program died: nothing retained the field before the temporary's release inside the branch. Only ananyfield, whose other branch boxed a fresh value, happened to be retained.consumeConditionalResultsnow has such a branch retain what it yields, so thets.Ifcarries the reference.anyto an interface (every model).<Adder>xof ananyholding an object literal read the literal's block as the interface's (this, vtable) pair and crashed. The box says only that it holds a literal (typeof'object' or 'tuple'), not which fields, so no vtable can be laid out: the cast now throws. An interface value made of a literal before boxing still round-trips. A boxednullcast to an interface was non-null under rc, none and own; it is now the null interface.Tests (own, rc, gc, none):
own_literal_variable_closures,own_temporary_field_take,00any_literal_to_interface. Teeth: without the empty-value store, the own build ofown_temporary_field_takefails.Validated on Windows: ctest 6203/6203; DefaultLib release passes under gc (175), rc and none (174 + 1 gc-only skip), own (164 + 11 not-own skips).
Still not covered under own: a literal whose arrows capture a local, given later (
{ w: x => x * k }); a field of a named class local (const r = next(); initial ?? r.value); a parameter on the other branch (given ?? pair(n).item, kept).🤖 Generated with Claude Code