use crate::prelude::*;
#[cfg(feature = "rustc")]
mod resolution;
#[cfg(feature = "rustc")]
mod utils;
#[cfg(feature = "rustc")]
pub use utils::{
erase_and_norm, implied_predicates, predicates_defined_on, required_predicates, self_predicate,
};
#[cfg(feature = "rustc")]
pub use resolution::PredicateSearcher;
#[cfg(feature = "rustc")]
use rustc_middle::ty;
#[cfg(feature = "rustc")]
use rustc_span::def_id::DefId as RDefId;
#[derive(AdtInto)]
#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::PathChunk<'tcx>, state: S as s)]
#[derive_group(Serializers)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
pub enum ImplExprPathChunk {
AssocItem {
item: AssocItem,
generic_args: Vec<GenericArg>,
impl_exprs: Vec<ImplExpr>,
predicate: Binder<TraitPredicate>,
#[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)]
predicate_id: PredicateId,
index: usize,
},
Parent {
predicate: Binder<TraitPredicate>,
#[value(<_ as SInto<_, Clause>>::sinto(predicate, s).id)]
predicate_id: PredicateId,
index: usize,
},
}
#[derive(AdtInto)]
#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExprAtom<'tcx>, state: S as s)]
#[derive_group(Serializers)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema)]
pub enum ImplExprAtom {
Concrete {
#[from(def_id)]
id: GlobalIdent,
generics: Vec<GenericArg>,
},
LocalBound {
#[not_in_source]
#[value({
let Self::LocalBound { predicate, .. } = self else { unreachable!() };
predicate.sinto(s).id
})]
predicate_id: PredicateId,
index: usize,
r#trait: Binder<TraitRef>,
path: Vec<ImplExprPathChunk>,
},
SelfImpl {
r#trait: Binder<TraitRef>,
path: Vec<ImplExprPathChunk>,
},
Dyn,
Builtin { r#trait: Binder<TraitRef> },
Error(String),
}
#[derive_group(Serializers)]
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, AdtInto)]
#[args(<'tcx, S: UnderOwnerState<'tcx> >, from: resolution::ImplExpr<'tcx>, state: S as s)]
pub struct ImplExpr {
pub r#trait: Binder<TraitRef>,
pub r#impl: ImplExprAtom,
pub args: Vec<ImplExpr>,
}
#[cfg(feature = "rustc")]
pub fn super_clause_to_clause_and_impl_expr<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
impl_did: rustc_span::def_id::DefId,
clause: rustc_middle::ty::Clause<'tcx>,
span: rustc_span::Span,
) -> Option<(Clause, ImplExpr, Span)> {
use rustc_middle::ty::ToPolyTraitRef;
let tcx = s.base().tcx;
let impl_trait_ref = tcx
.impl_trait_ref(impl_did)
.map(|binder| rustc_middle::ty::Binder::dummy(binder.instantiate_identity()))?;
let original_predicate_id = {
let s = &with_owner_id(s.base(), (), (), impl_trait_ref.def_id());
clause.sinto(s).id
};
let new_clause = clause.instantiate_supertrait(tcx, impl_trait_ref);
let impl_expr = solve_trait(
s,
new_clause
.as_predicate()
.as_trait_clause()?
.to_poly_trait_ref(),
);
let mut new_clause_no_binder = new_clause.sinto(s);
new_clause_no_binder.id = original_predicate_id;
Some((new_clause_no_binder, impl_expr, span.sinto(s)))
}
#[cfg(feature = "rustc")]
#[tracing::instrument(level = "trace", skip(s))]
pub fn solve_trait<'tcx, S: BaseState<'tcx> + HasOwnerId>(
s: &S,
trait_ref: rustc_middle::ty::PolyTraitRef<'tcx>,
) -> ImplExpr {
let warn = |msg: &str| {
if !s.base().ty_alias_mode {
crate::warning!(s, "{}", msg)
}
};
if let Some(impl_expr) = s.with_cache(|cache| cache.impl_exprs.get(&trait_ref).cloned()) {
return impl_expr;
}
let resolved = s.with_cache(|cache| {
cache
.predicate_searcher
.get_or_insert_with(|| PredicateSearcher::new_for_owner(s.base().tcx, s.owner_id()))
.resolve(&trait_ref, &warn)
});
let impl_expr = match resolved {
Ok(x) => x.sinto(s),
Err(e) => crate::fatal!(s, "{}", e),
};
s.with_cache(|cache| cache.impl_exprs.insert(trait_ref, impl_expr.clone()));
impl_expr
}
#[cfg(feature = "rustc")]
#[tracing::instrument(level = "trace", skip(s), ret)]
pub fn solve_item_required_traits<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
def_id: RDefId,
generics: ty::GenericArgsRef<'tcx>,
) -> Vec<ImplExpr> {
let predicates = required_predicates(s.base().tcx, def_id);
solve_item_traits_inner(s, generics, predicates)
}
#[cfg(feature = "rustc")]
#[tracing::instrument(level = "trace", skip(s), ret)]
pub fn solve_item_implied_traits<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
def_id: RDefId,
generics: ty::GenericArgsRef<'tcx>,
) -> Vec<ImplExpr> {
let predicates = implied_predicates(s.base().tcx, def_id);
solve_item_traits_inner(s, generics, predicates)
}
#[cfg(feature = "rustc")]
fn solve_item_traits_inner<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
generics: ty::GenericArgsRef<'tcx>,
predicates: impl Iterator<Item = ty::Clause<'tcx>>,
) -> Vec<ImplExpr> {
use crate::rustc_middle::ty::ToPolyTraitRef;
let tcx = s.base().tcx;
let param_env = s.param_env();
predicates
.filter_map(|clause| clause.as_trait_clause())
.map(|clause| clause.to_poly_trait_ref())
.map(|trait_ref| ty::EarlyBinder::bind(trait_ref).instantiate(tcx, generics))
.map(|trait_ref| {
tcx.try_normalize_erasing_regions(param_env, trait_ref)
.unwrap_or(trait_ref)
})
.map(|trait_ref| solve_trait(s, trait_ref))
.collect()
}
#[cfg(feature = "rustc")]
pub fn self_clause_for_item<'tcx, S: UnderOwnerState<'tcx>>(
s: &S,
assoc: &rustc_middle::ty::AssocItem,
generics: rustc_middle::ty::GenericArgsRef<'tcx>,
) -> Option<ImplExpr> {
use rustc_middle::ty::EarlyBinder;
let tcx = s.base().tcx;
let tr_def_id = tcx.trait_of_item(assoc.def_id)?;
let self_pred = self_predicate(tcx, tr_def_id).unwrap();
let generics = generics.truncate_to(tcx, tcx.generics_of(tr_def_id));
let self_pred = EarlyBinder::bind(self_pred).instantiate(tcx, generics);
Some(solve_trait(s, self_pred))
}