| 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); |
| 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, span, fty, 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()); |
| } |