Skip to content

Commit 443358d

Browse files
authored
Rollup merge of #140318 - compiler-errors:specialized-async-fn-kind-err, r=fee1-dead
Simply try to unpeel AsyncFnKindHelper goal in `emit_specialized_closure_kind_error` Tweak the handling of `AsyncFnKindHelper` goals in `emit_specialized_closure_kind_error` to not be so special-casey, and just try to unpeel one or two layers of obligation causes to get to their underlying `AsyncFn*` goal. Fixes #140292
2 parents fbf6832 + 4b309c6 commit 443358d

File tree

3 files changed

+53
-31
lines changed

3 files changed

+53
-31
lines changed

compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs

+10-31
Original file line numberDiff line numberDiff line change
@@ -813,38 +813,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
813813
obligation: &PredicateObligation<'tcx>,
814814
mut trait_pred: ty::PolyTraitPredicate<'tcx>,
815815
) -> Option<ErrorGuaranteed> {
816-
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
817-
// doesn't extend the goal kind. This is worth reporting, but we can only do so
818-
// if we actually know which closure this goal comes from, so look at the cause
819-
// to see if we can extract that information.
820-
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
821-
&& let Some(found_kind) =
822-
trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
823-
&& let Some(expected_kind) =
824-
trait_pred.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
825-
&& !found_kind.extends(expected_kind)
826-
{
827-
if let Some((_, Some(parent))) = obligation.cause.code().parent_with_predicate() {
828-
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
816+
// If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent
817+
// `AsyncFn*` goal.
818+
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {
819+
let mut code = obligation.cause.code();
820+
// Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.
821+
if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {
822+
code = &**parent_code;
823+
}
824+
// If we have a derived obligation, then the parent will be a `AsyncFn*` goal.
825+
if let Some((_, Some(parent))) = code.parent_with_predicate() {
829826
trait_pred = parent;
830-
} else if let &ObligationCauseCode::FunctionArg { arg_hir_id, .. } =
831-
obligation.cause.code()
832-
&& let Some(typeck_results) = &self.typeck_results
833-
&& let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
834-
*typeck_results.node_type(arg_hir_id).kind()
835-
{
836-
// Otherwise, extract the closure kind from the obligation,
837-
// but only if we actually have an argument to deduce the
838-
// closure type from...
839-
let mut err = self.report_closure_error(
840-
&obligation,
841-
closure_def_id,
842-
found_kind,
843-
expected_kind,
844-
"Async",
845-
);
846-
self.note_obligation_cause(&mut err, &obligation);
847-
return Some(err.emit());
848827
}
849828
}
850829

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
//@ edition: 2024
2+
3+
// Regression test for <https://github.com/rust-lang/rust/issues/140292>.
4+
5+
struct Test;
6+
7+
impl Test {
8+
async fn an_async_fn(&mut self) {
9+
todo!()
10+
}
11+
12+
pub async fn uses_takes_asyncfn(&mut self) {
13+
takes_asyncfn(Box::new(async || self.an_async_fn().await));
14+
//~^ ERROR expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
15+
}
16+
}
17+
18+
async fn takes_asyncfn(_: impl AsyncFn()) {
19+
todo!()
20+
}
21+
22+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
error[E0525]: expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnMut`
2+
--> $DIR/kind-due-to-arg-with-box-wrap.rs:13:32
3+
|
4+
LL | takes_asyncfn(Box::new(async || self.an_async_fn().await));
5+
| ------------- ---------^^^^^^^^--------------------------
6+
| | | | |
7+
| | | | closure is `AsyncFnMut` because it mutates the variable `*self` here
8+
| | | this closure implements `AsyncFnMut`, not `AsyncFn`
9+
| | the requirement to implement `AsyncFn` derives from here
10+
| required by a bound introduced by this call
11+
|
12+
= note: required for `Box<{async closure@$DIR/kind-due-to-arg-with-box-wrap.rs:13:32: 13:40}>` to implement `AsyncFn()`
13+
note: required by a bound in `takes_asyncfn`
14+
--> $DIR/kind-due-to-arg-with-box-wrap.rs:18:32
15+
|
16+
LL | async fn takes_asyncfn(_: impl AsyncFn()) {
17+
| ^^^^^^^^^ required by this bound in `takes_asyncfn`
18+
19+
error: aborting due to 1 previous error
20+
21+
For more information about this error, try `rustc --explain E0525`.

0 commit comments

Comments
 (0)