about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAda Alakbarova <ada.alakbarova@proton.me>2025-09-10 09:35:45 +0200
committerAda Alakbarova <ada.alakbarova@proton.me>2025-09-10 10:25:39 +0200
commite4f69ea1af40cd43da1aec1d6489ac6e78d3e769 (patch)
treee2043edbc72428e82f5d748eb6abfe123d8873ad
parent49e2f37b26fbfa1de818cfaacda57b7375165bf5 (diff)
downloadrust-e4f69ea1af40cd43da1aec1d6489ac6e78d3e769.tar.gz
rust-e4f69ea1af40cd43da1aec1d6489ac6e78d3e769.zip
fix(needless_closure): don't lint on `AsyncFn*`s
-rw-r--r--clippy_lints/src/eta_reduction.rs27
-rw-r--r--tests/ui/eta.fixed8
-rw-r--r--tests/ui/eta.rs8
3 files changed, 31 insertions, 12 deletions
diff --git a/clippy_lints/src/eta_reduction.rs b/clippy_lints/src/eta_reduction.rs
index 2da1c2bad11..752f39b4e6d 100644
--- a/clippy_lints/src/eta_reduction.rs
+++ b/clippy_lints/src/eta_reduction.rs
@@ -197,6 +197,18 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                 // in a type which is `'static`.
                 // For now ignore all callee types which reference a type parameter.
                 && !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
+                // Rule out `AsyncFn*`s, because while they can be called as `|x| f(x)`,
+                // they can't be passed directly into a place expecting an `Fn*` (#13892)
+                && let Ok((closure_kind, _)) = cx
+                    .tcx
+                    .infer_ctxt()
+                    .build(cx.typing_mode())
+                    .err_ctxt()
+                    .type_implements_fn_trait(
+                        cx.param_env,
+                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+                        ty::PredicatePolarity::Positive,
+                    )
             {
                 span_lint_hir_and_then(
                     cx,
@@ -213,19 +225,10 @@ fn check_closure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tcx
                                 // 'cuz currently nothing changes after deleting this check.
                                 local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
                             }) {
-                                match cx
-                                    .tcx
-                                    .infer_ctxt()
-                                    .build(cx.typing_mode())
-                                    .err_ctxt()
-                                    .type_implements_fn_trait(
-                                        cx.param_env,
-                                        Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
-                                        ty::PredicatePolarity::Positive,
-                                    ) {
+                                match closure_kind {
                                     // Mutable closure is used after current expr; we cannot consume it.
-                                    Ok((ClosureKind::FnMut, _)) => snippet = format!("&mut {snippet}"),
-                                    Ok((ClosureKind::Fn, _)) if !callee_ty_raw.is_ref() => {
+                                    ClosureKind::FnMut => snippet = format!("&mut {snippet}"),
+                                    ClosureKind::Fn if !callee_ty_raw.is_ref() => {
                                         snippet = format!("&{snippet}");
                                     },
                                     _ => (),
diff --git a/tests/ui/eta.fixed b/tests/ui/eta.fixed
index 6944a979c05..107318e5323 100644
--- a/tests/ui/eta.fixed
+++ b/tests/ui/eta.fixed
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}
diff --git a/tests/ui/eta.rs b/tests/ui/eta.rs
index 5bcc1cb26fd..b85e8e75153 100644
--- a/tests/ui/eta.rs
+++ b/tests/ui/eta.rs
@@ -635,3 +635,11 @@ fn issue8817() {
         //~| HELP: replace the closure with the tuple variant itself
         .unwrap(); // just for nicer formatting
 }
+
+async fn issue13892<'a, T, F>(maybe: Option<&'a T>, visitor: F)
+where
+    F: AsyncFn(&'a T),
+    T: 'a,
+{
+    maybe.map(|x| visitor(x));
+}