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::bug;
use rustc_middle::query::Providers;
use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
use rustc_middle::ty::{GenericArgs, 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};
use tracing::debug;
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)
})
}
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() {
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());
}