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 https://github.com/rust-lang/rust/issues/140292
This commit is contained in:
Matthias Krüger
2025-04-26 16:12:33 +02:00
committed by GitHub
3 changed files with 53 additions and 31 deletions

View File

@@ -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());
}
}