use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_infer::infer::canonical::{Canonical, QueryResponse}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::query::Providers; use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult}; use rustc_middle::ty::GenericArgs; use rustc_middle::ty::TyCtxt; use rustc_trait_selection::infer::InferCtxtBuilderExt; use rustc_trait_selection::traits::query::dropck_outlives::{ compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner, }; use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution}; pub(crate) fn provide(p: &mut Providers) { *p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p }; } fn dropck_outlives<'tcx>( tcx: TyCtxt<'tcx>, canonical_goal: CanonicalTyGoal<'tcx>, ) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, DropckOutlivesResult<'tcx>>>, NoSolution> { debug!("dropck_outlives(goal={:#?})", canonical_goal); tcx.infer_ctxt().enter_canonical_trait_query(&canonical_goal, |ocx, goal| { compute_dropck_outlives_inner(ocx, goal) }) } /// Calculates the dtorck constraint for a type. pub(crate) fn adt_dtorck_constraint( tcx: TyCtxt<'_>, def_id: DefId, ) -> Result<&DropckConstraint<'_>, NoSolution> { let def = tcx.adt_def(def_id); let span = tcx.def_span(def_id); let param_env = tcx.param_env(def_id); debug!("dtorck_constraint: {:?}", def); if def.is_manually_drop() { bug!("`ManuallyDrop` should have been handled by `trivial_dropck_outlives`"); } else if def.is_phantom_data() { // The first generic parameter here is guaranteed to be a type because it's // `PhantomData`. let args = GenericArgs::identity_for_item(tcx, def_id); assert_eq!(args.len(), 1); let result = DropckConstraint { outlives: vec![], dtorck_types: vec![args.type_at(0)], overflows: vec![], }; debug!("dtorck_constraint: {:?} => {:?}", def, result); return Ok(tcx.arena.alloc(result)); } let mut result = DropckConstraint::empty(); for field in def.all_fields() { let fty = tcx.type_of(field.did).instantiate_identity(); dtorck_constraint_for_ty_inner(tcx, param_env, span, 0, fty, &mut result)?; } result.outlives.extend(tcx.destructor_constraints(def)); dedup_dtorck_constraint(&mut result); debug!("dtorck_constraint: {:?} => {:?}", def, result); Ok(tcx.arena.alloc(result)) } fn dedup_dtorck_constraint(c: &mut DropckConstraint<'_>) { let mut outlives = FxHashSet::default(); let mut dtorck_types = FxHashSet::default(); c.outlives.retain(|&val| outlives.replace(val).is_none()); c.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none()); }