use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::infer::canonical::query_response::make_query_region_constraints; use rustc_infer::infer::resolve::OpportunisticRegionResolver; use rustc_infer::traits::{Obligation, ObligationCause}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, fold_regions}; use rustc_span::def_id::DefId; use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars}; /// Return the set of types that should be taken into account when checking /// trait bounds on a coroutine's internal state. This properly replaces /// `ReErased` with new existential bound lifetimes. pub(crate) fn coroutine_hidden_types<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, ) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes>>> { let coroutine_layout = tcx.mir_coroutine_witnesses(def_id); let mut vars = vec![]; let bound_tys = tcx.mk_type_list_from_iter( coroutine_layout .as_ref() .map_or_else(|| [].iter(), |l| l.field_tys.iter()) .filter(|decl| !decl.ignore_for_traits) .map(|decl| { let ty = fold_regions(tcx, decl.ty, |re, debruijn| { assert_eq!(re, tcx.lifetimes.re_erased); let var = ty::BoundVar::from_usize(vars.len()); vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); ty::Region::new_bound( tcx, debruijn, ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, ) }); ty }), ); let assumptions = compute_assumptions(tcx, def_id, bound_tys); ty::EarlyBinder::bind(ty::Binder::bind_with_vars( ty::CoroutineWitnessTypes { types: bound_tys, assumptions }, tcx.mk_bound_variable_kinds(&vars), )) } fn compute_assumptions<'tcx>( tcx: TyCtxt<'tcx>, def_id: DefId, bound_tys: &'tcx ty::List>, ) -> &'tcx ty::List> { let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { defining_opaque_types_and_generators: ty::List::empty(), }); with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| { let param_env = tcx.param_env(def_id); let ocx = ObligationCtxt::new(&infcx); ocx.register_obligations(bound_tys.iter().map(|ty| { Obligation::new( tcx, ObligationCause::dummy(), param_env, ty::ClauseKind::WellFormed(ty.into()), ) })); let _errors = ocx.select_all_or_error(); let region_obligations = infcx.take_registered_region_obligations(); let region_assumptions = infcx.take_registered_region_assumptions(); let region_constraints = infcx.take_and_reset_region_constraints(); let outlives = make_query_region_constraints( region_obligations, ®ion_constraints, region_assumptions, ) .outlives .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); tcx.mk_outlives_from_iter( outlives .into_iter() .map(|(o, _)| o) // FIXME(higher_ranked_auto): We probably should deeply resolve these before // filtering out infers which only correspond to unconstrained infer regions // which we can sometimes get. .filter(|o| !o.has_infer()), ) }) }