use rustc_data_structures::fx::FxHashSet;
use rustc_middle::ty::{self, ToPolyTraitRef, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::Span;
pub use rustc_type_ir::elaborate::*;
use crate::traits::{self, Obligation, ObligationCauseCode, PredicateObligation};
pub fn anonymize_predicate<'tcx>(
tcx: TyCtxt<'tcx>,
pred: ty::Predicate<'tcx>,
) -> ty::Predicate<'tcx> {
let new = tcx.anonymize_bound_vars(pred.kind());
tcx.reuse_or_mk_predicate(pred, new)
}
pub struct PredicateSet<'tcx> {
tcx: TyCtxt<'tcx>,
set: FxHashSet<ty::Predicate<'tcx>>,
}
impl<'tcx> PredicateSet<'tcx> {
pub fn new(tcx: TyCtxt<'tcx>) -> Self {
Self { tcx, set: Default::default() }
}
pub fn insert(&mut self, pred: ty::Predicate<'tcx>) -> bool {
self.set.insert(anonymize_predicate(self.tcx, pred))
}
}
impl<'tcx> Extend<ty::Predicate<'tcx>> for PredicateSet<'tcx> {
fn extend<I: IntoIterator<Item = ty::Predicate<'tcx>>>(&mut self, iter: I) {
for pred in iter {
self.insert(pred);
}
}
fn extend_one(&mut self, pred: ty::Predicate<'tcx>) {
self.insert(pred);
}
fn extend_reserve(&mut self, additional: usize) {
Extend::<ty::Predicate<'tcx>>::extend_reserve(&mut self.set, additional);
}
}
impl<'tcx> Elaboratable<TyCtxt<'tcx>> for PredicateObligation<'tcx> {
fn predicate(&self) -> ty::Predicate<'tcx> {
self.predicate
}
fn child(&self, clause: ty::Clause<'tcx>) -> Self {
Obligation {
cause: self.cause.clone(),
param_env: self.param_env,
recursion_depth: 0,
predicate: clause.as_predicate(),
}
}
fn child_with_derived_cause(
&self,
clause: ty::Clause<'tcx>,
span: Span,
parent_trait_pred: ty::PolyTraitPredicate<'tcx>,
index: usize,
) -> Self {
let cause = self.cause.clone().derived_cause(parent_trait_pred, |derived| {
ObligationCauseCode::ImplDerived(Box::new(traits::ImplDerivedCause {
derived,
impl_or_alias_def_id: parent_trait_pred.def_id(),
impl_def_predicate_index: Some(index),
span,
}))
});
Obligation {
cause,
param_env: self.param_env,
recursion_depth: 0,
predicate: clause.as_predicate(),
}
}
}
pub fn transitive_bounds_that_define_assoc_item<'tcx>(
tcx: TyCtxt<'tcx>,
trait_refs: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
assoc_name: Ident,
) -> impl Iterator<Item = ty::PolyTraitRef<'tcx>> {
let mut seen = FxHashSet::default();
let mut stack: Vec<_> = trait_refs.collect();
std::iter::from_fn(move || {
while let Some(trait_ref) = stack.pop() {
if !seen.insert(tcx.anonymize_bound_vars(trait_ref)) {
continue;
}
stack.extend(
tcx.explicit_supertraits_containing_assoc_item((trait_ref.def_id(), assoc_name))
.iter_identity_copied()
.map(|(clause, _)| clause.instantiate_supertrait(tcx, trait_ref))
.filter_map(|clause| clause.as_trait_clause())
.map(|trait_pred| trait_pred.to_poly_trait_ref()),
);
return Some(trait_ref);
}
None
})
}