hir_def/hir/
generics.rs

1//! Pre-type IR item generics
2use std::{ops, sync::LazyLock};
3
4use hir_expand::name::Name;
5use la_arena::{Arena, Idx, RawIdx};
6use stdx::impl_from;
7use thin_vec::ThinVec;
8use triomphe::Arc;
9
10use crate::{
11    AdtId, ConstParamId, GenericDefId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
12    db::DefDatabase,
13    expr_store::{ExpressionStore, ExpressionStoreSourceMap},
14    type_ref::{ConstRef, LifetimeRefId, TypeBound, TypeRefId},
15};
16
17pub type LocalTypeOrConstParamId = Idx<TypeOrConstParamData>;
18pub type LocalLifetimeParamId = Idx<LifetimeParamData>;
19
20/// Data about a generic type parameter (to a function, struct, impl, ...).
21#[derive(Clone, PartialEq, Eq, Debug, Hash)]
22pub struct TypeParamData {
23    /// [`None`] only if the type ref is an [`TypeRef::ImplTrait`]. FIXME: Might be better to just
24    /// make it always be a value, giving impl trait a special name.
25    pub name: Option<Name>,
26    pub default: Option<TypeRefId>,
27    pub provenance: TypeParamProvenance,
28}
29
30/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
31#[derive(Clone, PartialEq, Eq, Debug, Hash)]
32pub struct LifetimeParamData {
33    pub name: Name,
34}
35
36/// Data about a generic const parameter (to a function, struct, impl, ...).
37#[derive(Clone, PartialEq, Eq, Debug, Hash)]
38pub struct ConstParamData {
39    pub name: Name,
40    pub ty: TypeRefId,
41    pub default: Option<ConstRef>,
42}
43
44#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
45pub enum TypeParamProvenance {
46    TypeParamList,
47    TraitSelf,
48    ArgumentImplTrait,
49}
50
51#[derive(Clone, PartialEq, Eq, Debug, Hash)]
52pub enum TypeOrConstParamData {
53    TypeParamData(TypeParamData),
54    ConstParamData(ConstParamData),
55}
56
57impl TypeOrConstParamData {
58    pub fn name(&self) -> Option<&Name> {
59        match self {
60            TypeOrConstParamData::TypeParamData(it) => it.name.as_ref(),
61            TypeOrConstParamData::ConstParamData(it) => Some(&it.name),
62        }
63    }
64
65    pub fn has_default(&self) -> bool {
66        match self {
67            TypeOrConstParamData::TypeParamData(it) => it.default.is_some(),
68            TypeOrConstParamData::ConstParamData(it) => it.default.is_some(),
69        }
70    }
71
72    pub fn type_param(&self) -> Option<&TypeParamData> {
73        match self {
74            TypeOrConstParamData::TypeParamData(it) => Some(it),
75            TypeOrConstParamData::ConstParamData(_) => None,
76        }
77    }
78
79    pub fn const_param(&self) -> Option<&ConstParamData> {
80        match self {
81            TypeOrConstParamData::TypeParamData(_) => None,
82            TypeOrConstParamData::ConstParamData(it) => Some(it),
83        }
84    }
85
86    pub fn is_trait_self(&self) -> bool {
87        match self {
88            TypeOrConstParamData::TypeParamData(it) => {
89                it.provenance == TypeParamProvenance::TraitSelf
90            }
91            TypeOrConstParamData::ConstParamData(_) => false,
92        }
93    }
94}
95
96impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
97
98#[derive(Clone, PartialEq, Eq, Debug, Hash)]
99pub enum GenericParamData {
100    TypeParamData(TypeParamData),
101    ConstParamData(ConstParamData),
102    LifetimeParamData(LifetimeParamData),
103}
104
105impl GenericParamData {
106    pub fn name(&self) -> Option<&Name> {
107        match self {
108            GenericParamData::TypeParamData(it) => it.name.as_ref(),
109            GenericParamData::ConstParamData(it) => Some(&it.name),
110            GenericParamData::LifetimeParamData(it) => Some(&it.name),
111        }
112    }
113
114    pub fn type_param(&self) -> Option<&TypeParamData> {
115        match self {
116            GenericParamData::TypeParamData(it) => Some(it),
117            _ => None,
118        }
119    }
120
121    pub fn const_param(&self) -> Option<&ConstParamData> {
122        match self {
123            GenericParamData::ConstParamData(it) => Some(it),
124            _ => None,
125        }
126    }
127
128    pub fn lifetime_param(&self) -> Option<&LifetimeParamData> {
129        match self {
130            GenericParamData::LifetimeParamData(it) => Some(it),
131            _ => None,
132        }
133    }
134}
135
136impl_from!(TypeParamData, ConstParamData, LifetimeParamData for GenericParamData);
137
138#[derive(Debug, Clone, Copy)]
139pub enum GenericParamDataRef<'a> {
140    TypeParamData(&'a TypeParamData),
141    ConstParamData(&'a ConstParamData),
142    LifetimeParamData(&'a LifetimeParamData),
143}
144
145/// Data about the generic parameters of a function, struct, impl, etc.
146#[derive(Clone, PartialEq, Eq, Debug, Hash)]
147pub struct GenericParams {
148    pub(crate) type_or_consts: Arena<TypeOrConstParamData>,
149    pub(crate) lifetimes: Arena<LifetimeParamData>,
150    pub(crate) where_predicates: Box<[WherePredicate]>,
151}
152
153impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
154    type Output = TypeOrConstParamData;
155    fn index(&self, index: LocalTypeOrConstParamId) -> &TypeOrConstParamData {
156        &self.type_or_consts[index]
157    }
158}
159
160impl ops::Index<LocalLifetimeParamId> for GenericParams {
161    type Output = LifetimeParamData;
162    fn index(&self, index: LocalLifetimeParamId) -> &LifetimeParamData {
163        &self.lifetimes[index]
164    }
165}
166
167/// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
168/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
169/// It might still result in multiple actual predicates though, because of
170/// associated type bindings like `Iterator<Item = u32>`.
171#[derive(Clone, PartialEq, Eq, Debug, Hash)]
172pub enum WherePredicate {
173    TypeBound { target: TypeRefId, bound: TypeBound },
174    Lifetime { target: LifetimeRefId, bound: LifetimeRefId },
175    ForLifetime { lifetimes: ThinVec<Name>, target: TypeRefId, bound: TypeBound },
176}
177
178static EMPTY: LazyLock<Arc<GenericParams>> = LazyLock::new(|| {
179    Arc::new(GenericParams {
180        type_or_consts: Arena::default(),
181        lifetimes: Arena::default(),
182        where_predicates: Box::default(),
183    })
184});
185
186impl GenericParams {
187    /// The index of the self param in the generic of the non-parent definition.
188    pub(crate) const SELF_PARAM_ID_IN_SELF: la_arena::Idx<TypeOrConstParamData> =
189        LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0));
190
191    pub fn new(db: &dyn DefDatabase, def: GenericDefId) -> Arc<GenericParams> {
192        match def {
193            GenericDefId::AdtId(AdtId::EnumId(it)) => db.enum_signature(it).generic_params.clone(),
194            GenericDefId::AdtId(AdtId::StructId(it)) => {
195                db.struct_signature(it).generic_params.clone()
196            }
197            GenericDefId::AdtId(AdtId::UnionId(it)) => {
198                db.union_signature(it).generic_params.clone()
199            }
200            GenericDefId::ConstId(_) => EMPTY.clone(),
201            GenericDefId::FunctionId(function_id) => {
202                db.function_signature(function_id).generic_params.clone()
203            }
204            GenericDefId::ImplId(impl_id) => db.impl_signature(impl_id).generic_params.clone(),
205            GenericDefId::StaticId(_) => EMPTY.clone(),
206            GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(),
207            GenericDefId::TypeAliasId(type_alias_id) => {
208                db.type_alias_signature(type_alias_id).generic_params.clone()
209            }
210        }
211    }
212
213    pub fn generic_params_and_store(
214        db: &dyn DefDatabase,
215        def: GenericDefId,
216    ) -> (Arc<GenericParams>, Arc<ExpressionStore>) {
217        match def {
218            GenericDefId::AdtId(AdtId::EnumId(id)) => {
219                let sig = db.enum_signature(id);
220                (sig.generic_params.clone(), sig.store.clone())
221            }
222            GenericDefId::AdtId(AdtId::StructId(id)) => {
223                let sig = db.struct_signature(id);
224                (sig.generic_params.clone(), sig.store.clone())
225            }
226            GenericDefId::AdtId(AdtId::UnionId(id)) => {
227                let sig = db.union_signature(id);
228                (sig.generic_params.clone(), sig.store.clone())
229            }
230            GenericDefId::ConstId(id) => {
231                let sig = db.const_signature(id);
232                (EMPTY.clone(), sig.store.clone())
233            }
234            GenericDefId::FunctionId(id) => {
235                let sig = db.function_signature(id);
236                (sig.generic_params.clone(), sig.store.clone())
237            }
238            GenericDefId::ImplId(id) => {
239                let sig = db.impl_signature(id);
240                (sig.generic_params.clone(), sig.store.clone())
241            }
242            GenericDefId::StaticId(id) => {
243                let sig = db.static_signature(id);
244                (EMPTY.clone(), sig.store.clone())
245            }
246            GenericDefId::TraitId(id) => {
247                let sig = db.trait_signature(id);
248                (sig.generic_params.clone(), sig.store.clone())
249            }
250            GenericDefId::TypeAliasId(id) => {
251                let sig = db.type_alias_signature(id);
252                (sig.generic_params.clone(), sig.store.clone())
253            }
254        }
255    }
256
257    pub fn generic_params_and_store_and_source_map(
258        db: &dyn DefDatabase,
259        def: GenericDefId,
260    ) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>) {
261        match def {
262            GenericDefId::AdtId(AdtId::EnumId(id)) => {
263                let (sig, sm) = db.enum_signature_with_source_map(id);
264                (sig.generic_params.clone(), sig.store.clone(), sm)
265            }
266            GenericDefId::AdtId(AdtId::StructId(id)) => {
267                let (sig, sm) = db.struct_signature_with_source_map(id);
268                (sig.generic_params.clone(), sig.store.clone(), sm)
269            }
270            GenericDefId::AdtId(AdtId::UnionId(id)) => {
271                let (sig, sm) = db.union_signature_with_source_map(id);
272                (sig.generic_params.clone(), sig.store.clone(), sm)
273            }
274            GenericDefId::ConstId(id) => {
275                let (sig, sm) = db.const_signature_with_source_map(id);
276                (EMPTY.clone(), sig.store.clone(), sm)
277            }
278            GenericDefId::FunctionId(id) => {
279                let (sig, sm) = db.function_signature_with_source_map(id);
280                (sig.generic_params.clone(), sig.store.clone(), sm)
281            }
282            GenericDefId::ImplId(id) => {
283                let (sig, sm) = db.impl_signature_with_source_map(id);
284                (sig.generic_params.clone(), sig.store.clone(), sm)
285            }
286            GenericDefId::StaticId(id) => {
287                let (sig, sm) = db.static_signature_with_source_map(id);
288                (EMPTY.clone(), sig.store.clone(), sm)
289            }
290            GenericDefId::TraitId(id) => {
291                let (sig, sm) = db.trait_signature_with_source_map(id);
292                (sig.generic_params.clone(), sig.store.clone(), sm)
293            }
294            GenericDefId::TypeAliasId(id) => {
295                let (sig, sm) = db.type_alias_signature_with_source_map(id);
296                (sig.generic_params.clone(), sig.store.clone(), sm)
297            }
298        }
299    }
300
301    /// Number of Generic parameters (type_or_consts + lifetimes)
302    #[inline]
303    pub fn len(&self) -> usize {
304        self.type_or_consts.len() + self.lifetimes.len()
305    }
306
307    #[inline]
308    pub fn len_lifetimes(&self) -> usize {
309        self.lifetimes.len()
310    }
311
312    #[inline]
313    pub fn len_type_or_consts(&self) -> usize {
314        self.type_or_consts.len()
315    }
316
317    #[inline]
318    pub fn is_empty(&self) -> bool {
319        self.len() == 0
320    }
321
322    #[inline]
323    pub fn has_no_predicates(&self) -> bool {
324        self.where_predicates.is_empty()
325    }
326
327    #[inline]
328    pub fn where_predicates(&self) -> &[WherePredicate] {
329        &self.where_predicates
330    }
331
332    /// Iterator of type_or_consts field
333    #[inline]
334    pub fn iter_type_or_consts(
335        &self,
336    ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
337        self.type_or_consts.iter()
338    }
339
340    /// Iterator of lifetimes field
341    #[inline]
342    pub fn iter_lt(
343        &self,
344    ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
345        self.lifetimes.iter()
346    }
347
348    pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
349        self.type_or_consts.iter().find_map(|(id, p)| {
350            if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
351                Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
352            } else {
353                None
354            }
355        })
356    }
357
358    pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
359        self.type_or_consts.iter().find_map(|(id, p)| {
360            if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
361                Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
362            } else {
363                None
364            }
365        })
366    }
367
368    #[inline]
369    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
370        if self.type_or_consts.is_empty() {
371            return None;
372        }
373        matches!(
374            self.type_or_consts[Self::SELF_PARAM_ID_IN_SELF],
375            TypeOrConstParamData::TypeParamData(TypeParamData {
376                provenance: TypeParamProvenance::TraitSelf,
377                ..
378            })
379        )
380        .then(|| Self::SELF_PARAM_ID_IN_SELF)
381    }
382
383    pub fn find_lifetime_by_name(
384        &self,
385        name: &Name,
386        parent: GenericDefId,
387    ) -> Option<LifetimeParamId> {
388        self.lifetimes.iter().find_map(|(id, p)| {
389            if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None }
390        })
391    }
392}