diff options
Diffstat (limited to 'crates/ra_hir_def/src/generics.rs')
-rw-r--r-- | crates/ra_hir_def/src/generics.rs | 340 |
1 files changed, 0 insertions, 340 deletions
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs deleted file mode 100644 index 699ba9c92..000000000 --- a/crates/ra_hir_def/src/generics.rs +++ /dev/null | |||
@@ -1,340 +0,0 @@ | |||
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 | ||
4 | //! in rustc. | ||
5 | use std::sync::Arc; | ||
6 | |||
7 | use either::Either; | ||
8 | use hir_expand::{ | ||
9 | name::{name, AsName, Name}, | ||
10 | InFile, | ||
11 | }; | ||
12 | use ra_arena::{map::ArenaMap, Arena}; | ||
13 | use ra_db::FileId; | ||
14 | use ra_prof::profile; | ||
15 | use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner}; | ||
16 | |||
17 | use crate::{ | ||
18 | body::LowerCtx, | ||
19 | child_by_source::ChildBySource, | ||
20 | db::DefDatabase, | ||
21 | dyn_map::DynMap, | ||
22 | keys, | ||
23 | src::HasChildSource, | ||
24 | src::HasSource, | ||
25 | type_ref::{TypeBound, TypeRef}, | ||
26 | AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId, | ||
27 | }; | ||
28 | |||
29 | /// Data about a generic parameter (to a function, struct, impl, ...). | ||
30 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
31 | pub struct TypeParamData { | ||
32 | pub name: Option<Name>, | ||
33 | pub default: Option<TypeRef>, | ||
34 | pub provenance: TypeParamProvenance, | ||
35 | } | ||
36 | |||
37 | #[derive(Copy, Clone, PartialEq, Eq, Debug)] | ||
38 | pub enum TypeParamProvenance { | ||
39 | TypeParamList, | ||
40 | TraitSelf, | ||
41 | ArgumentImplTrait, | ||
42 | } | ||
43 | |||
44 | /// Data about the generic parameters of a function, struct, impl, etc. | ||
45 | #[derive(Clone, PartialEq, Eq, Debug, Default)] | ||
46 | pub struct GenericParams { | ||
47 | pub types: Arena<TypeParamData>, | ||
48 | // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>, | ||
49 | pub where_predicates: Vec<WherePredicate>, | ||
50 | } | ||
51 | |||
52 | /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined | ||
53 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | ||
54 | /// It might still result in multiple actual predicates though, because of | ||
55 | /// associated type bindings like `Iterator<Item = u32>`. | ||
56 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
57 | pub struct WherePredicate { | ||
58 | pub target: WherePredicateTarget, | ||
59 | pub bound: TypeBound, | ||
60 | } | ||
61 | |||
62 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
63 | pub enum WherePredicateTarget { | ||
64 | TypeRef(TypeRef), | ||
65 | /// For desugared where predicates that can directly refer to a type param. | ||
66 | TypeParam(LocalTypeParamId), | ||
67 | } | ||
68 | |||
69 | type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>; | ||
70 | |||
71 | impl GenericParams { | ||
72 | pub(crate) fn generic_params_query( | ||
73 | db: &dyn DefDatabase, | ||
74 | def: GenericDefId, | ||
75 | ) -> Arc<GenericParams> { | ||
76 | let _p = profile("generic_params_query"); | ||
77 | |||
78 | let generics = match def { | ||
79 | GenericDefId::FunctionId(id) => { | ||
80 | let id = id.lookup(db).id; | ||
81 | let tree = db.item_tree(id.file_id); | ||
82 | let item = &tree[id.value]; | ||
83 | tree[item.generic_params].clone() | ||
84 | } | ||
85 | GenericDefId::AdtId(AdtId::StructId(id)) => { | ||
86 | let id = id.lookup(db).id; | ||
87 | let tree = db.item_tree(id.file_id); | ||
88 | let item = &tree[id.value]; | ||
89 | tree[item.generic_params].clone() | ||
90 | } | ||
91 | GenericDefId::AdtId(AdtId::EnumId(id)) => { | ||
92 | let id = id.lookup(db).id; | ||
93 | let tree = db.item_tree(id.file_id); | ||
94 | let item = &tree[id.value]; | ||
95 | tree[item.generic_params].clone() | ||
96 | } | ||
97 | GenericDefId::AdtId(AdtId::UnionId(id)) => { | ||
98 | let id = id.lookup(db).id; | ||
99 | let tree = db.item_tree(id.file_id); | ||
100 | let item = &tree[id.value]; | ||
101 | tree[item.generic_params].clone() | ||
102 | } | ||
103 | GenericDefId::TraitId(id) => { | ||
104 | let id = id.lookup(db).id; | ||
105 | let tree = db.item_tree(id.file_id); | ||
106 | let item = &tree[id.value]; | ||
107 | tree[item.generic_params].clone() | ||
108 | } | ||
109 | GenericDefId::TypeAliasId(id) => { | ||
110 | let id = id.lookup(db).id; | ||
111 | let tree = db.item_tree(id.file_id); | ||
112 | let item = &tree[id.value]; | ||
113 | tree[item.generic_params].clone() | ||
114 | } | ||
115 | GenericDefId::ImplId(id) => { | ||
116 | let id = id.lookup(db).id; | ||
117 | let tree = db.item_tree(id.file_id); | ||
118 | let item = &tree[id.value]; | ||
119 | tree[item.generic_params].clone() | ||
120 | } | ||
121 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(), | ||
122 | }; | ||
123 | Arc::new(generics) | ||
124 | } | ||
125 | |||
126 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | ||
127 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; | ||
128 | let mut sm = ArenaMap::default(); | ||
129 | |||
130 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | ||
131 | let file_id = match def { | ||
132 | GenericDefId::FunctionId(it) => { | ||
133 | let src = it.lookup(db).source(db); | ||
134 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
135 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
136 | // lower `impl Trait` in arguments | ||
137 | let data = db.function_data(it); | ||
138 | for param in &data.params { | ||
139 | generics.fill_implicit_impl_trait_args(param); | ||
140 | } | ||
141 | src.file_id | ||
142 | } | ||
143 | GenericDefId::AdtId(AdtId::StructId(it)) => { | ||
144 | let src = it.lookup(db).source(db); | ||
145 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
146 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
147 | src.file_id | ||
148 | } | ||
149 | GenericDefId::AdtId(AdtId::UnionId(it)) => { | ||
150 | let src = it.lookup(db).source(db); | ||
151 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
152 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
153 | src.file_id | ||
154 | } | ||
155 | GenericDefId::AdtId(AdtId::EnumId(it)) => { | ||
156 | let src = it.lookup(db).source(db); | ||
157 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
158 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
159 | src.file_id | ||
160 | } | ||
161 | GenericDefId::TraitId(it) => { | ||
162 | let src = it.lookup(db).source(db); | ||
163 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
164 | |||
165 | // traits get the Self type as an implicit first type parameter | ||
166 | let self_param_id = generics.types.alloc(TypeParamData { | ||
167 | name: Some(name![Self]), | ||
168 | default: None, | ||
169 | provenance: TypeParamProvenance::TraitSelf, | ||
170 | }); | ||
171 | sm.insert(self_param_id, Either::Left(src.value.clone())); | ||
172 | // add super traits as bounds on Self | ||
173 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | ||
174 | let self_param = TypeRef::Path(name![Self].into()); | ||
175 | generics.fill_bounds(&lower_ctx, &src.value, self_param); | ||
176 | |||
177 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
178 | src.file_id | ||
179 | } | ||
180 | GenericDefId::TypeAliasId(it) => { | ||
181 | let src = it.lookup(db).source(db); | ||
182 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
183 | |||
184 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
185 | src.file_id | ||
186 | } | ||
187 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | ||
188 | // type-parameter, but rather is a type-alias for impl's target | ||
189 | // type, so this is handled by the resolver. | ||
190 | GenericDefId::ImplId(it) => { | ||
191 | let src = it.lookup(db).source(db); | ||
192 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
193 | |||
194 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
195 | src.file_id | ||
196 | } | ||
197 | // We won't be using this ID anyway | ||
198 | GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), | ||
199 | }; | ||
200 | |||
201 | (generics, InFile::new(file_id, sm)) | ||
202 | } | ||
203 | |||
204 | pub(crate) fn fill( | ||
205 | &mut self, | ||
206 | lower_ctx: &LowerCtx, | ||
207 | sm: &mut SourceMap, | ||
208 | node: &dyn GenericParamsOwner, | ||
209 | ) { | ||
210 | if let Some(params) = node.generic_param_list() { | ||
211 | self.fill_params(lower_ctx, sm, params) | ||
212 | } | ||
213 | if let Some(where_clause) = node.where_clause() { | ||
214 | self.fill_where_predicates(lower_ctx, where_clause); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | pub(crate) fn fill_bounds( | ||
219 | &mut self, | ||
220 | lower_ctx: &LowerCtx, | ||
221 | node: &dyn ast::TypeBoundsOwner, | ||
222 | type_ref: TypeRef, | ||
223 | ) { | ||
224 | for bound in | ||
225 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | ||
226 | { | ||
227 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); | ||
228 | } | ||
229 | } | ||
230 | |||
231 | fn fill_params( | ||
232 | &mut self, | ||
233 | lower_ctx: &LowerCtx, | ||
234 | sm: &mut SourceMap, | ||
235 | params: ast::GenericParamList, | ||
236 | ) { | ||
237 | for type_param in params.type_params() { | ||
238 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
239 | // FIXME: Use `Path::from_src` | ||
240 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); | ||
241 | let param = TypeParamData { | ||
242 | name: Some(name.clone()), | ||
243 | default, | ||
244 | provenance: TypeParamProvenance::TypeParamList, | ||
245 | }; | ||
246 | let param_id = self.types.alloc(param); | ||
247 | sm.insert(param_id, Either::Right(type_param.clone())); | ||
248 | |||
249 | let type_ref = TypeRef::Path(name.into()); | ||
250 | self.fill_bounds(&lower_ctx, &type_param, type_ref); | ||
251 | } | ||
252 | } | ||
253 | |||
254 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { | ||
255 | for pred in where_clause.predicates() { | ||
256 | let type_ref = match pred.ty() { | ||
257 | Some(type_ref) => type_ref, | ||
258 | None => continue, | ||
259 | }; | ||
260 | let type_ref = TypeRef::from_ast(lower_ctx, type_ref); | ||
261 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | ||
262 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); | ||
263 | } | ||
264 | } | ||
265 | } | ||
266 | |||
267 | fn add_where_predicate_from_bound( | ||
268 | &mut self, | ||
269 | lower_ctx: &LowerCtx, | ||
270 | bound: ast::TypeBound, | ||
271 | type_ref: TypeRef, | ||
272 | ) { | ||
273 | if bound.question_mark_token().is_some() { | ||
274 | // FIXME: remove this bound | ||
275 | return; | ||
276 | } | ||
277 | let bound = TypeBound::from_ast(lower_ctx, bound); | ||
278 | self.where_predicates | ||
279 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | ||
280 | } | ||
281 | |||
282 | pub(crate) fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) { | ||
283 | type_ref.walk(&mut |type_ref| { | ||
284 | if let TypeRef::ImplTrait(bounds) = type_ref { | ||
285 | let param = TypeParamData { | ||
286 | name: None, | ||
287 | default: None, | ||
288 | provenance: TypeParamProvenance::ArgumentImplTrait, | ||
289 | }; | ||
290 | let param_id = self.types.alloc(param); | ||
291 | for bound in bounds { | ||
292 | self.where_predicates.push(WherePredicate { | ||
293 | target: WherePredicateTarget::TypeParam(param_id), | ||
294 | bound: bound.clone(), | ||
295 | }); | ||
296 | } | ||
297 | } | ||
298 | }); | ||
299 | } | ||
300 | |||
301 | pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { | ||
302 | self.types | ||
303 | .iter() | ||
304 | .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None }) | ||
305 | } | ||
306 | |||
307 | pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> { | ||
308 | self.types.iter().find_map(|(id, p)| { | ||
309 | if p.provenance == TypeParamProvenance::TraitSelf { | ||
310 | Some(id) | ||
311 | } else { | ||
312 | None | ||
313 | } | ||
314 | }) | ||
315 | } | ||
316 | } | ||
317 | |||
318 | impl HasChildSource for GenericDefId { | ||
319 | type ChildId = LocalTypeParamId; | ||
320 | type Value = Either<ast::Trait, ast::TypeParam>; | ||
321 | fn child_source(&self, db: &dyn DefDatabase) -> InFile<SourceMap> { | ||
322 | let (_, sm) = GenericParams::new(db, *self); | ||
323 | sm | ||
324 | } | ||
325 | } | ||
326 | |||
327 | impl ChildBySource for GenericDefId { | ||
328 | fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap { | ||
329 | let mut res = DynMap::default(); | ||
330 | let arena_map = self.child_source(db); | ||
331 | let arena_map = arena_map.as_ref(); | ||
332 | for (local_id, src) in arena_map.value.iter() { | ||
333 | let id = TypeParamId { parent: *self, local_id }; | ||
334 | if let Either::Right(type_param) = src { | ||
335 | res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id) | ||
336 | } | ||
337 | } | ||
338 | res | ||
339 | } | ||
340 | } | ||