Simply try to unpeel AsyncFnKindHelper goal in emit_specialized_closure_kind_error
This commit is contained in:
@@ -813,38 +813,17 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
obligation: &PredicateObligation<'tcx>,
|
obligation: &PredicateObligation<'tcx>,
|
||||||
mut trait_pred: ty::PolyTraitPredicate<'tcx>,
|
mut trait_pred: ty::PolyTraitPredicate<'tcx>,
|
||||||
) -> Option<ErrorGuaranteed> {
|
) -> Option<ErrorGuaranteed> {
|
||||||
// If `AsyncFnKindHelper` is not implemented, that means that the closure kind
|
// If we end up on an `AsyncFnKindHelper` goal, try to unwrap the parent
|
||||||
// doesn't extend the goal kind. This is worth reporting, but we can only do so
|
// `AsyncFn*` goal.
|
||||||
// if we actually know which closure this goal comes from, so look at the cause
|
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper) {
|
||||||
// to see if we can extract that information.
|
let mut code = obligation.cause.code();
|
||||||
if self.tcx.is_lang_item(trait_pred.def_id(), LangItem::AsyncFnKindHelper)
|
// Unwrap a `FunctionArg` cause, which has been refined from a derived obligation.
|
||||||
&& let Some(found_kind) =
|
if let ObligationCauseCode::FunctionArg { parent_code, .. } = code {
|
||||||
trait_pred.skip_binder().trait_ref.args.type_at(0).to_opt_closure_kind()
|
code = &**parent_code;
|
||||||
&& 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 have a derived obligation, then the parent will be a `AsyncFn*` goal.
|
||||||
|
if let Some((_, Some(parent))) = code.parent_with_predicate() {
|
||||||
trait_pred = parent;
|
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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {}
|
||||||
@@ -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`.
|
||||||
Reference in New Issue
Block a user