Teach typeck/borrowck/solvers how to deal with async closures
This commit is contained in:
@@ -117,9 +117,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
self.assemble_iterator_candidates(obligation, &mut candidates);
|
||||
} else if lang_items.async_iterator_trait() == Some(def_id) {
|
||||
self.assemble_async_iterator_candidates(obligation, &mut candidates);
|
||||
} else if lang_items.async_fn_kind_helper() == Some(def_id) {
|
||||
self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
|
||||
}
|
||||
|
||||
self.assemble_closure_candidates(obligation, &mut candidates);
|
||||
self.assemble_async_closure_candidates(obligation, &mut candidates);
|
||||
self.assemble_fn_pointer_candidates(obligation, &mut candidates);
|
||||
self.assemble_candidates_from_impls(obligation, &mut candidates);
|
||||
self.assemble_candidates_from_object_ty(obligation, &mut candidates);
|
||||
@@ -335,6 +338,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_async_closure_candidates(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
let Some(goal_kind) =
|
||||
self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id())
|
||||
else {
|
||||
return;
|
||||
};
|
||||
|
||||
match *obligation.self_ty().skip_binder().kind() {
|
||||
ty::CoroutineClosure(_, args) => {
|
||||
if let Some(closure_kind) =
|
||||
args.as_coroutine_closure().kind_ty().to_opt_closure_kind()
|
||||
&& !closure_kind.extends(goal_kind)
|
||||
{
|
||||
return;
|
||||
}
|
||||
candidates.vec.push(AsyncClosureCandidate);
|
||||
}
|
||||
ty::Infer(ty::TyVar(_)) => {
|
||||
candidates.ambiguous = true;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn assemble_async_fn_kind_helper_candidates(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
candidates: &mut SelectionCandidateSet<'tcx>,
|
||||
) {
|
||||
if let Some(closure_kind) = obligation.self_ty().skip_binder().to_opt_closure_kind()
|
||||
&& let Some(goal_kind) =
|
||||
obligation.predicate.skip_binder().trait_ref.args.type_at(1).to_opt_closure_kind()
|
||||
{
|
||||
if closure_kind.extends(goal_kind) {
|
||||
candidates.vec.push(AsyncFnKindHelperCandidate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements one of the `Fn()` family for a fn pointer.
|
||||
fn assemble_fn_pointer_candidates(
|
||||
&mut self,
|
||||
|
||||
@@ -83,6 +83,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
|
||||
}
|
||||
|
||||
AsyncClosureCandidate => {
|
||||
let vtable_closure = self.confirm_async_closure_candidate(obligation)?;
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
|
||||
}
|
||||
|
||||
AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]),
|
||||
|
||||
CoroutineCandidate => {
|
||||
let vtable_coroutine = self.confirm_coroutine_candidate(obligation)?;
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_coroutine)
|
||||
@@ -869,6 +876,49 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
#[instrument(skip(self), level = "debug")]
|
||||
fn confirm_async_closure_candidate(
|
||||
&mut self,
|
||||
obligation: &PolyTraitObligation<'tcx>,
|
||||
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
|
||||
// Okay to skip binder because the args on closure types never
|
||||
// touch bound regions, they just capture the in-scope
|
||||
// type/region parameters.
|
||||
let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder());
|
||||
let ty::CoroutineClosure(closure_def_id, args) = *self_ty.kind() else {
|
||||
bug!("async closure candidate for non-coroutine-closure {:?}", obligation);
|
||||
};
|
||||
|
||||
let trait_ref = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
|
||||
ty::TraitRef::new(
|
||||
self.tcx(),
|
||||
obligation.predicate.def_id(),
|
||||
[self_ty, sig.tupled_inputs_ty],
|
||||
)
|
||||
});
|
||||
|
||||
let mut nested = self.confirm_poly_trait_refs(obligation, trait_ref)?;
|
||||
|
||||
let goal_kind =
|
||||
self.tcx().async_fn_trait_kind_from_def_id(obligation.predicate.def_id()).unwrap();
|
||||
nested.push(obligation.with(
|
||||
self.tcx(),
|
||||
ty::TraitRef::from_lang_item(
|
||||
self.tcx(),
|
||||
LangItem::AsyncFnKindHelper,
|
||||
obligation.cause.span,
|
||||
[
|
||||
args.as_coroutine_closure().kind_ty(),
|
||||
Ty::from_closure_kind(self.tcx(), goal_kind),
|
||||
],
|
||||
),
|
||||
));
|
||||
|
||||
debug!(?closure_def_id, ?trait_ref, ?nested, "confirm closure candidate obligations");
|
||||
|
||||
Ok(nested)
|
||||
}
|
||||
|
||||
/// In the case of closure types and fn pointers,
|
||||
/// we currently treat the input type parameters on the trait as
|
||||
/// outputs. This means that when we have a match we have only
|
||||
|
||||
@@ -1864,6 +1864,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
ImplCandidate(..)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
@@ -1894,6 +1896,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
ImplCandidate(_)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
@@ -1930,6 +1934,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
ImplCandidate(..)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
@@ -1946,6 +1952,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
ImplCandidate(..)
|
||||
| AutoImplCandidate
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
@@ -2054,6 +2062,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
(
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
@@ -2066,6 +2076,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
|
||||
| TraitAliasCandidate,
|
||||
ImplCandidate(_)
|
||||
| ClosureCandidate { .. }
|
||||
| AsyncClosureCandidate
|
||||
| AsyncFnKindHelperCandidate
|
||||
| CoroutineCandidate
|
||||
| FutureCandidate
|
||||
| IteratorCandidate
|
||||
|
||||
Reference in New Issue
Block a user