Skip to content

Commit 6c6b7e2

Browse files
Add a couple helpers, make return types less confusing
1 parent ea3ac42 commit 6c6b7e2

File tree

3 files changed

+172
-116
lines changed

3 files changed

+172
-116
lines changed

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

+114-75
Original file line numberDiff line numberDiff line change
@@ -305,15 +305,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
305305
return Err(NoSolution);
306306
}
307307

308-
sig.to_coroutine_given_kind_and_upvars(
308+
coroutine_closure_to_certain_coroutine(
309309
tcx,
310-
args.parent_args(),
311-
tcx.coroutine_for_closure(def_id),
312310
goal_kind,
313311
// No captures by ref, so this doesn't matter.
314312
tcx.lifetimes.re_static,
315-
args.tupled_upvars_ty(),
316-
args.coroutine_captures_by_ref_ty(),
313+
def_id,
314+
args,
315+
sig,
317316
)
318317
} else {
319318
// Closure kind is not yet determined, so we return ambiguity unless
@@ -322,33 +321,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
322321
return Ok(None);
323322
}
324323

325-
let async_fn_kind_trait_def_id =
326-
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
327-
let upvars_projection_def_id = tcx
328-
.associated_items(async_fn_kind_trait_def_id)
329-
.filter_by_name_unhygienic(sym::Upvars)
330-
.next()
331-
.unwrap()
332-
.def_id;
333-
let tupled_upvars_ty = Ty::new_projection(
334-
tcx,
335-
upvars_projection_def_id,
336-
[
337-
ty::GenericArg::from(kind_ty),
338-
Ty::from_closure_kind(tcx, goal_kind).into(),
339-
// No captures by ref, so this doesn't matter.
340-
tcx.lifetimes.re_static.into(),
341-
sig.tupled_inputs_ty.into(),
342-
args.tupled_upvars_ty().into(),
343-
args.coroutine_captures_by_ref_ty().into(),
344-
],
345-
);
346-
sig.to_coroutine(
324+
coroutine_closure_to_ambiguous_coroutine(
347325
tcx,
348-
args.parent_args(),
349-
Ty::from_closure_kind(tcx, goal_kind),
350-
tcx.coroutine_for_closure(def_id),
351-
tupled_upvars_ty,
326+
goal_kind, // No captures by ref, so this doesn't matter.
327+
tcx.lifetimes.re_static,
328+
def_id,
329+
args,
330+
sig,
352331
)
353332
};
354333

@@ -385,6 +364,19 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
385364
}
386365
}
387366

367+
/// Relevant types for an async callable, including its inputs, output,
368+
/// and the return type you get from awaiting the output.
369+
#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)]
370+
pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> {
371+
pub tupled_inputs_ty: Ty<'tcx>,
372+
/// Type returned by calling the closure
373+
/// i.e. `f()`.
374+
pub output_coroutine_ty: Ty<'tcx>,
375+
/// Type returned by `await`ing the output
376+
/// i.e. `f().await`.
377+
pub coroutine_return_ty: Ty<'tcx>,
378+
}
379+
388380
// Returns a binder of the tupled inputs types, output type, and coroutine type
389381
// from a builtin coroutine-closure type. If we don't yet know the closure kind of
390382
// the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper`
@@ -395,8 +387,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
395387
self_ty: Ty<'tcx>,
396388
goal_kind: ty::ClosureKind,
397389
env_region: ty::Region<'tcx>,
398-
) -> Result<(ty::Binder<'tcx, (Ty<'tcx>, Ty<'tcx>, Ty<'tcx>)>, Vec<ty::Predicate<'tcx>>), NoSolution>
399-
{
390+
) -> Result<
391+
(ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec<ty::Predicate<'tcx>>),
392+
NoSolution,
393+
> {
400394
match *self_ty.kind() {
401395
ty::CoroutineClosure(def_id, args) => {
402396
let args = args.as_coroutine_closure();
@@ -407,24 +401,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
407401
if !closure_kind.extends(goal_kind) {
408402
return Err(NoSolution);
409403
}
410-
sig.to_coroutine_given_kind_and_upvars(
411-
tcx,
412-
args.parent_args(),
413-
tcx.coroutine_for_closure(def_id),
414-
goal_kind,
415-
env_region,
416-
args.tupled_upvars_ty(),
417-
args.coroutine_captures_by_ref_ty(),
404+
405+
coroutine_closure_to_certain_coroutine(
406+
tcx, goal_kind, env_region, def_id, args, sig,
418407
)
419408
} else {
420-
let async_fn_kind_trait_def_id =
421-
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
422-
let upvars_projection_def_id = tcx
423-
.associated_items(async_fn_kind_trait_def_id)
424-
.filter_by_name_unhygienic(sym::Upvars)
425-
.next()
426-
.unwrap()
427-
.def_id;
428409
// When we don't know the closure kind (and therefore also the closure's upvars,
429410
// which are computed at the same time), we must delay the computation of the
430411
// generator's upvars. We do this using the `AsyncFnKindHelper`, which as a trait
@@ -435,38 +416,23 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
435416
nested.push(
436417
ty::TraitRef::new(
437418
tcx,
438-
async_fn_kind_trait_def_id,
419+
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None),
439420
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
440421
)
441422
.to_predicate(tcx),
442423
);
443-
let tupled_upvars_ty = Ty::new_projection(
444-
tcx,
445-
upvars_projection_def_id,
446-
[
447-
ty::GenericArg::from(kind_ty),
448-
Ty::from_closure_kind(tcx, goal_kind).into(),
449-
env_region.into(),
450-
sig.tupled_inputs_ty.into(),
451-
args.tupled_upvars_ty().into(),
452-
args.coroutine_captures_by_ref_ty().into(),
453-
],
454-
);
455-
sig.to_coroutine(
456-
tcx,
457-
args.parent_args(),
458-
Ty::from_closure_kind(tcx, goal_kind),
459-
tcx.coroutine_for_closure(def_id),
460-
tupled_upvars_ty,
424+
425+
coroutine_closure_to_ambiguous_coroutine(
426+
tcx, goal_kind, env_region, def_id, args, sig,
461427
)
462428
};
463429

464430
Ok((
465-
args.coroutine_closure_sig().rebind((
466-
sig.tupled_inputs_ty,
467-
sig.return_ty,
468-
coroutine_ty,
469-
)),
431+
args.coroutine_closure_sig().rebind(AsyncCallableRelevantTypes {
432+
tupled_inputs_ty: sig.tupled_inputs_ty,
433+
output_coroutine_ty: coroutine_ty,
434+
coroutine_return_ty: sig.return_ty,
435+
}),
470436
nested,
471437
))
472438
}
@@ -490,7 +456,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
490456
.def_id;
491457
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
492458
Ok((
493-
bound_sig.rebind((Ty::new_tup(tcx, sig.inputs()), sig.output(), future_output_ty)),
459+
bound_sig.rebind(AsyncCallableRelevantTypes {
460+
tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()),
461+
output_coroutine_ty: sig.output(),
462+
coroutine_return_ty: future_output_ty,
463+
}),
494464
nested,
495465
))
496466
}
@@ -541,7 +511,14 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
541511
.unwrap()
542512
.def_id;
543513
let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]);
544-
Ok((bound_sig.rebind((sig.inputs()[0], sig.output(), future_output_ty)), nested))
514+
Ok((
515+
bound_sig.rebind(AsyncCallableRelevantTypes {
516+
tupled_inputs_ty: sig.inputs()[0],
517+
output_coroutine_ty: sig.output(),
518+
coroutine_return_ty: future_output_ty,
519+
}),
520+
nested,
521+
))
545522
}
546523

