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, LifetimeRefId, 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: 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 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 #[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 #[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 #[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}