Repository navigation
-mm=own: a generator over its this parameter borrows it - #701
Merged
Merged
Conversation
`a.keys()` of an array was "'this' is a parameter, kept here": the generator lowering gives `next` the body's `this` through `const .this = this`, and for a `this` parameter that alias was a local of its own, captured as a cell - so the state owned a copy of the caller's array. The alias is now a ConstRef to the parameter's storage (captured, unlike for-in's `.a`), so the closure captures the parameter and the state borrows it like any other (spec 19). Spec section 40. 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.
Summary
Under
-mm=own, an array'sa.keys()anda.values()failed with:Both are generators whose first parameter is
this(function* keys<T>(this: T[])).The cause is in the generator lowering.
buildGeneratorWrapperDeclarationgivesnextthe body'sthisthrough an alias,const .this = this, becausenexthas athisof its own.this, which the state holds by value.thisparameter, the alias was a separate local initialised from the parameter and captured into the state's box as a cell. That cell is not the parameter's, so the state owned a copy of the caller's array.The fix, in two parts:
thisis a parameter, the alias is now aConstRef, so the name is the parameter's storage, as for-in's.ais its array's.ConstRefs are normally never captured (setIgnoreCapturing, for.a);.thisnow is. Sonextcaptures the parameter'sts.Paramitself, and the state borrowsthislike any other parameter (spec §19):this@borrows("this")Under the other models the alias was a second reference to the same array; now it is the parameter's own cell.
Spec §40 is new, and
docs/own-memory-model.mdis updated.Tests
New
own_generator_this_param, run under own, rc, gc and none with churn between steps:this: C[]in afor...of@borrows("this")functionWithout the change it fails:
@borrows("this")is refused because nothing the function returns borrows. AOT under own: 200000 iterations peak at 4.4 MB, against 4.3 MB at 1000.New negative
own_err_generator_this_param_returned: the generator returned by a function without@borrows("this").Full
ctest -C Release: 5892 passed, 0 failed.DefaultLib suites, with the companion
@borrows("this")on Array'siterator():array_keys,array_values,array_iterator), with no new failures.Not here:
entries(), whoseyield [i, this[i]]puts a borrowed element into a tuple the caller owns.🤖 Generated with Claude Code