-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
New lint: needless_move
#11759
New lint: needless_move
#11759
Conversation
r? @Centri3 (rustbot has picked a reviewer for you, use r? to override) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some drive-by comments, I noticed the pr is marked ready now :)
clippy_lints/src/needless_move.rs
Outdated
// Collect moved & borrowed variables from the closure, which the closure *actually* needs. | ||
let MovedVariablesCtxt { | ||
moved_vars, | ||
mut captured_vars, | ||
} = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this use the closure_captures
query, or is there a reason that it isn't used? Reusing rustc's code seems like it would make it simpler and less error prone than reimplementing the capture rules in clippy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used that in the first commit (a66be9d), but it was kind of faulty because a move
closure will always capture by value, e.g. have the captured_place.info.capture_kind == UpvarCapture::ByValue
, regardless of whether that value is actually consumed in the body of the closure or not (unless the type is Copy
?). What this would need in order to properly function is basically the closure_captures
query applied on the same closure, but without the move
keyword, because then we could use the inference results to tell whether a variable needs to be moved or if it is just referenced, but sadly getting that modified closure is a quest I failed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh right, that's unfortunate
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I've found the file that does most of that analysis: https://github.com/rust-lang/rust/blob/master/compiler/rustc_hir_typeck/src/upvar.rs
Maybe exposing a few of those functions would be helpful for this lint, so I'm gonna look into it soon.
e80c3ba
to
d1b3fdf
Compare
☔ The latest upstream changes (presumably #11791) made this pull request unmergeable. Please resolve the merge conflicts. |
7a949c3
to
fea8899
Compare
☔ The latest upstream changes (presumably #11781) made this pull request unmergeable. Please resolve the merge conflicts. |
fb343f3
to
14da14a
Compare
20b12fc
to
f3fcd2a
Compare
clippy_lints/src/needless_move.rs
Outdated
/// E.g. all the values are captured by value into the closure / `async` block. | ||
/// | ||
/// ### Why is this bad? | ||
/// Pedantry |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be expanded upon
clippy_lints/src/needless_move.rs
Outdated
|
||
match lint_result { | ||
LintResult::NothingCaptured => { | ||
lint("there were no captured variables, so the `move` is unnecessary"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could probably be a let note_msg = match lint_result ...
instead, and early return on NeedMove
.
Using a closure is a bit more complex, and imo harder to read
clippy_lints/src/needless_move.rs
Outdated
return; | ||
} | ||
|
||
let ExprKind::Closure(closure) = &expr.kind else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a let-chain instead. However since this is only ever called once, maybe you can inline it?
015ce17
to
e2dc5a1
Compare
☔ The latest upstream changes (presumably #11597) made this pull request unmergeable. Please resolve the merge conflicts. |
There are merge commits (commits with multiple parents) in your changes. We have a no merge policy so these commits will need to be removed for this pull request to be merged. You can start a rebase with the following commands:
The following commits are merge commits: |
065aad2
to
1e1efac
Compare
☔ The latest upstream changes (presumably #11878) made this pull request unmergeable. Please resolve the merge conflicts. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nya
tests/ui/needless_move.stderr
Outdated
LL | let closure = assert_static(move || { | ||
| ^---- | ||
| | | ||
| _________________________________help: remove the `move` | ||
| | | ||
LL | | with_ref(&a); | ||
LL | | with_owned(a); | ||
LL | | }); | ||
| |_____^ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can see this getting out of hand quickly on larger closures. Can you make it so the span doesn't include the value (the block/expression)?
// rust/tests/ui/async-await/deep-futures-are-freeze.rs | ||
|
||
fn _deep_futures_are_freeze() { | ||
// no-prefer-dynamic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to ensure x test
won't read these, somehow, I dunno, very cautious 😅 I doubt it does when running tests in subtrees or when they aren't at the top of the file
Or just remove them
impl<'tcx> euv::Delegate<'tcx> for MovedVariablesCtxt<'tcx> { | ||
fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, hir_id: HirId) { | ||
if let euv::PlaceBase::Upvar(_) = cmt.place.base { | ||
self.moved.push((cmt.place.clone(), hir_id)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there any reason we can't store &'tcx Place<'tcx>
to prevent cloning? This is cheap if projections is empty, tho you're cloning a Vec
otherwise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cmt
is not a &'tcx
reference, so the lifetimes don't add up and the borrow checker is unhappy.
}, | ||
}; | ||
|
||
span_lint_and_then( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should call is_from_proc_macro
here. You can implement WithSearchPat
for Closure
by reusing the code for ExprKind::Closure
in expr_search_pat
Hey @dnbln, this is a ping from triage, since there hasn't been any activity in some time. Are you still planning to continue this implementation? If you have any questions, you're always welcome to ask them in this PR or on Zulip. @rustbot author Also this PR needs a new reviewer since r? @y21 would you mind taking this review? You can also ping |
An implementation for the lint described in rust-lang#11721
see discussion in rust-lang#11721
1e1efac
to
7a3337a
Compare
Hi @xFrednet. I've honestly really began to doubt the usefulness of this lint, so I don't think I'll be investing any more time into it. |
I do still quite like this as a restriction (very pedantic style) lint. I might get around to it eventually if nobody else picks it up :3 |
I'll just leave the script I used to extract the tests from the rust repo here, if anyone else is interested in continuing this and might find it useful: https://gist.github.com/dnbln/6b03d98bf189d76236a51ae9e2082433 |
A lint to check for uses of
move
on closures which aren't necessary. See #11721.Fixes #11721.
Currently blocked on rust-lang/rust#117585, and an eventual sync.changelog: [
needless_move
]: A lint for unnecessarymove
s on closures / async blocks.