Avoid redundant clone suggestions in borrowck diagnostics#154197
Avoid redundant clone suggestions in borrowck diagnostics#154197rust-bors[bot] merged 2 commits intorust-lang:mainfrom
Conversation
|
r? @adwinwhite rustbot has assigned @adwinwhite. Use Why was this reviewer chosen?The reviewer was selected based on:
|
This comment has been minimized.
This comment has been minimized.
|
The failed tests tell me another case of the issue. Let me mark PR as draft. |
e986806 to
9020069
Compare
| /// Tracks which suggestions were emitted by [`MirBorrowckCtxt::explain_captures`], | ||
| /// so callers can avoid emitting redundant suggestions downstream. | ||
| struct ExplainCapturesResult { | ||
| clone_suggestion: CloneSuggestion, |
There was a problem hiding this comment.
it's fine to use bool here instead of enum
There was a problem hiding this comment.
9020069 to
1c123db
Compare
|
I'll possibly take a look today or tomorrow. I'm rather busy at the moment, so I wouldn't expect this to be that quick, to be honest. |
|
It seems that @Kivooeo is quite busy. I'll have a look. |
|
Some nits, otherwise it's a very nice improvement. Thank you for working on this! |
|
This PR also improves the diag for the case below, I think. use std::ops::Deref;
struct MyBox<T>(T);
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
pub fn main() {
let _x = MyBox(vec![1, 2]).into_iter();
// currently we have a simple clone help which is wrong. it's better to have UFCS.
} |
|
@rustbot author |
|
Reminder, once the PR becomes ready for a review, use |
|
Thank you! Let me try 👍 |
| self.explain_captures( | ||
| // The return value indicates whether a clone suggestion was emitted; | ||
| // redundancy is already handled via the `FnSelfUse` check below. | ||
| let _ = self.explain_captures( |
There was a problem hiding this comment.
This isn't a real result. I think the wildcard binding is unnecessary.
| moved_place: Place<'tcx>, | ||
| msg_opt: CapturedMessageOpt, | ||
| ) { | ||
| ) -> ExplainCapturesResult { |
There was a problem hiding this comment.
Would it be better to use a simple enum as return type? For readability and less indirect wrapper.
| span: Span, | ||
| use_spans: Option<UseSpans<'tcx>>, | ||
| ) -> Diag<'infcx> { | ||
| ) -> (Diag<'infcx>, bool) { |
There was a problem hiding this comment.
We don't really get what the bool means from the fn signature.
|
Oh, thank you for the comments! Let me address your comments 👍 |
|
Final nits: Could you bless and add a After squashing all commits, r=me |
|
@bors delegate+ |
|
✌️ @yuk1ty, you can now approve this pull request! If @adwinwhite told you to " |
5451a7a to
958cd36
Compare
This comment has been minimized.
This comment has been minimized.
958cd36 to
5409599
Compare
|
This PR was rebased onto a different main commit. Here's a range-diff highlighting what actually changed. Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers. |
This comment has been minimized.
This comment has been minimized.
5409599 to
61ff157
Compare
|
@bors r=me |
|
@bors r- |
|
This pull request was unapproved. |
… r=adwinwhite Avoid redundant clone suggestions in borrowck diagnostics Fixes rust-lang#153886 Removed redundant `.clone()` suggestions. I found that there are two patterns to handle this issue while I was implementing: - Should suggest only UFCS - Should suggest only simple `.clone()` For the target issue, we can just remove the UFCS (`<Option<String> as Clone>::clone(&selection.1)`) side. However, for the `BorrowedContentSource::OverloadedDeref` pattern like `Rc<Vec<i32>>`, for instance the `borrowck-move-out-of-overloaded-auto-deref.rs` test case, I think we need to employ the UFCS way. The actual test case is: ```rust //@ run-rustfix use std::rc::Rc; pub fn main() { let _x = Rc::new(vec![1, 2]).into_iter(); //~^ ERROR [E0507] } ``` And another error will be shown if we simply use the simple `.clone()` pattern. Like: ```rust use std::rc::Rc; pub fn main() { let _x = Rc::new(vec![1, 2]).clone().into_iter(); } ``` then we will get ``` error[E0507]: cannot move out of an `Rc` --> src/main.rs:5:14 | 5 | let _x = Rc::new(vec![1, 2]).clone().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----------- value moved due to this method call | | | move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait | note: `into_iter` takes ownership of the receiver `self`, which moves value --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:310:18 | 310 | fn into_iter(self) -> Self::IntoIter; | ^^^^ help: you can `clone` the value and consume it, but this might not be your desired behavior | 5 - let _x = Rc::new(vec![1, 2]).clone().into_iter(); 5 + let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); | For more information about this error, try `rustc --explain E0507`. ``` [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=7e767bed3f1c573c03642f20f454ed03) In this case, `Rc::clone` only increments the reference count and returns a new `Rc<Vec<i32>>`; it does not grant ownership of the inner `Vec<i32>`. As a result, calling into_iter() attempts to move the `Vec<i32>`, leading to the same E0507 error again. On the other hand, in UFCS form: ``` <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter() ``` This explicitly calls `<Vec<i32> as Clone>::clone`, and the argument `&Rc<Vec<i32>>` is treated as `&Vec<i32>` via Rc’s `Deref` implementation. As a result, the `Vec<i32>` itself is cloned, yielding an owned `Vec<i32>`, which allows `into_iter()` to succeed, if my understanding is correct. I addressed the issue as far as I could find the edge cases but please advice me if I'm overlooking something.
Rollup of 7 pull requests Successful merges: - #155643 (Improve suggestion for $-prefixed fragment specifiers) - #154197 (Avoid redundant clone suggestions in borrowck diagnostics) - #154372 (Exposing Float Masks) - #155680 (Handle index projections in call destinations in DSE) - #155732 (bootstrap: Don't clone submodules unconditionally in dry-run) - #155737 (Account for `GetSyntheticValue` failures) - #155738 (Pass fields to `is_tuple_fields` instead of `SBValue` object)
Rollup merge of #154197 - yuk1ty:fix-redundant-clone-error2, r=adwinwhite Avoid redundant clone suggestions in borrowck diagnostics Fixes #153886 Removed redundant `.clone()` suggestions. I found that there are two patterns to handle this issue while I was implementing: - Should suggest only UFCS - Should suggest only simple `.clone()` For the target issue, we can just remove the UFCS (`<Option<String> as Clone>::clone(&selection.1)`) side. However, for the `BorrowedContentSource::OverloadedDeref` pattern like `Rc<Vec<i32>>`, for instance the `borrowck-move-out-of-overloaded-auto-deref.rs` test case, I think we need to employ the UFCS way. The actual test case is: ```rust //@ run-rustfix use std::rc::Rc; pub fn main() { let _x = Rc::new(vec![1, 2]).into_iter(); //~^ ERROR [E0507] } ``` And another error will be shown if we simply use the simple `.clone()` pattern. Like: ```rust use std::rc::Rc; pub fn main() { let _x = Rc::new(vec![1, 2]).clone().into_iter(); } ``` then we will get ``` error[E0507]: cannot move out of an `Rc` --> src/main.rs:5:14 | 5 | let _x = Rc::new(vec![1, 2]).clone().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ ----------- value moved due to this method call | | | move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait | note: `into_iter` takes ownership of the receiver `self`, which moves value --> /playground/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:310:18 | 310 | fn into_iter(self) -> Self::IntoIter; | ^^^^ help: you can `clone` the value and consume it, but this might not be your desired behavior | 5 - let _x = Rc::new(vec![1, 2]).clone().into_iter(); 5 + let _x = <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter(); | For more information about this error, try `rustc --explain E0507`. ``` [Rust Playground](https://play.rust-lang.org/?version=stable&mode=debug&edition=2024&gist=7e767bed3f1c573c03642f20f454ed03) In this case, `Rc::clone` only increments the reference count and returns a new `Rc<Vec<i32>>`; it does not grant ownership of the inner `Vec<i32>`. As a result, calling into_iter() attempts to move the `Vec<i32>`, leading to the same E0507 error again. On the other hand, in UFCS form: ``` <Vec<i32> as Clone>::clone(&Rc::new(vec![1, 2])).into_iter() ``` This explicitly calls `<Vec<i32> as Clone>::clone`, and the argument `&Rc<Vec<i32>>` is treated as `&Vec<i32>` via Rc’s `Deref` implementation. As a result, the `Vec<i32>` itself is cloned, yielding an owned `Vec<i32>`, which allows `into_iter()` to succeed, if my understanding is correct. I addressed the issue as far as I could find the edge cases but please advice me if I'm overlooking something.
|
@adwinwhite I'm sorry I misunderstood. Thank you for your support! |
View all comments
Fixes #153886
Removed redundant
.clone()suggestions.I found that there are two patterns to handle this issue while I was implementing:
.clone()For the target issue, we can just remove the UFCS (
<Option<String> as Clone>::clone(&selection.1)) side.However, for the
BorrowedContentSource::OverloadedDerefpattern likeRc<Vec<i32>>, for instance theborrowck-move-out-of-overloaded-auto-deref.rstest case, I think we need to employ the UFCS way. The actual test case is:And another error will be shown if we simply use the simple
.clone()pattern. Like:then we will get
Rust Playground
In this case,
Rc::cloneonly increments the reference count and returns a newRc<Vec<i32>>; it does not grant ownership of the innerVec<i32>. As a result, calling into_iter() attempts to move theVec<i32>, leading to the same E0507 error again.On the other hand, in UFCS form:
This explicitly calls
<Vec<i32> as Clone>::clone, and the argument&Rc<Vec<i32>>is treated as&Vec<i32>via Rc’sDerefimplementation. As a result, theVec<i32>itself is cloned, yielding an ownedVec<i32>, which allowsinto_iter()to succeed, if my understanding is correct.I addressed the issue as far as I could find the edge cases but please advice me if I'm overlooking something.