-
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
Use ControlFlow in more places #12830
Conversation
Looks like this broke some tests 😅 |
I've done some changes, it doesn't break any test files but it seems to not run EDIT: On CI it seems like there aren't any issues, could you test the patch on your PC to check? Maybe it's just my workflow |
I've had this commit already finished for the last... 3 days? I'm not sure why I didn't commit it 😅 |
@oli-obk do you have some commentary on this weird behaviour |
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 possible improvements :)
btw didn't this also change |
@@ -109,30 +109,43 @@ pub fn for_each_expr<'tcx, B, C: Continue>( | |||
res: Option<B>, | |||
} | |||
impl<'tcx, B, C: Continue, F: FnMut(&'tcx Expr<'tcx>) -> ControlFlow<B, C>> Visitor<'tcx> for V<B, F> { | |||
fn visit_expr(&mut self, e: &'tcx Expr<'tcx>) { | |||
type Result = ControlFlow<()>; |
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.
wondering if this can also just be ControlFlow<B>
like in some of the other visitors to get rid of the res
field? tho this might require some more involved changes... 🤔
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've tried this, and the generic rules in the language doesn't permit us to do it because B
in the internal impl and B
in the external impl could be different (even if it's never actually different) :/
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 feel like this should be possible, but fine, I can also look into- and try this in a followup, separately, and we can just keep this one as is
clippy_lints/src/if_let_mutex.rs
Outdated
cx: &'a LateContext<'tcx>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { | ||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { | ||
type Result = ControlFlow<&'tcx Expr<'tcx>>; |
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.
side note, not caused by this pr: isn't this visitor doing exactly the same thing as the other ArmVisitor
in this file? 😅
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 think this comment could be worth to look at as a small cleanup. But it's optional.
clippy_lints/src/if_let_mutex.rs
Outdated
if found_mutex.is_none() { | ||
found_mutex = arm_visit.visit_expr(if_else).break_value(); |
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 is technically a semantic change, we're no longer overriding the mutex if we found one in the then
branch, that is, this no longer emits a warning:
let x = Mutex::new(42);
let unrelated = Mutex::new(());
if let 42..=50 = *x.lock().unwrap() {
drop(unrelated.lock()); // ... `arm_visit.found_mutex_if_same_as()` is false here
} else {
drop(x.lock()); // never visited
};
on the other hand, the same argument can be made for the already existing logic, the current code already also has this bug if you swap the x.lock()
and unrelated.lock()
in the two branches, so.. 🤷 maybe we should just leave it and open an issue
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'll just keep the same behaviour, we can then talk about if the current behaviour should be like that :)
@@ -305,7 +304,9 @@ where | |||
{ | |||
self.found_default_call = true; |
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.
same here, still has a found_*
field
clippy_lints/src/unused_peekable.rs
Outdated
@@ -137,14 +135,15 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> { | |||
&& func_did == into_iter_did | |||
{ | |||
// Probably a for loop desugar, stop searching | |||
return; | |||
return ControlFlow::Continue(()); | |||
} | |||
|
|||
if args.iter().any(|arg| arg_is_mut_peekable(self.cx, arg)) { | |||
self.found_peek_call = true; |
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.
also here
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.
Done!
☔ The latest upstream changes (presumably #12921) made this pull request unmergeable. Please resolve the merge conflicts. |
3d549fb
to
d241556
Compare
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.
Two more small things (also CI is red, need to fix that too)
} | ||
intravisit::walk_expr(self, expr) |
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 was previously inside of an else {}
but isn't anymore with this change, so we descend into things when we don't need to right now
clippy_lints/src/unused_peekable.rs
Outdated
@@ -70,15 +71,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable { | |||
return; | |||
} | |||
|
|||
let mut found_peek_call = false; | |||
|
|||
for stmt in &block.stmts[idx..] { |
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.
Could simplify this for loop into let found_peek_call = block.stmts[idx..].iter().any(|stmt| vis.visit_stmt(stmt).is_break());
☔ The latest upstream changes (presumably #12999) 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.
Alright, the changes look fine to me now. But I would like another person to quickly skim over the changes here and double check since some of these visitors are used by a lot of lints and a bug here can easily cause subtle bugs.
Maybe @xFrednet? Quick tldr/context: like the description says, this adds a type Result = ControlFlow
and uses Break
in some visitors to short circuit them (also makes it nicer since the final value that the lints are interested in are directly in the ControlFlow::Break
and don't need their own field
Sure, I'll have a look at it tomorrow. |
If we rebase, we can also use our CI to check if there are any changed :3 |
a52281b
to
aca0401
Compare
aca0401
to
4e222c6
Compare
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.
Four smaller formatting nits. (As usual, probably a bit nitpicky ^^') The semantic changes all look good to me and I like the refactoring!
The CI is also happy and doesn't report any lint changes 👍
You can r=y21,xFrednet
once you've addressed the last comments.
clippy_lints/src/if_let_mutex.rs
Outdated
cx: &'a LateContext<'tcx>, | ||
} | ||
|
||
impl<'tcx> Visitor<'tcx> for OppVisitor<'_, 'tcx> { | ||
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) { | ||
type Result = ControlFlow<&'tcx Expr<'tcx>>; |
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 think this comment could be worth to look at as a small cleanup. But it's optional.
☔ The latest upstream changes (presumably #13065) made this pull request unmergeable. Please resolve the merge conflicts. |
cfe4c15
to
5fedd60
Compare
5fedd60
to
b21a91a
Compare
LGTM, thanks! Roses are red, |
Use ControlFlow in more places Now, instead of manually using variables in visitors to signify that a visit is "done" and that the visitor should stop traversing. We use the trait type "Result" to signify this (in relevant places). I'll schedule a perf run, I don't think it will be much of a difference, but every bit of performance is welcomed :) Fixes #12829 r? `@y21`
💔 Test failed - checks-action_test |
@bors retry |
@bors r=y21,xFredNet |
💡 This pull request was already approved, no need to approve it again. |
☀️ Test successful - checks-action_dev_test, checks-action_remark_test, checks-action_test |
Remove unnecessary `res` field in `for_each_expr` visitors Small refactor in the `for_each_expr*` visitors. This should not change anything functionally. Instead of storing the final value `Option<B>` in the visitor and setting it to `Some` when we get a `ControlFlow::Break(B)` from the closure, we can just directly return it from the visitor itself now that visitors support that. cc #12829 and #12830 (comment) changelog: none
Now, instead of manually using variables in visitors to signify that a visit is "done" and that the visitor should stop traversing. We use the trait type "Result" to signify this (in relevant places).
I'll schedule a perf run, I don't think it will be much of a difference, but every bit of performance is welcomed :)
changelog: Improve performance, less memory use in visitors
Fixes #12829
r? @y21