|
| 1 | +use rustc_hir::def_id::DefId; |
| 2 | +use rustc_infer::infer::TyCtxtInferExt; |
| 3 | +use rustc_infer::infer::canonical::query_response::make_query_region_constraints; |
| 4 | +use rustc_infer::traits::{Obligation, ObligationCause}; |
| 5 | +use rustc_middle::ty::{self, Ty, TyCtxt, fold_regions}; |
| 6 | +use rustc_trait_selection::traits::{ObligationCtxt, with_replaced_escaping_bound_vars}; |
| 7 | + |
| 8 | +/// Return the set of types that should be taken into account when checking |
| 9 | +/// trait bounds on a coroutine's internal state. This properly replaces |
| 10 | +/// `ReErased` with new existential bound lifetimes. |
| 11 | +pub(crate) fn coroutine_hidden_types<'tcx>( |
| 12 | + tcx: TyCtxt<'tcx>, |
| 13 | + def_id: DefId, |
| 14 | +) -> ty::EarlyBinder<'tcx, ty::Binder<'tcx, ty::CoroutineWitnessTypes<TyCtxt<'tcx>>>> { |
| 15 | + let coroutine_layout = tcx.mir_coroutine_witnesses(def_id); |
| 16 | + let mut vars = vec![]; |
| 17 | + let bound_tys = tcx.mk_type_list_from_iter( |
| 18 | + coroutine_layout |
| 19 | + .as_ref() |
| 20 | + .map_or_else(|| [].iter(), |l| l.field_tys.iter()) |
| 21 | + .filter(|decl| !decl.ignore_for_traits) |
| 22 | + .map(|decl| { |
| 23 | + let ty = fold_regions(tcx, decl.ty, |re, debruijn| { |
| 24 | + assert_eq!(re, tcx.lifetimes.re_erased); |
| 25 | + let var = ty::BoundVar::from_usize(vars.len()); |
| 26 | + vars.push(ty::BoundVariableKind::Region(ty::BoundRegionKind::Anon)); |
| 27 | + ty::Region::new_bound( |
| 28 | + tcx, |
| 29 | + debruijn, |
| 30 | + ty::BoundRegion { var, kind: ty::BoundRegionKind::Anon }, |
| 31 | + ) |
| 32 | + }); |
| 33 | + ty |
| 34 | + }), |
| 35 | + ); |
| 36 | + |
| 37 | + let assumptions = compute_assumptions(tcx, def_id, bound_tys); |
| 38 | + |
| 39 | + ty::EarlyBinder::bind(ty::Binder::bind_with_vars( |
| 40 | + ty::CoroutineWitnessTypes { types: bound_tys, assumptions }, |
| 41 | + tcx.mk_bound_variable_kinds(&vars), |
| 42 | + )) |
| 43 | +} |
| 44 | + |
| 45 | +fn compute_assumptions<'tcx>( |
| 46 | + tcx: TyCtxt<'tcx>, |
| 47 | + def_id: DefId, |
| 48 | + bound_tys: &'tcx ty::List<Ty<'tcx>>, |
| 49 | +) -> &'tcx ty::List<ty::OutlivesPredicate<'tcx, ty::GenericArg<'tcx>>> { |
| 50 | + let infcx = tcx.infer_ctxt().build(ty::TypingMode::Analysis { |
| 51 | + defining_opaque_types_and_generators: ty::List::empty(), |
| 52 | + }); |
| 53 | + with_replaced_escaping_bound_vars(&infcx, &mut vec![None], bound_tys, |bound_tys| { |
| 54 | + let param_env = tcx.param_env(def_id); |
| 55 | + let ocx = ObligationCtxt::new(&infcx); |
| 56 | + |
| 57 | + ocx.register_obligations(bound_tys.iter().map(|ty| { |
| 58 | + Obligation::new( |
| 59 | + tcx, |
| 60 | + ObligationCause::dummy(), |
| 61 | + param_env, |
| 62 | + ty::ClauseKind::WellFormed(ty.into()), |
| 63 | + ) |
| 64 | + })); |
| 65 | + let _errors = ocx.select_all_or_error(); |
| 66 | + |
| 67 | + // Cannot use `take_registered_region_obligations` as we may compute the response |
| 68 | + // inside of a `probe` whenever we have multiple choices inside of the solver. |
| 69 | + let region_obligations = infcx.take_registered_region_obligations(); |
| 70 | + let region_constraints = infcx.take_and_reset_region_constraints(); |
| 71 | + tcx.mk_outlives_from_iter( |
| 72 | + make_query_region_constraints( |
| 73 | + tcx, |
| 74 | + region_obligations |
| 75 | + .iter() |
| 76 | + .map(|r_o| (r_o.sup_type, r_o.sub_region, r_o.origin.to_constraint_category())), |
| 77 | + ®ion_constraints, |
| 78 | + ) |
| 79 | + .outlives |
| 80 | + .into_iter() |
| 81 | + .map(|(o, _)| o), |
| 82 | + ) |
| 83 | + }) |
| 84 | +} |
0 commit comments