1 //! Many kinds of items or constructs can have generic parameters: functions,
2 //! structs, impls, traits, etc. This module provides a common HIR for these
3 //! generic parameters. See also the `Generics` type and the `generics_of` query
7 use arena::{map::ArenaMap, Arena};
11 name::{name, AsName, Name},
14 use syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
18 child_by_source::ChildBySource,
22 src::{HasChildSource, HasSource},
23 type_ref::{LifetimeRef, TypeBound, TypeRef},
24 AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup,
28 /// Data about a generic parameter (to a function, struct, impl, ...).
29 #[derive(Clone, PartialEq, Eq, Debug)]
30 pub struct TypeParamData {
31 pub name: Option<Name>,
32 pub default: Option<TypeRef>,
33 pub provenance: TypeParamProvenance,
36 /// Data about a generic parameter (to a function, struct, impl, ...).
37 #[derive(Clone, PartialEq, Eq, Debug)]
38 pub struct LifetimeParamData {
42 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
43 pub enum TypeParamProvenance {
49 /// Data about the generic parameters of a function, struct, impl, etc.
50 #[derive(Clone, PartialEq, Eq, Debug, Default)]
51 pub struct GenericParams {
52 pub types: Arena<TypeParamData>,
53 pub lifetimes: Arena<LifetimeParamData>,
54 pub where_predicates: Vec<WherePredicate>,
57 /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
58 /// where clauses like `where T: Foo + Bar` are turned into multiple of these.
59 /// It might still result in multiple actual predicates though, because of
60 /// associated type bindings like `Iterator<Item = u32>`.
61 #[derive(Clone, PartialEq, Eq, Debug)]
62 pub enum WherePredicate {
63 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
64 Lifetime { target: LifetimeRef, bound: LifetimeRef },
65 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
68 #[derive(Clone, PartialEq, Eq, Debug)]
69 pub enum WherePredicateTypeTarget {
71 /// For desugared where predicates that can directly refer to a type param.
72 TypeParam(LocalTypeParamId),
76 pub(crate) struct SourceMap {
77 pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
78 lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
82 pub(crate) fn generic_params_query(
85 ) -> Arc<GenericParams> {
86 let _p = profile::span("generic_params_query");
88 let generics = match def {
89 GenericDefId::FunctionId(id) => {
90 let id = id.lookup(db).id;
91 let tree = db.item_tree(id.file_id);
92 let item = &tree[id.value];
93 tree[item.generic_params].clone()
95 GenericDefId::AdtId(AdtId::StructId(id)) => {
96 let id = id.lookup(db).id;
97 let tree = db.item_tree(id.file_id);
98 let item = &tree[id.value];
99 tree[item.generic_params].clone()
101 GenericDefId::AdtId(AdtId::EnumId(id)) => {
102 let id = id.lookup(db).id;
103 let tree = db.item_tree(id.file_id);
104 let item = &tree[id.value];
105 tree[item.generic_params].clone()
107 GenericDefId::AdtId(AdtId::UnionId(id)) => {
108 let id = id.lookup(db).id;
109 let tree = db.item_tree(id.file_id);
110 let item = &tree[id.value];
111 tree[item.generic_params].clone()
113 GenericDefId::TraitId(id) => {
114 let id = id.lookup(db).id;
115 let tree = db.item_tree(id.file_id);
116 let item = &tree[id.value];
117 tree[item.generic_params].clone()
119 GenericDefId::TypeAliasId(id) => {
120 let id = id.lookup(db).id;
121 let tree = db.item_tree(id.file_id);
122 let item = &tree[id.value];
123 tree[item.generic_params].clone()
125 GenericDefId::ImplId(id) => {
126 let id = id.lookup(db).id;
127 let tree = db.item_tree(id.file_id);
128 let item = &tree[id.value];
129 tree[item.generic_params].clone()
131 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
136 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
137 let mut generics = GenericParams::default();
138 let mut sm = SourceMap::default();
140 // FIXME: add `: Sized` bound for everything except for `Self` in traits
141 let file_id = match def {
142 GenericDefId::FunctionId(it) => {
143 let src = it.lookup(db).source(db);
144 let lower_ctx = LowerCtx::new(db, src.file_id);
145 generics.fill(&lower_ctx, &mut sm, &src.value);
146 // lower `impl Trait` in arguments
147 let data = db.function_data(it);
148 for param in &data.params {
149 generics.fill_implicit_impl_trait_args(param);
153 GenericDefId::AdtId(AdtId::StructId(it)) => {
154 let src = it.lookup(db).source(db);
155 let lower_ctx = LowerCtx::new(db, src.file_id);
156 generics.fill(&lower_ctx, &mut sm, &src.value);
159 GenericDefId::AdtId(AdtId::UnionId(it)) => {
160 let src = it.lookup(db).source(db);
161 let lower_ctx = LowerCtx::new(db, src.file_id);
162 generics.fill(&lower_ctx, &mut sm, &src.value);
165 GenericDefId::AdtId(AdtId::EnumId(it)) => {
166 let src = it.lookup(db).source(db);
167 let lower_ctx = LowerCtx::new(db, src.file_id);
168 generics.fill(&lower_ctx, &mut sm, &src.value);
171 GenericDefId::TraitId(it) => {
172 let src = it.lookup(db).source(db);
173 let lower_ctx = LowerCtx::new(db, src.file_id);
175 // traits get the Self type as an implicit first type parameter
176 let self_param_id = generics.types.alloc(TypeParamData {
177 name: Some(name![Self]),
179 provenance: TypeParamProvenance::TraitSelf,
181 sm.type_params.insert(self_param_id, Either::Left(src.value.clone()));
182 // add super traits as bounds on Self
183 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
184 let self_param = TypeRef::Path(name![Self].into());
185 generics.fill_bounds(&lower_ctx, &src.value, Either::Left(self_param));
187 generics.fill(&lower_ctx, &mut sm, &src.value);
190 GenericDefId::TypeAliasId(it) => {
191 let src = it.lookup(db).source(db);
192 let lower_ctx = LowerCtx::new(db, src.file_id);
194 generics.fill(&lower_ctx, &mut sm, &src.value);
197 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
198 // type-parameter, but rather is a type-alias for impl's target
199 // type, so this is handled by the resolver.
200 GenericDefId::ImplId(it) => {
201 let src = it.lookup(db).source(db);
202 let lower_ctx = LowerCtx::new(db, src.file_id);
204 generics.fill(&lower_ctx, &mut sm, &src.value);
207 // We won't be using this ID anyway
208 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
211 (generics, InFile::new(file_id, sm))
216 lower_ctx: &LowerCtx,
218 node: &dyn GenericParamsOwner,
220 if let Some(params) = node.generic_param_list() {
221 self.fill_params(lower_ctx, sm, params)
223 if let Some(where_clause) = node.where_clause() {
224 self.fill_where_predicates(lower_ctx, where_clause);
228 pub(crate) fn fill_bounds(
230 lower_ctx: &LowerCtx,
231 node: &dyn ast::TypeBoundsOwner,
232 target: Either<TypeRef, LifetimeRef>,
235 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
237 self.add_where_predicate_from_bound(lower_ctx, bound, None, target.clone());
243 lower_ctx: &LowerCtx,
245 params: ast::GenericParamList,
247 for type_param in params.type_params() {
248 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
249 // FIXME: Use `Path::from_src`
250 let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it));
251 let param = TypeParamData {
252 name: Some(name.clone()),
254 provenance: TypeParamProvenance::TypeParamList,
256 let param_id = self.types.alloc(param);
257 sm.type_params.insert(param_id, Either::Right(type_param.clone()));
259 let type_ref = TypeRef::Path(name.into());
260 self.fill_bounds(&lower_ctx, &type_param, Either::Left(type_ref));
262 for lifetime_param in params.lifetime_params() {
264 lifetime_param.lifetime().map_or_else(Name::missing, |lt| Name::new_lifetime(<));
265 let param = LifetimeParamData { name: name.clone() };
266 let param_id = self.lifetimes.alloc(param);
267 sm.lifetime_params.insert(param_id, lifetime_param.clone());
268 let lifetime_ref = LifetimeRef::new_name(name);
269 self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
273 fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
274 for pred in where_clause.predicates() {
275 let target = if let Some(type_ref) = pred.ty() {
276 Either::Left(TypeRef::from_ast(lower_ctx, type_ref))
277 } else if let Some(lifetime) = pred.lifetime() {
278 Either::Right(LifetimeRef::new(&lifetime))
283 let lifetimes: Option<Box<_>> = pred.generic_param_list().map(|param_list| {
284 // Higher-Ranked Trait Bounds
287 .map(|lifetime_param| {
290 .map_or_else(Name::missing, |lt| Name::new_lifetime(<))
294 for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) {
295 self.add_where_predicate_from_bound(
305 fn add_where_predicate_from_bound(
307 lower_ctx: &LowerCtx,
308 bound: ast::TypeBound,
309 hrtb_lifetimes: Option<&Box<[Name]>>,
310 target: Either<TypeRef, LifetimeRef>,
312 if bound.question_mark_token().is_some() {
313 // FIXME: remove this bound
316 let bound = TypeBound::from_ast(lower_ctx, bound);
317 let predicate = match (target, bound) {
318 (Either::Left(type_ref), bound) => match hrtb_lifetimes {
319 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
320 lifetimes: hrtb_lifetimes.clone(),
321 target: WherePredicateTypeTarget::TypeRef(type_ref),
324 None => WherePredicate::TypeBound {
325 target: WherePredicateTypeTarget::TypeRef(type_ref),
329 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
330 WherePredicate::Lifetime { target: lifetime, bound }
334 self.where_predicates.push(predicate);
337 pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
338 type_ref.walk(&mut |type_ref| {
339 if let TypeRef::ImplTrait(bounds) = type_ref {
340 let param = TypeParamData {
343 provenance: TypeParamProvenance::ArgumentImplTrait,
345 let param_id = self.types.alloc(param);
346 for bound in bounds {
347 self.where_predicates.push(WherePredicate::TypeBound {
348 target: WherePredicateTypeTarget::TypeParam(param_id),
349 bound: bound.clone(),
356 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
359 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
362 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
363 self.types.iter().find_map(|(id, p)| {
364 if p.provenance == TypeParamProvenance::TraitSelf {
373 impl HasChildSource<LocalTypeParamId> for GenericDefId {
374 type Value = Either<ast::Trait, ast::TypeParam>;
377 db: &dyn DefDatabase,
378 ) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> {
379 GenericParams::new(db, *self).1.map(|source_maps| source_maps.type_params)
383 impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
384 type Value = ast::LifetimeParam;
387 db: &dyn DefDatabase,
388 ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
389 GenericParams::new(db, *self).1.map(|source_maps| source_maps.lifetime_params)
393 impl ChildBySource for GenericDefId {
394 fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
395 let mut res = DynMap::default();
396 let (_, sm) = GenericParams::new(db, *self);
398 let sm = sm.as_ref();
399 for (local_id, src) in sm.value.type_params.iter() {
400 let id = TypeParamId { parent: *self, local_id };
401 if let Either::Right(type_param) = src {
402 res[keys::TYPE_PARAM].insert(sm.with_value(type_param.clone()), id)
405 for (local_id, src) in sm.value.lifetime_params.iter() {
406 let id = LifetimeParamId { parent: *self, local_id };
407 res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id);