Skip to content

Commit a78551b

Browse files
committed
Auto merge of #9556 - evantypanski:et/issue-9369, r=Alexendoo
[`redundant_closure`] Fix suggestion causes error for `impl FnMut` Fixes #9369 changelog: [`redundant_closure`] Fix suggestion causes error with `impl FnMut` types
2 parents 5f25f7e + dbadf37 commit a78551b

File tree

4 files changed

+51
-10
lines changed

4 files changed

+51
-10
lines changed

clippy_lints/src/eta_reduction.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
22
use clippy_utils::higher::VecArgs;
33
use clippy_utils::source::snippet_opt;
4-
use clippy_utils::ty::is_type_diagnostic_item;
4+
use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
55
use clippy_utils::usage::local_used_after_expr;
66
use clippy_utils::{higher, is_adjusted, path_to_local, path_to_local_id};
77
use if_chain::if_chain;
@@ -11,7 +11,7 @@ use rustc_hir::{Closure, Expr, ExprKind, Param, PatKind, Unsafety};
1111
use rustc_lint::{LateContext, LateLintPass};
1212
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow};
1313
use rustc_middle::ty::binding::BindingMode;
14-
use rustc_middle::ty::{self, ClosureKind, Ty, TypeVisitable};
14+
use rustc_middle::ty::{self, Ty, TypeVisitable};
1515
use rustc_session::{declare_lint_pass, declare_tool_lint};
1616
use rustc_span::symbol::sym;
1717

@@ -122,15 +122,12 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
122122
then {
123123
span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
124124
if let Some(mut snippet) = snippet_opt(cx, callee.span) {
125-
if_chain! {
126-
if let ty::Closure(_, substs) = callee_ty.peel_refs().kind();
127-
if substs.as_closure().kind() == ClosureKind::FnMut;
128-
if path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr));
129-
130-
then {
125+
if let Some(fn_mut_id) = cx.tcx.lang_items().fn_mut_trait()
126+
&& implements_trait(cx, callee_ty.peel_refs(), fn_mut_id, &[])
127+
&& path_to_local(callee).map_or(false, |l| local_used_after_expr(cx, l, expr))
128+
{
131129
// Mutable closure is used after current expr; we cannot consume it.
132130
snippet = format!("&mut {snippet}");
133-
}
134131
}
135132
diag.span_suggestion(
136133
expr.span,

tests/ui/eta.fixed

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,16 @@ fn not_general_enough() {
303303
fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {}
304304
f(|path| std::fs::remove_file(path));
305305
}
306+
307+
// https://github.com/rust-lang/rust-clippy/issues/9369
308+
pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() {
309+
fn takes_fn_mut(_: impl FnMut()) {}
310+
takes_fn_mut(&mut f);
311+
312+
fn takes_fn_once(_: impl FnOnce()) {}
313+
takes_fn_once(&mut f);
314+
315+
f();
316+
317+
move || takes_fn_mut(&mut f_used_once)
318+
}

tests/ui/eta.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,3 +303,16 @@ fn not_general_enough() {
303303
fn f(_: impl FnMut(&Path) -> std::io::Result<()>) {}
304304
f(|path| std::fs::remove_file(path));
305305
}
306+
307+
// https://github.com/rust-lang/rust-clippy/issues/9369
308+
pub fn mutable_impl_fn_mut(mut f: impl FnMut(), mut f_used_once: impl FnMut()) -> impl FnMut() {
309+
fn takes_fn_mut(_: impl FnMut()) {}
310+
takes_fn_mut(|| f());
311+
312+
fn takes_fn_once(_: impl FnOnce()) {}
313+
takes_fn_once(|| f());
314+
315+
f();
316+
317+
move || takes_fn_mut(|| f_used_once())
318+
}

tests/ui/eta.stderr

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,5 +116,23 @@ error: redundant closure
116116
LL | Some(1).map(|n| in_loop(n));
117117
| ^^^^^^^^^^^^^^ help: replace the closure with the function itself: `in_loop`
118118

119-
error: aborting due to 19 previous errors
119+
error: redundant closure
120+
--> $DIR/eta.rs:310:18
121+
|
122+
LL | takes_fn_mut(|| f());
123+
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
124+
125+
error: redundant closure
126+
--> $DIR/eta.rs:313:19
127+
|
128+
LL | takes_fn_once(|| f());
129+
| ^^^^^^ help: replace the closure with the function itself: `&mut f`
130+
131+
error: redundant closure
132+
--> $DIR/eta.rs:317:26
133+
|
134+
LL | move || takes_fn_mut(|| f_used_once())
135+
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `&mut f_used_once`
136+
137+
error: aborting due to 22 previous errors
120138

0 commit comments

Comments
 (0)