More comments, final tweaks

This commit is contained in:
Michael Goulet 2024-01-25 19:17:21 +00:00
parent 37184e86ea
commit c98d6994a3
20 changed files with 169 additions and 42 deletions

View file

@ -309,14 +309,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
}
// Returns a binder of the tupled inputs types, output type, and coroutine type
// from a builtin async closure type.
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
// which enforces the closure is actually callable with the given trait. When we
// know the kind already, we can short-circuit this check.
pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>(
tcx: TyCtxt<'tcx>,
self_ty: Ty<'tcx>,
goal_kind: ty::ClosureKind,
env_region: ty::Region<'tcx>,
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
{
) -> Result<
(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Option<ty::Predicate<'tcx>>),
NoSolution,
> {
match *self_ty.kind() {
ty::CoroutineClosure(def_id, args) => {
let args = args.as_coroutine_closure();
@ -339,7 +344,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
);
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
}),
vec![],
None,
))
} else {
let async_fn_kind_trait_def_id =
@ -350,6 +355,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
.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.
Ok((
args.coroutine_closure_sig().map_bound(|sig| {
let tupled_upvars_ty = Ty::new_projection(
@ -373,14 +385,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
);
(sig.tupled_inputs_ty, sig.return_ty, coroutine_ty)
}),
vec![
Some(
ty::TraitRef::new(
tcx,
async_fn_kind_trait_def_id,
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
)
.to_predicate(tcx),
],
),
))
}
}

View file

@ -2491,6 +2491,9 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
// since all this does is make the solver do more work.
//
// The code duplication due to the different length args is kind of weird, too.
//
// See the logic in `structural_traits` in the new solver to understand a bit
// more clearly how this *should* look.
let poly_cache_entry = args.coroutine_closure_sig().map_bound(|sig| {
let (projection_ty, term) = match tcx.item_name(obligation.predicate.def_id) {
sym::CallOnceFuture => {

View file

@ -121,9 +121,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_async_fn_kind_helper_candidates(obligation, &mut candidates);
}
// FIXME: Put these into `else if` blocks above, since they're built-in.
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);
}
@ -382,6 +384,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return;
}
// Check that the self kind extends the goal kind. If it does,
// then there's nothing else to check.
if let Some(closure_kind) = self_ty.to_opt_closure_kind()
&& let Some(goal_kind) = target_kind_ty.to_opt_closure_kind()
{

View file

@ -88,6 +88,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
ImplSource::Builtin(BuiltinImplSource::Misc, vtable_closure)
}
// No nested obligations or confirmation process. The checks that we do in
// candidate assembly are sufficient.
AsyncFnKindHelperCandidate => ImplSource::Builtin(BuiltinImplSource::Misc, vec![]),
CoroutineCandidate => {

View file

@ -728,7 +728,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
}
ty::CoroutineClosure(did, args) => {
// See the above comments.
// See the above comments. The same apply to coroutine-closures.
walker.skip_current_subtree();
self.compute(args.as_coroutine_closure().tupled_upvars_ty().into());
let obligations = self.nominal_obligations(did, args);