about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-04-26 01:42:48 +0000
committerMichael Goulet <michael@errs.io>2025-04-26 01:42:52 +0000
commit4b309c67c6fc3c5d6ff51a417af453380348c2eb (patch)
treed045818d3824e1cc2aab6a4f400afd8f902a88d0
parentbe181dd75c83d72fcc95538e235768bc367b76b9 (diff)
downloadrust-4b309c67c6fc3c5d6ff51a417af453380348c2eb.tar.gz
rust-4b309c67c6fc3c5d6ff51a417af453380348c2eb.zip
Simply try to unpeel AsyncFnKindHelper goal in emit_specialized_closure_kind_error
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs41
-rw-r--r--tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs22
-rw-r--r--tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr21
3 files changed, 53 insertions, 31 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 5648021f613..4c407cd7133 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -813,38 +813,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         mut trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> Option<ErrorGuaranteed> {
-        // If `AsyncFnKindHelper` is not implemented, that means that the closure kind
-        // doesn't extend the goal kind. This is worth reporting, but we can only do so
-        // if we actually know which closure this goal comes from, so look at the cause
-        // to see if we can extract that information.
-        if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
-            && let Some(found_kind) =
-                trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
-            && let Some(expected_kind) =
-                trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
-            && !found_kind.extends(expected_kind)
-        {
-            if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
-                // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
+        // If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent
+        // `AsyncFn*` goal.
+        if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {
+            let mut code = obligation.cause.code();
+            // Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.
+            if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {
+                code = &**parent_code;
+            }
+            // If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
+            if let Some((_, Some(parent))) = code.parent_with_predicate() {
                 trait_pred = parent;
-            } else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
-                obligation.cause.code()
-                && let Some(typeck_results) = &self.typeck_results
-                && let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
-                    *typeck_results.node_type(arg_hir_id).kind()
-            {
-                // Otherwise, extract the closure kind from the obligation,
-                // but only if we actually have an argument to deduce the
-                // closure type from...
-                let mut err = self.report_closure_error(
-                    &obligation,
-                    closure_def_id,
-                    found_kind,
-                    expected_kind,
-                    "Async",
-                );
-                self.note_obligation_cause(&mut err, &obligation);
-                return Some(err.emit());
             }
         }
 
diff --git a/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs
new file mode 100644
index 00000000000..650fb10d94b
--- /dev/null
+++ b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.rs
@@ -0,0 +1,22 @@
+//@ edition: 2024
+
+// Regression test for <https://github.com/rust-lang/rust/issues/140292>.
+
+struct Test;
+
+impl Test {
+    async fn an_async_fn(&mut self) {
+        todo!()
+    }
+
+    pub async fn uses_takes_asyncfn(&mut self) {
+        takes_asyncfn(Box::new(async || self.an_async_fn().await));
+        //~^ ERROR expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
+    }
+}
+
+async fn takes_asyncfn(_: impl AsyncFn()) {
+    todo!()
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr
new file mode 100644
index 00000000000..e79f95c197b
--- /dev/null
+++ b/tests/ui/async-await/async-closures/kind-due-to-arg-with-box-wrap.stderr
@@ -0,0 +1,21 @@
+error[E0525]: expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
+  --> $DIR/kind-due-to-arg-with-box-wrap.rs:13:32
+   |
+LL |         takes_asyncfn(Box::new(async || self.an_async_fn().await));
+   |         ------------- ---------^^^^^^^^--------------------------
+   |         |             |        |        |
+   |         |             |        |        closure is `AsyncFnMut` because it mutates the variable `*self` here
+   |         |             |        this closure implements `AsyncFnMut`, not `AsyncFn`
+   |         |             the requirement to implement `AsyncFn` derives from here
+   |         required by a bound introduced by this call
+   |
+   = note: required for `Box<{async closure@$DIR/kind-due-to-arg-with-box-wrap.rs:13:32: 13:40}>` to implement `AsyncFn()`
+note: required by a bound in `takes_asyncfn`
+  --> $DIR/kind-due-to-arg-with-box-wrap.rs:18:32
+   |
+LL | async fn takes_asyncfn(_: impl AsyncFn()) {
+   |                                ^^^^^^^^^ required by this bound in `takes_asyncfn`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0525`.