ergonomic_clones_dotuse_capture_by_ref: Capture upvar by ref for .use in non-move closures#157270
Open
Dnreikronos wants to merge 3 commits into
Open
ergonomic_clones_dotuse_capture_by_ref: Capture upvar by ref for .use in non-move closures#157270Dnreikronos wants to merge 3 commits into
.use in non-move closures#157270Dnreikronos wants to merge 3 commits into
Conversation
When a method call fails to resolve, the suggestion machinery probes all traits for a method with the same name and builds a trait reference for the providing trait to detect duplicate trait items coming from multiple crate versions. It passed only the receiver type as the single argument, which is correct only for traits whose sole generic parameter is `Self`. For a trait with further parameters (for example `Borrow<Borrowed>`), or when the receiver type is unknown, the argument list no longer matched the trait's generics and tripped the `debug_assert_args_compatible` assertion, producing an ICE. Build the argument list with `GenericArgs::for_item` instead, using the receiver type for `Self` when known and fresh inference variables for the remaining parameters.
A plain `|| { x.use }` closure marked the upvar capture as `ByUse`,
which clones the value into the closure at construction time. The
`.use` in the body then clones again on every call, so the value was
cloned once more than the number of invocations.
A `ByUse` capture in a non-`move`/`use` closure can only originate from
a `.use` expression in the body; a `use ||` capture clause is handled by
`adjust_for_use_closure` instead. Capture such places by immutable
borrow so the `.use` clones once per evaluation and nothing is cloned
into the closure at construction.
Collaborator
|
r? @folkertdev rustbot has assigned @folkertdev. Use Why was this reviewer chosen?The reviewer was selected based on:
|
Contributor
|
r? types |
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.
Fixes #157141
A plain
|| { x.use }closure was cloning the captured value one time too many: once when the closure is built, then once per call. So two invocations produced three clones.The capture analysis marked the upvar as
ByUse, which clones the value into the closure at construction time, and the.usein the body still clones on every call. But for a closure without amoveorusekeyword, aByUsecapture can only come from a.useexpression in the body. Ause ||capture clause is handled separately inadjust_for_use_closure. Theast::CaptureBy::Usedocs already spell this out: a regular|| x.useshould not produce aUsecapture, it should look at the type and treatx.useas a copy/clone/move as appropriate.So in
adjust_for_non_move_closure, capture such places by immutable borrow instead. The.usethen clones once per evaluation and nothing is cloned into the closure up front, matching the count you get from a directx.useor amove ||closure.use ||andmove ||are unaffected.