aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_def/src/generics.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir_def/src/generics.rs')
-rw-r--r--crates/ra_hir_def/src/generics.rs340
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.
5use std::sync::Arc;
6
7use either::Either;
8use hir_expand::{
9 name::{name, AsName, Name},
10 InFile,
11};
12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId;
14use ra_prof::profile;
15use ra_syntax::ast::{self, GenericParamsOwner, NameOwner, TypeBoundsOwner};
16
17use 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)]
31pub 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)]
38pub 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)]
46pub 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)]
57pub struct WherePredicate {
58 pub target: WherePredicateTarget,
59 pub bound: TypeBound,
60}
61
62#[derive(Clone, PartialEq, Eq, Debug)]
63pub enum WherePredicateTarget {
64 TypeRef(TypeRef),
65 /// For desugared where predicates that can directly refer to a type param.
66 TypeParam(LocalTypeParamId),
67}
68
69type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>;
70
71impl 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
318impl 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
327impl 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}