547524
ty::Bool
@@ -574,6 +551,68 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
574551
}
575552
}
576553

554+
/// Given a coroutine-closure, project to its returned coroutine when we are *certain*
555+
/// that the closure's kind is compatible with the goal.
556+
fn coroutine_closure_to_certain_coroutine<'tcx>(
557+
tcx: TyCtxt<'tcx>,
558+
goal_kind: ty::ClosureKind,
559+
goal_region: ty::Region<'tcx>,
560+
def_id: DefId,
561+
args: ty::CoroutineClosureArgs<'tcx>,
562+
sig: ty::CoroutineClosureSignature<'tcx>,
563+
) -> Ty<'tcx> {
564+
sig.to_coroutine_given_kind_and_upvars(
565+
tcx,
566+
args.parent_args(),
567+
tcx.coroutine_for_closure(def_id),
568+
goal_kind,
569+
goal_region,
570+
args.tupled_upvars_ty(),
571+
args.coroutine_captures_by_ref_ty(),
572+
)
573+
}
574+
575+
/// Given a coroutine-closure, project to its returned coroutine when we are *not certain*
576+
/// that the closure's kind is compatible with the goal, and therefore also don't know
577+
/// yet what the closure's upvars are.
578+
///
579+
/// Note that we do not also push a `AsyncFnKindHelper` goal here.
580+
fn coroutine_closure_to_ambiguous_coroutine<'tcx>(
581+
tcx: TyCtxt<'tcx>,
582+
goal_kind: ty::ClosureKind,
583+
goal_region: ty::Region<'tcx>,
584+
def_id: DefId,
585+
args: ty::CoroutineClosureArgs<'tcx>,
586+
sig: ty::CoroutineClosureSignature<'tcx>,
587+
) -> Ty<'tcx> {
588+
let async_fn_kind_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
589+
let upvars_projection_def_id = tcx
590+
.associated_items(async_fn_kind_trait_def_id)
591+
.filter_by_name_unhygienic(sym::Upvars)
592+
.next()
593+
.unwrap()
594+
.def_id;
595+
let tupled_upvars_ty = Ty::new_projection(
596+
tcx,
597+
upvars_projection_def_id,
598+
[
599+
ty::GenericArg::from(args.kind_ty()),
600+
Ty::from_closure_kind(tcx, goal_kind).into(),
601+
goal_region.into(),
602+
sig.tupled_inputs_ty.into(),
603+
args.tupled_upvars_ty().into(),
604+
args.coroutine_captures_by_ref_ty().into(),
605+
],
606+
);
607+
sig.to_coroutine(
608+
tcx,
609+
args.parent_args(),
610+
Ty::from_closure_kind(tcx, goal_kind),
611+
tcx.coroutine_for_closure(def_id),
612+
tupled_upvars_ty,
613+
)
614+
}
615+
577616
/// Assemble a list of predicates that would be present on a theoretical
578617
/// user impl for an object type. These predicates must be checked any time
579618
/// we assemble a built-in object candidate for an object type, since they

compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs

+46-35
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::traits::{check_args_compatible, specialization_graph};
22

3+
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
34
use super::assembly::{self, structural_traits, Candidate};
45
use super::{EvalCtxt, GoalSource};
56
use rustc_hir::def::DefKind;
@@ -392,46 +393,56 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
392393
goal_kind,
393394
env_region,
394395
)?;
395-
let output_is_sized_pred =
396-
tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
397-
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
398-
});
396+
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
397+
|AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| {
398+
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_ty])
399+
},
400+
);
399401

400402
let pred = tupled_inputs_and_output_and_coroutine
401-
.map_bound(|(inputs, output, coroutine)| {
402-
let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
403-
sym::CallOnceFuture => (
404-
ty::AliasTy::new(
405-
tcx,
406-
goal.predicate.def_id(),
407-
[goal.predicate.self_ty(), inputs],
403+
.map_bound(
404+
|AsyncCallableRelevantTypes {
405+
tupled_inputs_ty,
406+
output_coroutine_ty,
407+
coroutine_return_ty,
408+
}| {
409+
let (projection_ty, term) = match tcx.item_name(goal.predicate.def_id()) {
410+
sym::CallOnceFuture => (
411+
ty::AliasTy::new(
412+
tcx,
413+
goal.predicate.def_id(),
414+
[goal.predicate.self_ty(), tupled_inputs_ty],
415+
),
416+
output_coroutine_ty.into(),
408417
),
409-
coroutine.into(),
410-
),
411-
sym::CallMutFuture | sym::CallFuture => (
412-
ty::AliasTy::new(
413-
tcx,
414-
goal.predicate.def_id(),
415-
[
416-
ty::GenericArg::from(goal.predicate.self_ty()),
417-
inputs.into(),
418-
env_region.into(),
419-
],
418+
sym::CallMutFuture | sym::CallFuture => (
419+
ty::AliasTy::new(
420+
tcx,
421+
goal.predicate.def_id(),
422+
[
423+
ty::GenericArg::from(goal.predicate.self_ty()),
424+
tupled_inputs_ty.into(),
425+
env_region.into(),
426+
],
427+
),
428+
output_coroutine_ty.into(),
420429
),
421-
coroutine.into(),
422-
),
423-
sym::Output => (
424-
ty::AliasTy::new(
425-
tcx,
426-
goal.predicate.def_id(),
427-
[ty::GenericArg::from(goal.predicate.self_ty()), inputs.into()],
430+
sym::Output => (
431+
ty::AliasTy::new(
432+
tcx,
433+
goal.predicate.def_id(),
434+
[
435+
ty::GenericArg::from(goal.predicate.self_ty()),
436+
tupled_inputs_ty.into(),
437+
],
438+
),
439+
coroutine_return_ty.into(),
428440
),
429-
output.into(),
430-
),
431-
name => bug!("no such associated type: {name}"),
432-
};
433-
ty::ProjectionPredicate { projection_ty, term }
434-
})
441+
name => bug!("no such associated type: {name}"),
442+
};
443+
ty::ProjectionPredicate { projection_ty, term }
444+
},
445+
)
435446
.to_predicate(tcx);
436447

437448
// A built-in `AsyncFn` impl only holds if the output is sized.

compiler/rustc_trait_selection/src/solve/trait_goals.rs

+12-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
33
use crate::traits::supertrait_def_ids;
44

5+
use super::assembly::structural_traits::AsyncCallableRelevantTypes;
56
use super::assembly::{self, structural_traits, Candidate};
67
use super::{EvalCtxt, GoalSource, SolverMode};
78
use rustc_data_structures::fx::FxIndexSet;
@@ -327,14 +328,19 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
327328
// This region doesn't matter because we're throwing away the coroutine type
328329
tcx.lifetimes.re_static,
329330
)?;
330-
let output_is_sized_pred =
331-
tupled_inputs_and_output_and_coroutine.map_bound(|(_, output, _)| {
332-
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
333-
});
331+
let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound(
332+
|AsyncCallableRelevantTypes { output_coroutine_ty, .. }| {
333+
ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output_coroutine_ty])
334+
},
335+
);
334336

335337
let pred = tupled_inputs_and_output_and_coroutine
336-
.map_bound(|(inputs, _, _)| {
337-
ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
338+
.map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| {
339+
ty::TraitRef::new(
340+
tcx,
341+
goal.predicate.def_id(),
342+
[goal.predicate.self_ty(), tupled_inputs_ty],
343+
)
338344
})
339345
.to_predicate(tcx);
340346
// A built-in `AsyncFn` impl only holds if the output is sized.

0 commit comments

Comments
 (0)