| //! 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()) |
| } |
| } |