Repository navigation
-mm=own: c ? h : h2 bound in a loop borrows the one it chooses - #672
Merged
Merged
Conversation
A ternary of two locals lowers to an arith.select (or, when a side has a call, a cf branch passing each as a block argument). Neither was a read to own, so the merge took the value, and inside a loop that was "moved inside a loop but was made outside it" for every type. A merge whose value is only read - walkBorrowed finds no store, return, capture or retain of it, a `let` declared from a merge of values the function made borrowing as `let b = a` does - is now a borrow of each value it chooses, checked against that value's releases. What reads the merged value is a read of each source, so a use of it after a move of one is still a use after the move. A merge whose value is kept is still a taker, decided as before. walkBorrowed passes through a select. own_ternary_outer_loop runs under every model; 00interface_cast_unrelated gets its loop case back. Stored, returned and captured merges stay errors. 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.
Problem
Under
-mm=own, bindingcond ? x : yinside a loop, wherexandyare locals made before the loop, was rejected for every type, a plain class included:The ternary lowers to an
arith.selectof the two values, or to acfbranch that passes each as a block argument when one side has a call. own did not treat either as a read, so it counted the merge as taking the value. #671 found this and rewrote the loop case in00interface_cast_unrelatedto avoid it.Fix
borrowsThroughMerge/mergedValuesOf(OwnershipInferenceMoves.cpp): a merge whose value is only read now counts as a borrow of each value it chooses. "Only read" meanswalkBorrowedfinds no store, return, capture or retain of the merged value, and none of its uses runs after one of the source's releases.his still a use after that move.let each = c ? h : h2: whenhandh2are values the function made,eachborrows the merge the waylet b = adoes. Itsts.RetainSlotandts.ReleaseSlotare erased, anddecideRetainsskips them throughmergeBorrowRetains.walkBorrowed(passesOn) passes through a select, as it already did through a branch.checkValueMoves(borrowinglets) also leaves such a merge out of its takers.Tests
own/own_ternary_outer_loop.tsbinds the ternary inside a loop and readshandh2after the loop. It covers aconstand alet, a class and an interface, the branch form (i % 4 == 0 ? h : (odd(i) ? h2 : h)) and one side made inside the loop. It runs under own, rc, gc and none, JIT and AOT, and own emits no counting.tests/00interface_cast_unrelated.tsgets its loop case back. Its element case ([h]) stays rewritten, because that one really is a move ofh.own_err_ternary_loop_stored(pushed),own_err_ternary_loop_returned(aletreturned) andown_err_ternary_loop_captured(captured by an escaping closure). All three are stillmoved inside a loop.ctest -C Release5446/5446 passed. Linux (WSL, ninja Release): 5428/5428 passed.Not covered
let each = c ? h : h2wherehandh2are themselveslets. The merge is of their reads, whichmovesOfdoes not check, so it is still rejected. It was rejected before this PR as well. Aconst eachof the same reads compiles, before and after.constthat a ternary branch yields is never released.releaseDiscardedTemporariesskips any value that ats.Resultuses. So the class-typed cases leakhandh2under rc, and under own too. The interface cases don't leak. This belongs in OwnedReturnConsumptionPass, not in own, and a separate session is working on it.🤖 Generated with Claude Code