mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-06 04:08:40 +00:00
Improve error message for AsyncFn trait failure for RPIT
This commit is contained in:
parent
daf59857d6
commit
e213f4beea
@ -829,7 +829,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
&& let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
|
&& let ty::Closure(closure_def_id, _) | ty::CoroutineClosure(closure_def_id, _) =
|
||||||
*typeck_results.node_type(arg_hir_id).kind()
|
*typeck_results.node_type(arg_hir_id).kind()
|
||||||
{
|
{
|
||||||
// Otherwise, extract the closure kind from the obligation.
|
// 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(
|
let mut err = self.report_closure_error(
|
||||||
&obligation,
|
&obligation,
|
||||||
closure_def_id,
|
closure_def_id,
|
||||||
@ -844,63 +846,72 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
|
|
||||||
let self_ty = trait_pred.self_ty().skip_binder();
|
let self_ty = trait_pred.self_ty().skip_binder();
|
||||||
|
|
||||||
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
|
let (expected_kind, trait_prefix) =
|
||||||
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
|
if let Some(expected_kind) = self.tcx.fn_trait_kind_from_def_id(trait_pred.def_id()) {
|
||||||
ty::Closure(def_id, args) => {
|
(expected_kind, "")
|
||||||
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
|
} else if let Some(expected_kind) =
|
||||||
}
|
self.tcx.async_fn_trait_kind_from_def_id(trait_pred.def_id())
|
||||||
ty::CoroutineClosure(def_id, args) => (
|
{
|
||||||
def_id,
|
(expected_kind, "Async")
|
||||||
args.as_coroutine_closure()
|
} else {
|
||||||
.coroutine_closure_sig()
|
return None;
|
||||||
.map_bound(|sig| sig.tupled_inputs_ty),
|
|
||||||
Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
|
|
||||||
),
|
|
||||||
_ => return None,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let expected_args =
|
let (closure_def_id, found_args, by_ref_captures) = match *self_ty.kind() {
|
||||||
trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
|
ty::Closure(def_id, args) => {
|
||||||
|
(def_id, args.as_closure().sig().map_bound(|sig| sig.inputs()[0]), None)
|
||||||
// Verify that the arguments are compatible. If the signature is
|
|
||||||
// mismatched, then we have a totally different error to report.
|
|
||||||
if self.enter_forall(found_args, |found_args| {
|
|
||||||
self.enter_forall(expected_args, |expected_args| {
|
|
||||||
!self.can_eq(obligation.param_env, expected_args, found_args)
|
|
||||||
})
|
|
||||||
}) {
|
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
|
ty::CoroutineClosure(def_id, args) => (
|
||||||
|
def_id,
|
||||||
|
args.as_coroutine_closure()
|
||||||
|
.coroutine_closure_sig()
|
||||||
|
.map_bound(|sig| sig.tupled_inputs_ty),
|
||||||
|
Some(args.as_coroutine_closure().coroutine_captures_by_ref_ty()),
|
||||||
|
),
|
||||||
|
_ => return None,
|
||||||
|
};
|
||||||
|
|
||||||
if let Some(found_kind) = self.closure_kind(self_ty)
|
let expected_args = trait_pred.map_bound(|trait_pred| trait_pred.trait_ref.args.type_at(1));
|
||||||
&& !found_kind.extends(expected_kind)
|
|
||||||
{
|
|
||||||
let mut err = self.report_closure_error(
|
|
||||||
&obligation,
|
|
||||||
closure_def_id,
|
|
||||||
found_kind,
|
|
||||||
expected_kind,
|
|
||||||
"",
|
|
||||||
);
|
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
|
||||||
return Some(err.emit());
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the closure has captures, then perhaps the reason that the trait
|
// Verify that the arguments are compatible. If the signature is
|
||||||
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
|
// mismatched, then we have a totally different error to report.
|
||||||
// if they have captures.
|
if self.enter_forall(found_args, |found_args| {
|
||||||
if let Some(by_ref_captures) = by_ref_captures
|
self.enter_forall(expected_args, |expected_args| {
|
||||||
&& let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
|
!self.can_eq(obligation.param_env, expected_args, found_args)
|
||||||
&& !sig_tys.skip_binder().output().is_unit()
|
})
|
||||||
{
|
}) {
|
||||||
let mut err = self.dcx().create_err(AsyncClosureNotFn {
|
return None;
|
||||||
span: self.tcx.def_span(closure_def_id),
|
|
||||||
kind: expected_kind.as_str(),
|
|
||||||
});
|
|
||||||
self.note_obligation_cause(&mut err, &obligation);
|
|
||||||
return Some(err.emit());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(found_kind) = self.closure_kind(self_ty)
|
||||||
|
&& !found_kind.extends(expected_kind)
|
||||||
|
{
|
||||||
|
let mut err = self.report_closure_error(
|
||||||
|
&obligation,
|
||||||
|
closure_def_id,
|
||||||
|
found_kind,
|
||||||
|
expected_kind,
|
||||||
|
trait_prefix,
|
||||||
|
);
|
||||||
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
|
return Some(err.emit());
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the closure has captures, then perhaps the reason that the trait
|
||||||
|
// is unimplemented is because async closures don't implement `Fn`/`FnMut`
|
||||||
|
// if they have captures.
|
||||||
|
if let Some(by_ref_captures) = by_ref_captures
|
||||||
|
&& let ty::FnPtr(sig_tys, _) = by_ref_captures.kind()
|
||||||
|
&& !sig_tys.skip_binder().output().is_unit()
|
||||||
|
{
|
||||||
|
let mut err = self.dcx().create_err(AsyncClosureNotFn {
|
||||||
|
span: self.tcx.def_span(closure_def_id),
|
||||||
|
kind: expected_kind.as_str(),
|
||||||
|
});
|
||||||
|
self.note_obligation_cause(&mut err, &obligation);
|
||||||
|
return Some(err.emit());
|
||||||
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3191,7 +3191,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
|
|||||||
false
|
false
|
||||||
};
|
};
|
||||||
|
|
||||||
if !is_upvar_tys_infer_tuple {
|
let is_builtin_async_fn_trait =
|
||||||
|
tcx.async_fn_trait_kind_from_def_id(data.parent_trait_pred.def_id()).is_some();
|
||||||
|
|
||||||
|
if !is_upvar_tys_infer_tuple && !is_builtin_async_fn_trait {
|
||||||
let ty_str = tcx.short_string(ty, err.long_ty_path());
|
let ty_str = tcx.short_string(ty, err.long_ty_path());
|
||||||
let msg = format!("required because it appears within the type `{ty_str}`");
|
let msg = format!("required because it appears within the type `{ty_str}`");
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
|
@ -984,8 +984,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
|||||||
return Err(SelectionError::Unimplemented);
|
return Err(SelectionError::Unimplemented);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
nested.push(obligation.with(
|
nested.push(Obligation::new(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
|
obligation.derived_cause(ObligationCauseCode::BuiltinDerived),
|
||||||
|
obligation.param_env,
|
||||||
ty::TraitRef::new(
|
ty::TraitRef::new(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
self.tcx().require_lang_item(
|
self.tcx().require_lang_item(
|
||||||
|
14
tests/ui/async-await/async-closures/kind-due-to-rpit.rs
Normal file
14
tests/ui/async-await/async-closures/kind-due-to-rpit.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//@ edition: 2024
|
||||||
|
|
||||||
|
// Make sure the error message is understandable when an `AsyncFn` goal is not satisfied
|
||||||
|
// (due to closure kind), and that goal originates from an RPIT.
|
||||||
|
|
||||||
|
fn repro(foo: impl Into<bool>) -> impl AsyncFn() {
|
||||||
|
let inner_fn = async move || {
|
||||||
|
//~^ ERROR expected a closure that implements the `AsyncFn` trait
|
||||||
|
let _ = foo.into();
|
||||||
|
};
|
||||||
|
inner_fn
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
17
tests/ui/async-await/async-closures/kind-due-to-rpit.stderr
Normal file
17
tests/ui/async-await/async-closures/kind-due-to-rpit.stderr
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
error[E0525]: expected a closure that implements the `AsyncFn` trait, but this closure only implements `AsyncFnOnce`
|
||||||
|
--> $DIR/kind-due-to-rpit.rs:7:20
|
||||||
|
|
|
||||||
|
LL | fn repro(foo: impl Into<bool>) -> impl AsyncFn() {
|
||||||
|
| -------------- the requirement to implement `AsyncFn` derives from here
|
||||||
|
LL | let inner_fn = async move || {
|
||||||
|
| ^^^^^^^^^^^^^ this closure implements `AsyncFnOnce`, not `AsyncFn`
|
||||||
|
LL |
|
||||||
|
LL | let _ = foo.into();
|
||||||
|
| --- closure is `AsyncFnOnce` because it moves the variable `foo` out of its environment
|
||||||
|
LL | };
|
||||||
|
LL | inner_fn
|
||||||
|
| -------- return type was inferred to be `{async closure@$DIR/kind-due-to-rpit.rs:7:20: 7:33}` here
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0525`.
|
Loading…
Reference in New Issue
Block a user