Fix wrong suggestion for returning async closure
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 5a5d8af..03a46d7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1034,17 +1034,25 @@ pub(super) fn suggest_fn_call(
             && let ty::Tuple(inputs) = *sig.tupled_inputs_ty.kind()
             && inputs.is_empty()
             && self.tcx.is_lang_item(trait_pred.def_id(), LangItem::Future)
+            && let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
+            && let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(..), .. }) =
+                self.tcx.hir_node(*arg_hir_id)
             && let Some(hir::Node::Expr(hir::Expr {
-                kind:
-                    hir::ExprKind::Closure(hir::Closure {
-                        kind: hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async),
-                        fn_arg_span: Some(arg_span),
-                        ..
-                    }),
-                ..
+                kind: hir::ExprKind::Closure(closure), ..
             })) = self.tcx.hir_get_if_local(def_id)
-            && obligation.cause.span.contains(*arg_span)
+            && let hir::ClosureKind::CoroutineClosure(CoroutineDesugaring::Async) = closure.kind
+            && let Some(arg_span) = closure.fn_arg_span
+            && obligation.cause.span.contains(arg_span)
         {
+            let mut body = self.tcx.hir_body(closure.body).value;
+            let peeled = body.peel_blocks().peel_drop_temps();
+            if let hir::ExprKind::Closure(inner) = peeled.kind {
+                body = self.tcx.hir_body(inner.body).value;
+            }
+            if !matches!(body.peel_blocks().peel_drop_temps().kind, hir::ExprKind::Block(..)) {
+                return false;
+            }
+
             let sm = self.tcx.sess.source_map();
             let removal_span = if let Ok(snippet) =
                 sm.span_to_snippet(arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1)))
