Skip to content

Simply try to unpeel AsyncFnKindHelper goal in emit_specialized_closure_kind_error #140318

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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());
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -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() {}
Original file line number Diff line number Diff line change
@@ -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`.
Loading