Skip to content

Commit f3d32f2

Browse files
Flatten confirmation logic
1 parent 4a2fe44 commit f3d32f2

File tree

2 files changed

+107
-136
lines changed

2 files changed

+107
-136
lines changed

compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs

Lines changed: 51 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -318,34 +318,27 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
318318
self_ty: Ty<'tcx>,
319319
goal_kind: ty::ClosureKind,
320320
env_region: ty::Region<'tcx>,
321-
) -> Result<
322-
(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option<ty::Predicate<'tcx>>),
323-
NoSolution,
324-
> {
321+
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
322+
{
325323
match *self_ty.kind() {
326324
ty::CoroutineClosure(def_id, args) => {
327325
let args = args.as_coroutine_closure();
328326
let kind_ty = args.kind_ty();
329-
330-
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
327+
let sig = args.coroutine_closure_sig().skip_binder();
328+
let mut nested = vec![];
329+
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
331330
if !closure_kind.extends(goal_kind) {
332331
return Err(NoSolution);
333332
}
334-
Ok((
335-
args.coroutine_closure_sig().map_bound(|sig| {
336-
let coroutine_ty = sig.to_coroutine_given_kind_and_upvars(
337-
tcx,
338-
args.parent_args(),
339-
tcx.coroutine_for_closure(def_id),
340-
goal_kind,
341-
env_region,
342-
args.tupled_upvars_ty(),
343-
args.coroutine_captures_by_ref_ty(),
344-
);
345-
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
346-
}),
347-
None,
348-
))
333+
sig.to_coroutine_given_kind_and_upvars(
334+
tcx,
335+
args.parent_args(),
336+
tcx.coroutine_for_closure(def_id),
337+
goal_kind,
338+
env_region,
339+
args.tupled_upvars_ty(),
340+
args.coroutine_captures_by_ref_ty(),
341+
)
349342
} else {
350343
let async_fn_kind_trait_def_id =
351344
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
362355
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
363356
// will project to the right upvars for the generator, appending the inputs and
364357
// coroutine upvars respecting the closure kind.
365-
Ok((
366-
args.coroutine_closure_sig().map_bound(|sig| {
367-
let tupled_upvars_ty = Ty::new_projection(
368-
tcx,
369-
upvars_projection_def_id,
370-
[
371-
ty::GenericArg::from(kind_ty),
372-
Ty::from_closure_kind(tcx, goal_kind).into(),
373-
env_region.into(),
374-
sig.tupled_inputs_ty.into(),
375-
args.tupled_upvars_ty().into(),
376-
args.coroutine_captures_by_ref_ty().into(),
377-
],
378-
);
379-
let coroutine_ty = sig.to_coroutine(
380-
tcx,
381-
args.parent_args(),
382-
Ty::from_closure_kind(tcx, goal_kind),
383-
tcx.coroutine_for_closure(def_id),
384-
tupled_upvars_ty,
385-
);
386-
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
387-
}),
388-
Some(
389-
ty::TraitRef::new(
390-
tcx,
391-
async_fn_kind_trait_def_id,
392-
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
393-
)
394-
.to_predicate(tcx),
395-
),
396-
))
397-
}
358+
nested.push(
359+
ty::TraitRef::new(
360+
tcx,
361+
async_fn_kind_trait_def_id,
362+
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
363+
)
364+
.to_predicate(tcx),
365+
);
366+
let tupled_upvars_ty = Ty::new_projection(
367+
tcx,
368+
upvars_projection_def_id,
369+
[
370+
ty::GenericArg::from(kind_ty),
371+
Ty::from_closure_kind(tcx, goal_kind).into(),
372+
env_region.into(),
373+
sig.tupled_inputs_ty.into(),
374+
args.tupled_upvars_ty().into(),
375+
args.coroutine_captures_by_ref_ty().into(),
376+
],
377+
);
378+
sig.to_coroutine(
379+
tcx,
380+
args.parent_args(),
381+
Ty::from_closure_kind(tcx, goal_kind),
382+
tcx.coroutine_for_closure(def_id),
383+
tupled_upvars_ty,
384+
)
385+
};
386+
387+
Ok((
388+
args.coroutine_closure_sig().rebind((
389+
sig.tupled_inputs_ty,
390+
sig.return_ty,
391+
coroutine_ty,
392+
)),
393+
nested,
394+
))
398395
}
399396

400397
ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) => Err(NoSolution),

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 56 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -2446,8 +2446,9 @@ fn confirm_callable_candidate<'cx, 'tcx>(
24462446
fn confirm_async_closure_candidate<'cx, 'tcx>(
24472447
selcx: &mut SelectionContext<'cx, 'tcx>,
24482448
obligation: &ProjectionTyObligation<'tcx>,
2449-
mut nested: Vec<PredicateObligation<'tcx>>,
2449+
nested: Vec<PredicateObligation<'tcx>>,
24502450
) -> Progress<'tcx> {
2451+
let tcx = selcx.tcx();
24512452
let self_ty = selcx.infcx.shallow_resolve(obligation.predicate.self_ty());
24522453
let ty::CoroutineClosure(def_id, args) = *self_ty.kind() else {
24532454
unreachable!(
@@ -2456,76 +2457,48 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
24562457
};
24572458
let args = args.as_coroutine_closure();
24582459
let kind_ty = args.kind_ty();
2460+
let sig = args.coroutine_closure_sig().skip_binder();
24592461

2460-
let tcx = selcx.tcx();
24612462
let goal_kind =
24622463
tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
2463-
2464-
let async_fn_kind_helper_trait_def_id =
2465-
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
2466-
nested.push(obligation.with(
2467-
tcx,
2468-
ty::TraitRef::new(
2469-
tcx,
2470-
async_fn_kind_helper_trait_def_id,
2471-
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
2472-
),
2473-
));
2474-
24752464
let env_region = match goal_kind {
24762465
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => obligation.predicate.args.region_at(2),
24772466
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
24782467
};
24792468

2480-
let upvars_projection_def_id = tcx
2481-
.associated_items(async_fn_kind_helper_trait_def_id)
2482-
.filter_by_name_unhygienic(sym::Upvars)
2483-
.next()
2484-
.unwrap()
2485-
.def_id;
2486-
2487-
// FIXME(async_closures): Confirmation is kind of a mess here. Ideally,
2488-
// we'd short-circuit when we know that the goal_kind >= closure_kind, and not
2489-
// register a nested predicate or create a new projection ty here. But I'm too
2490-
// lazy to make this more efficient atm, and we can always tweak it later,
2491-
// since all this does is make the solver do more work.
2492-
//
2493-
// The code duplication due to the different length args is kind of weird, too.
2494-
//
2495-
// See the logic in `structural_traits` in the new solver to understand a bit
2496-
// more clearly how this *should* look.
2497-
let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| {
2498-
let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) {
2499-
sym::CallOnceFuture => {
2500-
let tupled_upvars_ty = Ty::new_projection(
2501-
tcx,
2502-
upvars_projection_def_id,
2503-
[
2504-
ty::GenericArg::from(kind_ty),
2505-
Ty::from_closure_kind(tcx, goal_kind).into(),
2506-
env_region.into(),
2507-
sig.tupled_inputs_ty.into(),
2508-
args.tupled_upvars_ty().into(),
2509-
args.coroutine_captures_by_ref_ty().into(),
2510-
],
2511-
);
2512-
let coroutine_ty = sig.to_coroutine(
2469+
let item_name = tcx.item_name(obligation.predicate.def_id);
2470+
let term = match item_name {
2471+
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => {
2472+
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
2473+
if !closure_kind.extends(goal_kind) {
2474+
bug!("we should not be confirming if the closure kind is not met");
2475+
}
2476+
sig.to_coroutine_given_kind_and_upvars(
25132477
tcx,
25142478
args.parent_args(),
2515-
Ty::from_closure_kind(tcx, goal_kind),
25162479
tcx.coroutine_for_closure(def_id),
2517-
tupled_upvars_ty,
2518-
);
2519-
(
2520-
ty::AliasTy::new(
2521-
tcx,
2522-
obligation.predicate.def_id,
2523-
[self_ty, sig.tupled_inputs_ty],
2524-
),
2525-
coroutine_ty.into(),
2480+
goal_kind,
2481+
env_region,
2482+
args.tupled_upvars_ty(),
2483+
args.coroutine_captures_by_ref_ty(),
25262484
)
2527-
}
2528-
sym::CallMutFuture | sym::CallFuture => {
2485+
} else {
2486+
let async_fn_kind_trait_def_id =
2487+
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
2488+
let upvars_projection_def_id = tcx
2489+
.associated_items(async_fn_kind_trait_def_id)
2490+
.filter_by_name_unhygienic(sym::Upvars)
2491+
.next()
2492+
.unwrap()
2493+
.def_id;
2494+
// When we don't know the closure kind (and therefore also the closure's upvars,
2495+
// which are computed at the same time), we must delay the computation of the
2496+
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
2497+
// goal functions similarly to the old `ClosureKind` predicate, and ensures that
2498+
// the goal kind <= the closure kind. As a projection `AsyncFnKindHelper::Upvars`
2499+
// will project to the right upvars for the generator, appending the inputs and
2500+
// coroutine upvars respecting the closure kind.
2501+
// N.B. No need to register a `AsyncFnKindHelper` goal here, it's already in `nested`.
25292502
let tupled_upvars_ty = Ty::new_projection(
25302503
tcx,
25312504
upvars_projection_def_id,
@@ -2538,37 +2511,38 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
25382511
args.coroutine_captures_by_ref_ty().into(),
25392512
],
25402513
);
2541-
let coroutine_ty = sig.to_coroutine(
2514+
sig.to_coroutine(
25422515
tcx,
25432516
args.parent_args(),
25442517
Ty::from_closure_kind(tcx, goal_kind),
25452518
tcx.coroutine_for_closure(def_id),
25462519
tupled_upvars_ty,
2547-
);
2548-
(
2549-
ty::AliasTy::new(
2550-
tcx,
2551-
obligation.predicate.def_id,
2552-
[
2553-
ty::GenericArg::from(self_ty),
2554-
sig.tupled_inputs_ty.into(),
2555-
env_region.into(),
2556-
],
2557-
),
2558-
coroutine_ty.into(),
25592520
)
25602521
}
2561-
sym::Output => (
2562-
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty]),
2563-
sig.return_ty.into(),
2564-
),
2565-
name => bug!("no such associated type: {name}"),
2566-
};
2567-
ty::ProjectionPredicate { projection_ty, term }
2568-
});
2522+
}
2523+
sym::Output => sig.return_ty,
2524+
name => bug!("no such associated type: {name}"),
2525+
};
2526+
let projection_ty = match item_name {
2527+
sym::CallOnceFuture | sym::Output => {
2528+
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.tupled_inputs_ty])
2529+
}
2530+
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
2531+
tcx,
2532+
obligation.predicate.def_id,
2533+
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
2534+
),
2535+
name => bug!("no such associated type: {name}"),
2536+
};
25692537

2570-
confirm_param_env_candidate(selcx, obligation, poly_cache_entry, true)
2571-
.with_addl_obligations(nested)
2538+
confirm_param_env_candidate(
2539+
selcx,
2540+
obligation,
2541+
args.coroutine_closure_sig()
2542+
.rebind(ty::ProjectionPredicate { projection_ty, term: term.into() }),
2543+
true,
2544+
)
2545+
.with_addl_obligations(nested)
25722546
}
25732547

25742548
fn confirm_async_fn_kind_helper_candidate<'cx, 'tcx>(

0 commit comments

Comments
 (0)