mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-22 23:04:33 +00:00
Flatten confirmation logic
This commit is contained in:
parent
4a2fe4491e
commit
f3d32f2f0c
@ -318,34 +318,27 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
self_ty: Ty<'tcx>,
|
self_ty: Ty<'tcx>,
|
||||||
goal_kind: ty::ClosureKind,
|
goal_kind: ty::ClosureKind,
|
||||||
env_region: ty::Region<'tcx>,
|
env_region: ty::Region<'tcx>,
|
||||||
) -> Result<
|
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
|
||||||
(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option<ty::Predicate<'tcx>>),
|
{
|
||||||
NoSolution,
|
|
||||||
> {
|
|
||||||
match *self_ty.kind() {
|
match *self_ty.kind() {
|
||||||
ty::CoroutineClosure(def_id, args) => {
|
ty::CoroutineClosure(def_id, args) => {
|
||||||
let args = args.as_coroutine_closure();
|
let args = args.as_coroutine_closure();
|
||||||
let kind_ty = args.kind_ty();
|
let kind_ty = args.kind_ty();
|
||||||
|
let sig = args.coroutine_closure_sig().skip_binder();
|
||||||
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
let mut nested = vec![];
|
||||||
|
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
||||||
if !closure_kind.extends(goal_kind) {
|
if !closure_kind.extends(goal_kind) {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
Ok((
|
sig.to_coroutine_given_kind_and_upvars(
|
||||||
args.coroutine_closure_sig().map_bound(|sig| {
|
tcx,
|
||||||
let coroutine_ty = sig.to_coroutine_given_kind_and_upvars(
|
args.parent_args(),
|
||||||
tcx,
|
tcx.coroutine_for_closure(def_id),
|
||||||
args.parent_args(),
|
goal_kind,
|
||||||
tcx.coroutine_for_closure(def_id),
|
env_region,
|
||||||
goal_kind,
|
args.tupled_upvars_ty(),
|
||||||
env_region,
|
args.coroutine_captures_by_ref_ty(),
|
||||||
args.tupled_upvars_ty(),
|
)
|
||||||
args.coroutine_captures_by_ref_ty(),
|
|
||||||
);
|
|
||||||
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
|
|
||||||
}),
|
|
||||||
None,
|
|
||||||
))
|
|
||||||
} else {
|
} else {
|
||||||
let async_fn_kind_trait_def_id =
|
let async_fn_kind_trait_def_id =
|
||||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||||
@ -362,39 +355,43 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
|||||||
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
|
||||||
// will project to the right upvars for the generator, appending the inputs and
|
// will project to the right upvars for the generator, appending the inputs and
|
||||||
// coroutine upvars respecting the closure kind.
|
// coroutine upvars respecting the closure kind.
|
||||||
Ok((
|
nested.push(
|
||||||
args.coroutine_closure_sig().map_bound(|sig| {
|
ty::TraitRef::new(
|
||||||
let tupled_upvars_ty = Ty::new_projection(
|
tcx,
|
||||||
tcx,
|
async_fn_kind_trait_def_id,
|
||||||
upvars_projection_def_id,
|
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
||||||
[
|
)
|
||||||
ty::GenericArg::from(kind_ty),
|
.to_predicate(tcx),
|
||||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
);
|
||||||
env_region.into(),
|
let tupled_upvars_ty = Ty::new_projection(
|
||||||
sig.tupled_inputs_ty.into(),
|
tcx,
|
||||||
args.tupled_upvars_ty().into(),
|
upvars_projection_def_id,
|
||||||
args.coroutine_captures_by_ref_ty().into(),
|
[
|
||||||
],
|
ty::GenericArg::from(kind_ty),
|
||||||
);
|
Ty::from_closure_kind(tcx, goal_kind).into(),
|
||||||
let coroutine_ty = sig.to_coroutine(
|
env_region.into(),
|
||||||
tcx,
|
sig.tupled_inputs_ty.into(),
|
||||||
args.parent_args(),
|
args.tupled_upvars_ty().into(),
|
||||||
Ty::from_closure_kind(tcx, goal_kind),
|
args.coroutine_captures_by_ref_ty().into(),
|
||||||
tcx.coroutine_for_closure(def_id),
|
],
|
||||||
tupled_upvars_ty,
|
);
|
||||||
);
|
sig.to_coroutine(
|
||||||
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
|
tcx,
|
||||||
}),
|
args.parent_args(),
|
||||||
Some(
|
Ty::from_closure_kind(tcx, goal_kind),
|
||||||
ty::TraitRef::new(
|
tcx.coroutine_for_closure(def_id),
|
||||||
tcx,
|
tupled_upvars_ty,
|
||||||
async_fn_kind_trait_def_id,
|
)
|
||||||
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
};
|
||||||
)
|
|
||||||
.to_predicate(tcx),
|
Ok((
|
||||||
),
|
args.coroutine_closure_sig().rebind((
|
||||||
))
|
sig.tupled_inputs_ty,
|
||||||
}
|
sig.return_ty,
|
||||||
|
coroutine_ty,
|
||||||
|
)),
|
||||||
|
nested,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution),
|
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution),
|
||||||
|
@ -2446,8 +2446,9 @@ fn confirm_callable_candidate<'cx, 'tcx>(
|
|||||||
fn confirm_async_closure_candidate<'cx, 'tcx>(
|
fn confirm_async_closure_candidate<'cx, 'tcx>(
|
||||||
selcx: &mut SelectionContext<'cx, 'tcx>,
|
selcx: &mut SelectionContext<'cx, 'tcx>,
|
||||||
obligation: &ProjectionTyObligation<'tcx>,
|
obligation: &ProjectionTyObligation<'tcx>,
|
||||||
mut nested: Vec<PredicateObligation<'tcx>>,
|
nested: Vec<PredicateObligation<'tcx>>,
|
||||||
) -> Progress<'tcx> {
|
) -> Progress<'tcx> {
|
||||||
|
let tcx = selcx.tcx();
|
||||||
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
|
||||||
let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else {
|
let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else {
|
||||||
unreachable!(
|
unreachable!(
|
||||||
@ -2456,47 +2457,48 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
|
|||||||
};
|
};
|
||||||
let args = args.as_coroutine_closure();
|
let args = args.as_coroutine_closure();
|
||||||
let kind_ty = args.kind_ty();
|
let kind_ty = args.kind_ty();
|
||||||
|
let sig = args.coroutine_closure_sig().skip_binder();
|
||||||
|
|
||||||
let tcx = selcx.tcx();
|
|
||||||
let goal_kind =
|
let goal_kind =
|
||||||
tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
|
tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
|
||||||
|
|
||||||
let async_fn_kind_helper_trait_def_id =
|
|
||||||
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
|
||||||
nested.push(obligation.with(
|
|
||||||
tcx,
|
|
||||||
ty::TraitRef::new(
|
|
||||||
tcx,
|
|
||||||
async_fn_kind_helper_trait_def_id,
|
|
||||||
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
|
|
||||||
),
|
|
||||||
));
|
|
||||||
|
|
||||||
let env_region = match goal_kind {
|
let env_region = match goal_kind {
|
||||||
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
|
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
|
||||||
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
|
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
|
||||||
};
|
};
|
||||||
|
|
||||||
let upvars_projection_def_id = tcx
|
let item_name = tcx.item_name(obligation.predicate.def_id);
|
||||||
.associated_items(async_fn_kind_helper_trait_def_id)
|
let term = match item_name {
|
||||||
.filter_by_name_unhygienic(sym::Upvars)
|
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => {
|
||||||
.next()
|
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
||||||
.unwrap()
|
if !closure_kind.extends(goal_kind) {
|
||||||
.def_id;
|
bug!("we should not be confirming if the closure kind is not met");
|
||||||
|
}
|
||||||
// FIXME(async_closures): Confirmation is kind of a mess here. Ideally,
|
sig.to_coroutine_given_kind_and_upvars(
|
||||||
// we'd short-circuit when we know that the goal_kind >= closure_kind, and not
|
tcx,
|
||||||
// register a nested predicate or create a new projection ty here. But I'm too
|
args.parent_args(),
|
||||||
// lazy to make this more efficient atm, and we can always tweak it later,
|
tcx.coroutine_for_closure(def_id),
|
||||||
// since all this does is make the solver do more work.
|
goal_kind,
|
||||||
//
|
env_region,
|
||||||
// The code duplication due to the different length args is kind of weird, too.
|
args.tupled_upvars_ty(),
|
||||||
//
|
args.coroutine_captures_by_ref_ty(),
|
||||||
// See the logic in `structural_traits` in the new solver to understand a bit
|
)
|
||||||
// more clearly how this *should* look.
|
} else {
|
||||||
let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| {
|
let async_fn_kind_trait_def_id =
|
||||||
let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) {
|
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
|
||||||
sym::CallOnceFuture => {
|
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(
|
let tupled_upvars_ty = Ty::new_projection(
|
||||||
tcx,
|
tcx,
|
||||||
upvars_projection_def_id,
|
upvars_projection_def_id,
|
||||||
@ -2509,66 +2511,38 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
|
|||||||
args.coroutine_captures_by_ref_ty().into(),
|
args.coroutine_captures_by_ref_ty().into(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
let coroutine_ty = sig.to_coroutine(
|
sig.to_coroutine(
|
||||||
tcx,
|
tcx,
|
||||||
args.parent_args(),
|
args.parent_args(),
|
||||||
Ty::from_closure_kind(tcx, goal_kind),
|
Ty::from_closure_kind(tcx, goal_kind),
|
||||||
tcx.coroutine_for_closure(def_id),
|
tcx.coroutine_for_closure(def_id),
|
||||||
tupled_upvars_ty,
|
tupled_upvars_ty,
|
||||||
);
|
|
||||||
(
|
|
||||||
ty::AliasTy::new(
|
|
||||||
tcx,
|
|
||||||
obligation.predicate.def_id,
|
|
||||||
[self_ty, sig.tupled_inputs_ty],
|
|
||||||
),
|
|
||||||
coroutine_ty.into(),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
sym::CallMutFuture | sym::CallFuture => {
|
}
|
||||||
let tupled_upvars_ty = Ty::new_projection(
|
sym::Output => sig.return_ty,
|
||||||
tcx,
|
name => bug!("no such associated type: {name}"),
|
||||||
upvars_projection_def_id,
|
};
|
||||||
[
|
let projection_ty = match item_name {
|
||||||
ty::GenericArg::from(kind_ty),
|
sym::CallOnceFuture | sym::Output => {
|
||||||
Ty::from_closure_kind(tcx, goal_kind).into(),
|
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty])
|
||||||
env_region.into(),
|
}
|
||||||
sig.tupled_inputs_ty.into(),
|
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
|
||||||
args.tupled_upvars_ty().into(),
|
tcx,
|
||||||
args.coroutine_captures_by_ref_ty().into(),
|
obligation.predicate.def_id,
|
||||||
],
|
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
|
||||||
);
|
),
|
||||||
let coroutine_ty = sig.to_coroutine(
|
name => bug!("no such associated type: {name}"),
|
||||||
tcx,
|
};
|
||||||
args.parent_args(),
|
|
||||||
Ty::from_closure_kind(tcx, goal_kind),
|
|
||||||
tcx.coroutine_for_closure(def_id),
|
|
||||||
tupled_upvars_ty,
|
|
||||||
);
|
|
||||||
(
|
|
||||||
ty::AliasTy::new(
|
|
||||||
tcx,
|
|
||||||
obligation.predicate.def_id,
|
|
||||||
[
|
|
||||||
ty::GenericArg::from(self_ty),
|
|
||||||
sig.tupled_inputs_ty.into(),
|
|
||||||
env_region.into(),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
coroutine_ty.into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
sym::Output => (
|
|
||||||
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]),
|
|
||||||
sig.return_ty.into(),
|
|
||||||
),
|
|
||||||
name => bug!("no such associated type: {name}"),
|
|
||||||
};
|
|
||||||
ty::ProjectionPredicate { projection_ty, term }
|
|
||||||
});
|
|
||||||
|
|
||||||
confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true)
|
confirm_param_env_candidate(
|
||||||
.with_addl_obligations(nested)
|
selcx,
|
||||||
|
obligation,
|
||||||
|
args.coroutine_closure_sig()
|
||||||
|
.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }),
|
||||||
|
true,
|
||||||
|
)
|
||||||
|
.with_addl_obligations(nested)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
|
fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(
|
||||||
|
Loading…
Reference in New Issue
Block a user