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, LifetimeRef, 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: LifetimeRef, bound: LifetimeRef },
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::TraitAliasId(trait_alias_id) => {
207                db.trait_alias_signature(trait_alias_id).generic_params.clone()
208            }
209            GenericDefId::TraitId(trait_id) => db.trait_signature(trait_id).generic_params.clone(),
210            GenericDefId::TypeAliasId(type_alias_id) => {
211                db.type_alias_signature(type_alias_id).generic_params.clone()
212            }
213        }
214    }
215
216    pub fn generic_params_and_store(
217        db: &dyn DefDatabase,
218        def: GenericDefId,
219    ) -> (Arc<GenericParams>, Arc<ExpressionStore>) {
220        match def {
221            GenericDefId::AdtId(AdtId::EnumId(id)) => {
222                let sig = db.enum_signature(id);
223                (sig.generic_params.clone(), sig.store.clone())
224            }
225            GenericDefId::AdtId(AdtId::StructId(id)) => {
226                let sig = db.struct_signature(id);
227                (sig.generic_params.clone(), sig.store.clone())
228            }
229            GenericDefId::AdtId(AdtId::UnionId(id)) => {
230                let sig = db.union_signature(id);
231                (sig.generic_params.clone(), sig.store.clone())
232            }
233            GenericDefId::ConstId(id) => {
234                let sig = db.const_signature(id);
235                (EMPTY.clone(), sig.store.clone())
236            }
237            GenericDefId::FunctionId(id) => {
238                let sig = db.function_signature(id);
239                (sig.generic_params.clone(), sig.store.clone())
240            }
241            GenericDefId::ImplId(id) => {
242                let sig = db.impl_signature(id);
243                (sig.generic_params.clone(), sig.store.clone())
244            }
245            GenericDefId::StaticId(id) => {
246                let sig = db.static_signature(id);
247                (EMPTY.clone(), sig.store.clone())
248            }
249            GenericDefId::TraitAliasId(id) => {
250                let sig = db.trait_alias_signature(id);
251                (sig.generic_params.clone(), sig.store.clone())
252            }
253            GenericDefId::TraitId(id) => {
254                let sig = db.trait_signature(id);
255                (sig.generic_params.clone(), sig.store.clone())
256            }
257            GenericDefId::TypeAliasId(id) => {
258                let sig = db.type_alias_signature(id);
259                (sig.generic_params.clone(), sig.store.clone())
260            }
261        }
262    }
263
264    pub fn generic_params_and_store_and_source_map(
265        db: &dyn DefDatabase,
266        def: GenericDefId,
267    ) -> (Arc<GenericParams>, Arc<ExpressionStore>, Arc<ExpressionStoreSourceMap>) {
268        match def {
269            GenericDefId::AdtId(AdtId::EnumId(id)) => {
270                let (sig, sm) = db.enum_signature_with_source_map(id);
271                (sig.generic_params.clone(), sig.store.clone(), sm)
272            }
273            GenericDefId::AdtId(AdtId::StructId(id)) => {
274                let (sig, sm) = db.struct_signature_with_source_map(id);
275                (sig.generic_params.clone(), sig.store.clone(), sm)
276            }
277            GenericDefId::AdtId(AdtId::UnionId(id)) => {
278                let (sig, sm) = db.union_signature_with_source_map(id);
279                (sig.generic_params.clone(), sig.store.clone(), sm)
280            }
281            GenericDefId::ConstId(id) => {
282                let (sig, sm) = db.const_signature_with_source_map(id);
283                (EMPTY.clone(), sig.store.clone(), sm)
284            }
285            GenericDefId::FunctionId(id) => {
286                let (sig, sm) = db.function_signature_with_source_map(id);
287                (sig.generic_params.clone(), sig.store.clone(), sm)
288            }
289            GenericDefId::ImplId(id) => {
290                let (sig, sm) = db.impl_signature_with_source_map(id);
291                (sig.generic_params.clone(), sig.store.clone(), sm)
292            }
293            GenericDefId::StaticId(id) => {
294                let (sig, sm) = db.static_signature_with_source_map(id);
295                (EMPTY.clone(), sig.store.clone(), sm)
296            }
297            GenericDefId::TraitAliasId(id) => {
298                let (sig, sm) = db.trait_alias_signature_with_source_map(id);
299                (sig.generic_params.clone(), sig.store.clone(), sm)
300            }
301            GenericDefId::TraitId(id) => {
302                let (sig, sm) = db.trait_signature_with_source_map(id);
303                (sig.generic_params.clone(), sig.store.clone(), sm)
304            }
305            GenericDefId::TypeAliasId(id) => {
306                let (sig, sm) = db.type_alias_signature_with_source_map(id);
307                (sig.generic_params.clone(), sig.store.clone(), sm)
308            }
309        }
310    }
311
312    /// Number of Generic parameters (type_or_consts + lifetimes)
313    #[inline]
314    pub fn len(&self) -> usize {
315        self.type_or_consts.len() + self.lifetimes.len()
316    }
317
318    #[inline]
319    pub fn len_lifetimes(&self) -> usize {
320        self.lifetimes.len()
321    }
322
323    #[inline]
324    pub fn len_type_or_consts(&self) -> usize {
325        self.type_or_consts.len()
326    }
327
328    #[inline]
329    pub fn is_empty(&self) -> bool {
330        self.len() == 0
331    }
332
333    #[inline]
334    pub fn no_predicates(&self) -> bool {
335        self.where_predicates.is_empty()
336    }
337
338    #[inline]
339    pub fn where_predicates(&self) -> std::slice::Iter<'_, WherePredicate> {
340        self.where_predicates.iter()
341    }
342
343    /// Iterator of type_or_consts field
344    #[inline]
345    pub fn iter_type_or_consts(
346        &self,
347    ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
348        self.type_or_consts.iter()
349    }
350
351    /// Iterator of lifetimes field
352    #[inline]
353    pub fn iter_lt(
354        &self,
355    ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
356        self.lifetimes.iter()
357    }
358
359    pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
360        self.type_or_consts.iter().find_map(|(id, p)| {
361            if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
362                Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
363            } else {
364                None
365            }
366        })
367    }
368
369    pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
370        self.type_or_consts.iter().find_map(|(id, p)| {
371            if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
372                Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
373            } else {
374                None
375            }
376        })
377    }
378
379    #[inline]
380    pub fn trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
381        if self.type_or_consts.is_empty() {
382            return None;
383        }
384        matches!(
385            self.type_or_consts[Self::SELF_PARAM_ID_IN_SELF],
386            TypeOrConstParamData::TypeParamData(TypeParamData {
387                provenance: TypeParamProvenance::TraitSelf,
388                ..
389            })
390        )
391        .then(|| Self::SELF_PARAM_ID_IN_SELF)
392    }
393
394    pub fn find_lifetime_by_name(
395        &self,
396        name: &Name,
397        parent: GenericDefId,
398    ) -> Option<LifetimeParamId> {
399        self.lifetimes.iter().find_map(|(id, p)| {
400            if &p.name == name { Some(LifetimeParamId { local_id: id, parent }) } else { None }
401        })
402    }
403}