Regular closures now built-in impls for AsyncFn*
This commit is contained in:
parent
0dd40786b5
commit
08af64e96b
7 changed files with 318 additions and 114 deletions
|
@ -2450,14 +2450,6 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
|
|||
) -> Progress<'tcx> {
|
||||
let tcx = selcx.tcx();
|
||||
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||
let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else {
|
||||
unreachable!(
|
||||
"expected coroutine-closure self type for coroutine-closure candidate, found {self_ty}"
|
||||
)
|
||||
};
|
||||
let args = args.as_coroutine_closure();
|
||||
let kind_ty = args.kind_ty();
|
||||
let sig = args.coroutine_closure_sig().skip_binder();
|
||||
|
||||
let goal_kind =
|
||||
tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
|
||||
|
@ -2465,84 +2457,163 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
|
|||
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
|
||||
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
|
||||
};
|
||||
|
||||
let item_name = tcx.item_name(obligation.predicate.def_id);
|
||||
let term = match item_name {
|
||||
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => {
|
||||
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
||||
if !closure_kind.extends(goal_kind) {
|
||||
bug!("we should not be confirming if the closure kind is not met");
|
||||
|
||||
let poly_cache_entry = match *self_ty.kind() {
|
||||
ty::CoroutineClosure(def_id, args) => {
|
||||
let args = args.as_coroutine_closure();
|
||||
let kind_ty = args.kind_ty();
|
||||
let sig = args.coroutine_closure_sig().skip_binder();
|
||||
|
||||
let term = match item_name {
|
||||
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => {
|
||||
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
||||
if !closure_kind.extends(goal_kind) {
|
||||
bug!("we should not be confirming if the closure kind is not met");
|
||||
}
|
||||
sig.to_coroutine_given_kind_and_upvars(
|
||||
tcx,
|
||||
args.parent_args(),
|
||||
tcx.coroutine_for_closure(def_id),
|
||||
goal_kind,
|
||||
env_region,
|
||||
args.tupled_upvars_ty(),
|
||||
args.coroutine_captures_by_ref_ty(),
|
||||
)
|
||||
} else {
|
||||
let async_fn_kind_trait_def_id =
|
||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||
let upvars_projection_def_id = tcx
|
||||
.associated_items(async_fn_kind_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Upvars)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
// When we don't know the closure kind (and therefore also the closure's upvars,
|
||||
// which are computed at the same time), we must delay the computation of the
|
||||
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
||||
// goal functions similarly to the old `ClosureKind` predicate, and ensures that
|
||||
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
||||
// will project to the right upvars for the generator, appending the inputs and
|
||||
// coroutine upvars respecting the closure kind.
|
||||
// N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`.
|
||||
let tupled_upvars_ty = Ty::new_projection(
|
||||
tcx,
|
||||
upvars_projection_def_id,
|
||||
[
|
||||
ty::GenericArg::from(kind_ty),
|
||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
||||
env_region.into(),
|
||||
sig.tupled_inputs_ty.into(),
|
||||
args.tupled_upvars_ty().into(),
|
||||
args.coroutine_captures_by_ref_ty().into(),
|
||||
],
|
||||
);
|
||||
sig.to_coroutine(
|
||||
tcx,
|
||||
args.parent_args(),
|
||||
Ty::from_closure_kind(tcx, goal_kind),
|
||||
tcx.coroutine_for_closure(def_id),
|
||||
tupled_upvars_ty,
|
||||
)
|
||||
}
|
||||
}
|
||||
sig.to_coroutine_given_kind_and_upvars(
|
||||
sym::Output => sig.return_ty,
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
let projection_ty = match item_name {
|
||||
sym::CallOnceFuture | sym::Output => ty::AliasTy::new(
|
||||
tcx,
|
||||
args.parent_args(),
|
||||
tcx.coroutine_for_closure(def_id),
|
||||
goal_kind,
|
||||
env_region,
|
||||
args.tupled_upvars_ty(),
|
||||
args.coroutine_captures_by_ref_ty(),
|
||||
)
|
||||
} else {
|
||||
let async_fn_kind_trait_def_id =
|
||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||
let upvars_projection_def_id = tcx
|
||||
.associated_items(async_fn_kind_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Upvars)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
// When we don't know the closure kind (and therefore also the closure's upvars,
|
||||
// which are computed at the same time), we must delay the computation of the
|
||||
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
|
||||
// goal functions similarly to the old `ClosureKind` predicate, and ensures that
|
||||
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
||||
// will project to the right upvars for the generator, appending the inputs and
|
||||
// coroutine upvars respecting the closure kind.
|
||||
// N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`.
|
||||
let tupled_upvars_ty = Ty::new_projection(
|
||||
obligation.predicate.def_id,
|
||||
[self_ty, sig.tupled_inputs_ty],
|
||||
),
|
||||
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
|
||||
tcx,
|
||||
upvars_projection_def_id,
|
||||
obligation.predicate.def_id,
|
||||
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
|
||||
),
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
|
||||
args.coroutine_closure_sig()
|
||||
.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
|
||||
}
|
||||
ty::FnDef(..) | ty::FnPtr(..) => {
|
||||
let bound_sig = self_ty.fn_sig(tcx);
|
||||
let sig = bound_sig.skip_binder();
|
||||
|
||||
let term = match item_name {
|
||||
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(),
|
||||
sym::Output => {
|
||||
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
||||
let future_output_def_id = tcx
|
||||
.associated_items(future_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Output)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
Ty::new_projection(tcx, future_output_def_id, [sig.output()])
|
||||
}
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
let projection_ty = match item_name {
|
||||
sym::CallOnceFuture | sym::Output => ty::AliasTy::new(
|
||||
tcx,
|
||||
obligation.predicate.def_id,
|
||||
[self_ty, Ty::new_tup(tcx, sig.inputs())],
|
||||
),
|
||||
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
|
||||
tcx,
|
||||
obligation.predicate.def_id,
|
||||
[
|
||||
ty::GenericArg::from(kind_ty),
|
||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
||||
ty::GenericArg::from(self_ty),
|
||||
Ty::new_tup(tcx, sig.inputs()).into(),
|
||||
env_region.into(),
|
||||
sig.tupled_inputs_ty.into(),
|
||||
args.tupled_upvars_ty().into(),
|
||||
args.coroutine_captures_by_ref_ty().into(),
|
||||
],
|
||||
);
|
||||
sig.to_coroutine(
|
||||
),
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
|
||||
bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
|
||||
}
|
||||
ty::Closure(_, args) => {
|
||||
let args = args.as_closure();
|
||||
let bound_sig = args.sig();
|
||||
let sig = bound_sig.skip_binder();
|
||||
|
||||
let term = match item_name {
|
||||
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(),
|
||||
sym::Output => {
|
||||
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
|
||||
let future_output_def_id = tcx
|
||||
.associated_items(future_trait_def_id)
|
||||
.filter_by_name_unhygienic(sym::Output)
|
||||
.next()
|
||||
.unwrap()
|
||||
.def_id;
|
||||
Ty::new_projection(tcx, future_output_def_id, [sig.output()])
|
||||
}
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
let projection_ty = match item_name {
|
||||
sym::CallOnceFuture | sym::Output => {
|
||||
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]])
|
||||
}
|
||||
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
|
||||
tcx,
|
||||
args.parent_args(),
|
||||
Ty::from_closure_kind(tcx, goal_kind),
|
||||
tcx.coroutine_for_closure(def_id),
|
||||
tupled_upvars_ty,
|
||||
)
|
||||
}
|
||||
obligation.predicate.def_id,
|
||||
[ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()],
|
||||
),
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
|
||||
bound_sig.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() })
|
||||
}
|
||||
sym::Output => sig.return_ty,
|
||||
name => bug!("no such associated type: {name}"),
|
||||
};
|
||||
let projection_ty = match item_name {
|
||||
sym::CallOnceFuture | sym::Output => {
|
||||
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty])
|
||||
}
|
||||
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
|
||||
tcx,
|
||||
obligation.predicate.def_id,
|
||||
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
|
||||
),
|
||||
name => bug!("no such associated type: {name}"),
|
||||
_ => bug!("expected callable type for AsyncFn candidate"),
|
||||
};
|
||||
|
||||
confirm_param_env_candidate(
|
||||
selcx,
|
||||
obligation,
|
||||
args.coroutine_closure_sig()
|
||||
.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }),
|
||||
true,
|
||||
)
|
||||
.with_addl_obligations(nested)
|
||||
confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true)
|
||||
.with_addl_obligations(nested)
|
||||
}
|
||||
|
||||
fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue