Skip to content

Commit 2badfe8

Browse files
authored
Fix redundant_closure suggests wrongly with deref overload (#15077)
Closes #15072 changelog: [`redundant_closure`] fix wrong suggestions with deref overload
2 parents 1a7127c + 220249e commit 2badfe8

File tree

4 files changed

+130
-9
lines changed

4 files changed

+130
-9
lines changed

clippy_lints/src/eta_reduction.rs

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use rustc_hir::attrs::AttributeKind;
1212
use rustc_hir::{BindingMode, Expr, ExprKind, FnRetTy, GenericArgs, Param, PatKind, QPath, Safety, TyKind, find_attr};
1313
use rustc_infer::infer::TyCtxtInferExt;
1414
use rustc_lint::{LateContext, LateLintPass};
15+
use rustc_middle::ty::adjustment::Adjust;
1516
use rustc_middle::ty::{
1617
self, Binder, ClosureKind, FnSig, GenericArg, GenericArgKind, List, Region, Ty, TypeVisitableExt, TypeckResults,
1718
};
@@ -148,10 +149,9 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
148149
{
149150
return;
150151
}
151-
let callee_ty_adjusted = typeck
152-
.expr_adjustments(callee)
153-
.last()
154-
.map_or(callee_ty, |a| a.target.peel_refs());
152+
153+
let callee_ty_adjustments = typeck.expr_adjustments(callee);
154+
let callee_ty_adjusted = callee_ty_adjustments.last().map_or(callee_ty, |a| a.target);
155155

156156
let sig = match callee_ty_adjusted.kind() {
157157
ty::FnDef(def, _) => {
@@ -230,7 +230,20 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
230230
},
231231
_ => (),
232232
}
233+
} else if let n_refs =
234+
callee_ty_adjustments
235+
.iter()
236+
.rev()
237+
.fold(0, |acc, adjustment| match adjustment.kind {
238+
Adjust::Deref(Some(_)) => acc + 1,
239+
Adjust::Deref(_) if acc > 0 => acc + 1,
240+
_ => acc,
241+
})
242+
&& n_refs > 0
243+
{
244+
snippet = format!("{}{snippet}", "*".repeat(n_refs));
233245
}
246+
234247
let replace_with = match callee_ty_adjusted.kind() {
235248
ty::FnDef(def, _) => cx.tcx.def_descr(*def),
236249
_ => "function",

tests/ui/eta.fixed

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,51 @@ fn issue_14789() {
565565
);
566566
}
567567

568+
fn issue_15072() {
569+
use std::ops::Deref;
570+
571+
struct Foo;
572+
impl Deref for Foo {
573+
type Target = fn() -> &'static str;
574+
575+
fn deref(&self) -> &Self::Target {
576+
fn hello() -> &'static str {
577+
"Hello, world!"
578+
}
579+
&(hello as fn() -> &'static str)
580+
}
581+
}
582+
583+
fn accepts_fn(f: impl Fn() -> &'static str) {
584+
println!("{}", f());
585+
}
586+
587+
fn some_fn() -> &'static str {
588+
todo!()
589+
}
590+
591+
let f = &Foo;
592+
accepts_fn(**f);
593+
//~^ redundant_closure
594+
595+
let g = &some_fn;
596+
accepts_fn(g);
597+
//~^ redundant_closure
598+
599+
struct Bar(Foo);
600+
impl Deref for Bar {
601+
type Target = Foo;
602+
603+
fn deref(&self) -> &Self::Target {
604+
&self.0
605+
}
606+
}
607+
608+
let b = &Bar(Foo);
609+
accepts_fn(***b);
610+
//~^ redundant_closure
611+
}
612+
568613
fn issue8817() {
569614
fn f(_: u32) -> u32 {
570615
todo!()

tests/ui/eta.rs

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -565,6 +565,51 @@ fn issue_14789() {
565565
);
566566
}
567567

568+
fn issue_15072() {
569+
use std::ops::Deref;
570+
571+
struct Foo;
572+
impl Deref for Foo {
573+
type Target = fn() -> &'static str;
574+
575+
fn deref(&self) -> &Self::Target {
576+
fn hello() -> &'static str {
577+
"Hello, world!"
578+
}
579+
&(hello as fn() -> &'static str)
580+
}
581+
}
582+
583+
fn accepts_fn(f: impl Fn() -> &'static str) {
584+
println!("{}", f());
585+
}
586+
587+
fn some_fn() -> &'static str {
588+
todo!()
589+
}
590+
591+
let f = &Foo;
592+
accepts_fn(|| f());
593+
//~^ redundant_closure
594+
595+
let g = &some_fn;
596+
accepts_fn(|| g());
597+
//~^ redundant_closure
598+
599+
struct Bar(Foo);
600+
impl Deref for Bar {
601+
type Target = Foo;
602+
603+
fn deref(&self) -> &Self::Target {
604+
&self.0
605+
}
606+
}
607+
608+
let b = &Bar(Foo);
609+
accepts_fn(|| b());
610+
//~^ redundant_closure
611+
}
612+
568613
fn issue8817() {
569614
fn f(_: u32) -> u32 {
570615
todo!()

tests/ui/eta.stderr

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -215,28 +215,46 @@ LL | let _field = bind.or_else(|| get_default()).unwrap();
215215
| ^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `get_default`
216216

217217
error: redundant closure
218-
--> tests/ui/eta.rs:588:14
218+
--> tests/ui/eta.rs:592:16
219+
|
220+
LL | accepts_fn(|| f());
221+
| ^^^^^^ help: replace the closure with the function itself: `**f`
222+
223+
error: redundant closure
224+
--> tests/ui/eta.rs:596:16
225+
|
226+
LL | accepts_fn(|| g());
227+
| ^^^^^^ help: replace the closure with the function itself: `g`
228+
229+
error: redundant closure
230+
--> tests/ui/eta.rs:609:16
231+
|
232+
LL | accepts_fn(|| b());
233+
| ^^^^^^ help: replace the closure with the function itself: `***b`
234+
235+
error: redundant closure
236+
--> tests/ui/eta.rs:633:14
219237
|
220238
LL | .map(|n| MyError::A(n))
221239
| ^^^^^^^^^^^^^^^^^ help: replace the closure with the tuple variant itself: `MyError::A`
222240

223241
error: redundant closure
224-
--> tests/ui/eta.rs:585:14
242+
--> tests/ui/eta.rs:630:14
225243
|
226244
LL | .map(|n| S(n))
227245
| ^^^^^^^^ help: replace the closure with the tuple struct itself: `S`
228246

229247
error: redundant closure
230-
--> tests/ui/eta.rs:582:14
248+
--> tests/ui/eta.rs:627:14
231249
|
232250
LL | .map(|n| g(n))
233251
| ^^^^^^^^ help: replace the closure with the function itself: `g`
234252

235253
error: redundant closure
236-
--> tests/ui/eta.rs:579:14
254+
--> tests/ui/eta.rs:624:14
237255
|
238256
LL | .map(|n| f(n))
239257
| ^^^^^^^^ help: replace the closure with the function itself: `f`
240258

241-
error: aborting due to 39 previous errors
259+
error: aborting due to 42 previous errors
242260

0 commit comments

Comments
 (0)