rustc_traits/
coroutine_witnesses.rs

1use rustc_hir::def_id::DefId;
2use rustc_infer::infer::TyCtxtInferExt;
3use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
4use rustc_infer::infer::resolve::OpportunisticRegionResolver;
5use rustc_infer::traits::{Obligation, ObligationCause};
6use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions};
7use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars};
8
9/// Return the set of types that should be taken into account when checking
10/// trait bounds on a coroutine's internal state. This properly replaces
11/// `ReErased` with new existential bound lifetimes.
12pub(crate) fn coroutine_hidden_types<'tcx>(
13    tcx: TyCtxt<'tcx>,
14    def_id: DefId,
15) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> {
16    let coroutine_layout = tcx.mir_coroutine_witnesses(def_id);
17    let mut vars = vec![];
18    let bound_tys = tcx.mk_type_list_from_iter(
19        coroutine_layout
20            .as_ref()
21            .map_or_else(|| [].iter(), |l| l.field_tys.iter())
22            .filter(|decl| !decl.ignore_for_traits)
23            .map(|decl| {
24                let ty = fold_regions(tcx, decl.ty, |re, debruijn| {
25                    assert_eq!(re, tcx.lifetimes.re_erased);
26                    let var = ty::BoundVar::from_usize(vars.len());
27                    vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon));
28                    ty::Region::new_bound(
29                        tcx,
30                        debruijn,
31                        ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon },
32                    )
33                });
34                ty
35            }),
36    );
37
38    let assumptions = compute_assumptions(tcx, def_id, bound_tys);
39
40    ty::EarlyBinder::bind(ty::Binder::bind_with_vars(
41        ty::CoroutineWitnessTypes { types: bound_tys, assumptions },
42        tcx.mk_bound_variable_kinds(&vars),
43    ))
44}
45
46fn compute_assumptions<'tcx>(
47    tcx: TyCtxt<'tcx>,
48    def_id: DefId,
49    bound_tys: &'tcx ty::List<Ty<'tcx>>,
50) -> &'tcx ty::List<ty::ArgOutlivesPredicate<'tcx>> {
51    let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis {
52        defining_opaque_types_and_generators: ty::List::empty(),
53    });
54    with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| {
55        let param_env = tcx.param_env(def_id);
56        let ocx = ObligationCtxt::new(&infcx);
57
58        ocx.register_obligations(bound_tys.iter().map(|ty| {
59            Obligation::new(
60                tcx,
61                ObligationCause::dummy(),
62                param_env,
63                ty::ClauseKind::WellFormed(ty.into()),
64            )
65        }));
66        let _errors = ocx.select_all_or_error();
67
68        let region_obligations = infcx.take_registered_region_obligations();
69        let region_assumptions = infcx.take_registered_region_assumptions();
70        let region_constraints = infcx.take_and_reset_region_constraints();
71
72        let outlives = make_query_region_constraints(
73            tcx,
74            region_obligations,
75            &region_constraints,
76            region_assumptions,
77        )
78        .outlives
79        .fold_with(&mut OpportunisticRegionResolver::new(&infcx));
80
81        tcx.mk_outlives_from_iter(
82            outlives
83                .into_iter()
84                .map(|(o, _)| o)
85                // FIXME(higher_ranked_auto): We probably should deeply resolve these before
86                // filtering out infers which only correspond to unconstrained infer regions
87                // which we can sometimes get.
88                .filter(|o| !o.has_infer()),
89        )
90    })
91}