Skip to main content

hir_ty/next_solver/
generics.rs

1//! Things related to generics in the next-trait-solver.
2
3use hir_def::{
4    GenericDefId, GenericParamId, TypeParamId,
5    hir::generics::{GenericParamDataRef, LifetimeParamData},
6};
7
8use crate::db::HirDatabase;
9
10use super::{Ctor, DbInterner, SolverDefId};
11
12pub(crate) fn generics<'db>(interner: DbInterner<'db>, def: SolverDefId<'db>) -> Generics<'db> {
13    let db = interner.db;
14    let (def, consider_late_bound) = match (def.try_into(), def) {
15        (Ok(def), _) => (def, false),
16        (_, SolverDefId::InternedOpaqueTyId(id)) => match id.loc(db) {
17            crate::ImplTraitId::ReturnTypeImplTrait(function_id, _) => (function_id.into(), true),
18            crate::ImplTraitId::TypeAliasImplTrait(type_alias_id, _) => {
19                (type_alias_id.into(), true)
20            }
21        },
22        (_, SolverDefId::BuiltinDeriveImplId(id)) => {
23            return crate::builtin_derive::generics_of(interner, id);
24        }
25        (_, SolverDefId::EnumVariantId(id) | SolverDefId::Ctor(Ctor::Enum(id))) => {
26            (id.loc(db).parent.into(), false)
27        }
28        (_, SolverDefId::Ctor(Ctor::Struct(id))) => (id.into(), false),
29        (_, SolverDefId::AnonConstId(id)) => {
30            let loc = id.loc(db);
31            let generic_def = loc.owner.generic_def(db);
32            return if loc.allow_using_generic_params {
33                Generics::from_generic_def(db, generic_def, false)
34            } else {
35                #[expect(
36                    deprecated,
37                    reason = "`Generics` only exposes an iterator over `GenericParamId`, \
38                        so you cannot exploit the erroneous `crate::generics::Generics`"
39                )]
40                Generics {
41                    generics: crate::generics::Generics::empty(generic_def),
42                    additional_param: None,
43                    consider_late_bound: false,
44                }
45            };
46        }
47        _ => panic!("No generics for {def:?}"),
48    };
49
50    Generics::from_generic_def(db, def, consider_late_bound)
51}
52
53#[derive(Debug)]
54pub struct Generics<'db> {
55    generics: crate::generics::Generics<'db>,
56    /// This is used for builtin derives, specifically `CoercePointee`.
57    additional_param: Option<GenericParamId>,
58    consider_late_bound: bool,
59}
60
61impl<'db> Generics<'db> {
62    pub(crate) fn from_generic_def(
63        db: &'db dyn HirDatabase,
64        def: GenericDefId,
65        consider_late_bound: bool,
66    ) -> Generics<'db> {
67        Generics {
68            generics: crate::generics::generics(db, def),
69            additional_param: None,
70            consider_late_bound,
71        }
72    }
73
74    pub(crate) fn from_generic_def_plus_one(
75        db: &'db dyn HirDatabase,
76        def: GenericDefId,
77        additional_param: TypeParamId,
78        consider_late_bound: bool,
79    ) -> Generics<'db> {
80        Generics {
81            generics: crate::generics::generics(db, def),
82            additional_param: Some(additional_param.into()),
83            consider_late_bound,
84        }
85    }
86
87    pub(super) fn iter(
88        &self,
89    ) -> impl Iterator<Item = (GenericParamId, Option<&LifetimeParamData>)> {
90        self.generics
91            .iter(self.consider_late_bound)
92            .map(|(id, data)| {
93                if let GenericParamDataRef::LifetimeParamData(lt_param) = data {
94                    (id, Some(lt_param))
95                } else {
96                    (id, None)
97                }
98            })
99            .chain(self.additional_param.zip(None))
100    }
101}
102
103impl<'db> rustc_type_ir::inherent::GenericsOf<DbInterner<'db>> for Generics<'db> {
104    fn count(&self) -> usize {
105        self.generics.len(self.consider_late_bound) + usize::from(self.additional_param.is_some())
106    }
107}