1use 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#[derive(Clone, PartialEq, Eq, Debug, Hash)]
22pub struct TypeParamData {
23 pub name: Option<Name>,
26 pub default: Option<TypeRefId>,
27 pub provenance: TypeParamProvenance,
28}
29
30#[derive(Clone, PartialEq, Eq, Debug, Hash)]
32pub struct LifetimeParamData {
33 pub name: Name,
34}
35
36#[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#[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#[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 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 #[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 #[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 #[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}