@@ -1053,7 +1061,7 @@ pub(super) fn suggest_fn_call(
                 // There's a space after `||`, include it in the removal
                 arg_span.with_hi(arg_span.hi() + rustc_span::BytePos(1))
             } else {
-                *arg_span
+                arg_span
             };
             err.span_suggestion_verbose(
                 removal_span,
@@ -1093,23 +1101,63 @@ pub(super) fn suggest_fn_call(
             .collect::<Vec<_>>()
             .join(", ");
 
-        if matches!(obligation.cause.code(), ObligationCauseCode::FunctionArg { .. })
+        if let ObligationCauseCode::FunctionArg { arg_hir_id, .. } = obligation.cause.code()
             && obligation.cause.span.can_be_used_for_suggestions()
         {
-            let (span, sugg) = if let Some(snippet) =
-                self.tcx.sess.source_map().span_to_snippet(obligation.cause.span).ok()
-                && snippet.starts_with("|")
-            {
-                (obligation.cause.span, format!("({snippet})({args})"))
-            } else {
-                (obligation.cause.span.shrink_to_hi(), format!("({args})"))
+            let span = obligation.cause.span;
+
+            let arg_expr = match self.tcx.hir_node(*arg_hir_id) {
+                hir::Node::Expr(expr) => Some(expr),
+                _ => None,
             };
 
-            // When the obligation error has been ensured to have been caused by
-            // an argument, the `obligation.cause.span` points at the expression
-            // of the argument, so we can provide a suggestion. Otherwise, we give
-            // a more general note.
-            err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
+            let is_closure_expr =
+                arg_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Closure(..)));
+
+            // If the user wrote `|| {}()`, suggesting to call the closure would produce `(|| {}())()`,
+            // which doesn't help and is often outright wrong.
+            if args.is_empty()
+                && let Some(expr) = arg_expr
+                && let hir::ExprKind::Closure(closure) = expr.kind
+            {
+                let mut body = self.tcx.hir_body(closure.body).value;
+
+                // Async closures desugar to a closure returning a coroutine
+                if let hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) =
+                    closure.kind
+                {
+                    let peeled = body.peel_blocks().peel_drop_temps();
+                    if let hir::ExprKind::Closure(inner) = peeled.kind {
+                        body = self.tcx.hir_body(inner.body).value;
+                    }
+                }
+
+                let peeled_body = body.peel_blocks().peel_drop_temps();
+                if let hir::ExprKind::Call(callee, call_args) = peeled_body.kind
+                    && call_args.is_empty()
+                    && let hir::ExprKind::Block(..) = callee.peel_blocks().peel_drop_temps().kind
+                {
+                    return false;
+                }
+            }
+
+            if is_closure_expr {
+                err.multipart_suggestions(
+                    msg,
+                    vec![vec![
+                        (span.shrink_to_lo(), "(".to_string()),
+                        (span.shrink_to_hi(), format!(")({args})")),
+                    ]],
+                    Applicability::HasPlaceholders,
+                );
+            } else {
+                err.span_suggestion_verbose(
+                    span.shrink_to_hi(),
+                    msg,
+                    format!("({args})"),
+                    Applicability::HasPlaceholders,
+                );
+            }
         } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
             let name = match self.tcx.hir_get_if_local(def_id) {
                 Some(hir::Node::Expr(hir::Expr {
diff --git a/tests/ui/async-await/async-closures/suggest-async-block-issue-140265.stderr b/tests/ui/async-await/async-closures/suggest-async-block-issue-140265.stderr
index d81cfaa..8e9e8ce 100644
--- a/tests/ui/async-await/async-closures/suggest-async-block-issue-140265.stderr
+++ b/tests/ui/async-await/async-closures/suggest-async-block-issue-140265.stderr
@@ -66,8 +66,11 @@
    |                            ^^^^^^^^^^^^^^^^^^^ required by this bound in `takes_future`
 help: use parentheses to call this closure
    |
-LL |     }(/* i32 */));
-   |      +++++++++++
+LL ~     takes_future((async |x: i32| {
+LL |
+LL |         println!("{x}");
+LL ~     })(/* i32 */));
+   |
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
index be63c9e..0237e7b 100644
--- a/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
+++ b/tests/ui/const-generics/adt_const_params/const_param_ty_bad.stderr
@@ -32,9 +32,8 @@
    |                  ^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `check`
 help: use parentheses to call this closure
    |
-LL -     check(|| {});
-LL +     check((|| {})());
-   |
+LL |     check((|| {})());
+   |           +     +++
 
 error[E0277]: `fn()` can't be used as a const parameter type
   --> $DIR/const_param_ty_bad.rs:9:11
diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed b/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed
new file mode 100644
index 0000000..f3e226c
--- /dev/null
+++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed
@@ -0,0 +1,15 @@
+// Regression test for #150701
+
+//@ run-rustfix
+//@ edition: 2024
+
+use std::future::Future;
+
+fn f(_c: impl Future<Output = ()>) {}
+
+fn main() {
+    f((async || {})()); //~ ERROR: expected function, found `()`
+    //~^ ERROR: is not a future
+    f(async {});
+    //~^ ERROR: is not a future
+}
diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.rs b/tests/ui/suggestions/suggest-create-closure-issue-150701.rs
new file mode 100644
index 0000000..e7a5076
--- /dev/null
+++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.rs
@@ -0,0 +1,15 @@
+// Regression test for #150701
+
+//@ run-rustfix
+//@ edition: 2024
+
+use std::future::Future;
+
+fn f(_c: impl Future<Output = ()>) {}
+
+fn main() {
+    f(async || {}()); //~ ERROR: expected function, found `()`
+    //~^ ERROR: is not a future
+    f(async || {});
+    //~^ ERROR: is not a future
+}
diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr b/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr
new file mode 100644
index 0000000..0f99116
--- /dev/null
+++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr
@@ -0,0 +1,52 @@
+error[E0618]: expected function, found `()`
+  --> $DIR/suggest-create-closure-issue-150701.rs:11:16
+   |
+LL |     f(async || {}());
+   |                ^^--
+   |                |
+   |                call expression requires function
+   |
+help: if you meant to create this closure and immediately call it, surround the closure with parentheses
+   |
+LL |     f((async || {})());
+   |       +           +
+
+error[E0277]: `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}` is not a future
+  --> $DIR/suggest-create-closure-issue-150701.rs:11:7
+   |
+LL |     f(async || {}());
+   |     - ^^^^^^^^^^^^^ `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}` is not a future
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Future` is not implemented for `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}`
+note: required by a bound in `f`
+  --> $DIR/suggest-create-closure-issue-150701.rs:8:15
+   |
+LL | fn f(_c: impl Future<Output = ()>) {}
+   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `f`
+
+error[E0277]: `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}` is not a future
+  --> $DIR/suggest-create-closure-issue-150701.rs:13:7
+   |
+LL |     f(async || {});
+   |     - ^^^^^^^^^^^ `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}` is not a future
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Future` is not implemented for `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}`
+note: required by a bound in `f`
+  --> $DIR/suggest-create-closure-issue-150701.rs:8:15
+   |
+LL | fn f(_c: impl Future<Output = ()>) {}
+   |               ^^^^^^^^^^^^^^^^^^^ required by this bound in `f`
+help: use `async {}` instead of `async || {}` to introduce an async block
+   |
+LL -     f(async || {});
+LL +     f(async {});
+   |
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0618.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr
index cb6df5a..e32b2d4 100644
--- a/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr
+++ b/tests/ui/suggestions/use-parentheses-to-call-closure-issue-145404.stderr
@@ -14,9 +14,8 @@
    |                            ^^^^^^^ required by this bound in `S::call`
 help: use parentheses to call this closure
    |
-LL -     S.call(|| "hello");
-LL +     S.call((|| "hello")());
-   |
+LL |     S.call((|| "hello")());
+   |            +          +++
 
 error: aborting due to 1 previous error