//! Things related to generics in the next-trait-solver.
use hir_def::{
GenericDefId, GenericParamId, TypeParamId,
hir::generics::{GenericParamDataRef, LifetimeParamData},
};
use crate::db::HirDatabase;
use super::{Ctor, DbInterner, SolverDefId};
pub(crate) fn generics<'db>(interner: DbInterner<'db>, def: SolverDefId<'db>) -> Generics<'db> {
let db = interner.db;
let (def, consider_late_bound) = match (def.try_into(), def) {
(Ok(def), _) => (def, false),
(_, SolverDefId::InternedOpaqueTyId(id)) => match id.loc(db) {
crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => (function_id.into(), true),
crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
(type_alias_id.into(), true)
}
},
(_, SolverDefId::BuiltinDeriveImplId(id)) => {
return crate::builtin_derive::generics_of(interner, id);
}
(_, SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id))) => {
(id.loc(db).parent.into(), false)
}
(_, SolverDefId::Ctor(Ctor::Struct(id))) => (id.into(), false),
(_, SolverDefId::AnonConstId(id)) => {
let loc = id.loc(db);
let generic_def = loc.owner.generic_def(db);
return if loc.allow_using_generic_params {
Generics::from_generic_def(db, generic_def, false)
} else {
#[expect(
deprecated,
reason = "`Generics` only exposes an iterator over `GenericParamId`, \
so you cannot exploit the erroneous `crate::generics::Generics`"
)]
Generics {
generics: crate::generics::Generics::empty(generic_def),
additional_param: None,
consider_late_bound: false,
}
};
}
_ => panic!("No generics for {def:?}"),
};
Generics::from_generic_def(db, def, consider_late_bound)
}
#[derive(Debug)]
pub struct Generics<'db> {
generics: crate::generics::Generics<'db>,
/// This is used for builtin derives, specifically `CoercePointee`.
additional_param: Option<GenericParamId>,
consider_late_bound: bool,
}
impl<'db> Generics<'db> {
pub(crate) fn from_generic_def(
db: &'db dyn HirDatabase,
def: GenericDefId,
consider_late_bound: bool,
) -> Generics<'db> {
Generics {
generics: crate::generics::generics(db, def),
additional_param: None,
consider_late_bound,
}
}
pub(crate) fn from_generic_def_plus_one(
db: &'db dyn HirDatabase,
def: GenericDefId,
additional_param: TypeParamId,
consider_late_bound: bool,
) -> Generics<'db> {
Generics {
generics: crate::generics::generics(db, def),
additional_param: Some(additional_param.into()),
consider_late_bound,
}
}
pub(super) fn iter(
&self,
) -> impl Iterator<Item = (GenericParamId, Option<&LifetimeParamData>)> {
self.generics
.iter(self.consider_late_bound)
.map(|(id, data)| {
if let GenericParamDataRef::LifetimeParamData(lt_param) = data {
(id, Some(lt_param))
} else {
(id, None)
}
})
.chain(self.additional_param.map(|param| (param, None)))
}
}
impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics<'db> {
fn count(&self) -> usize {
self.generics.len(self.consider_late_bound) + usize::from(self.additional_param.is_some())
}
}