diff options
Diffstat (limited to 'crates/ra_hir/src/generics.rs')
-rw-r--r-- | crates/ra_hir/src/generics.rs | 190 |
1 files changed, 4 insertions, 186 deletions
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index c35482ae8..f1bf2ee9d 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -1,50 +1,12 @@ | |||
1 | //! Many kinds of items or constructs can have generic parameters: functions, | 1 | //! Temp module to wrap hir_def::generics |
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 | |||
6 | use std::sync::Arc; | 2 | use std::sync::Arc; |
7 | 3 | ||
8 | use hir_def::{ | ||
9 | path::Path, | ||
10 | type_ref::{TypeBound, TypeRef}, | ||
11 | }; | ||
12 | use hir_expand::name::{self, AsName}; | ||
13 | use ra_syntax::ast::{self, DefaultTypeParamOwner, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | ||
14 | |||
15 | use crate::{ | 4 | use crate::{ |
16 | db::{AstDatabase, DefDatabase, HirDatabase}, | 5 | db::DefDatabase, Adt, Const, Container, Enum, EnumVariant, Function, ImplBlock, Struct, Trait, |
17 | Adt, Const, Container, Enum, EnumVariant, Function, HasSource, ImplBlock, Name, Struct, Trait, | ||
18 | TypeAlias, Union, | 6 | TypeAlias, Union, |
19 | }; | 7 | }; |
20 | 8 | ||
21 | /// Data about a generic parameter (to a function, struct, impl, ...). | 9 | pub use hir_def::generics::{GenericParam, GenericParams, WherePredicate}; |
22 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
23 | pub struct GenericParam { | ||
24 | // FIXME: give generic params proper IDs | ||
25 | pub idx: u32, | ||
26 | pub name: Name, | ||
27 | pub default: Option<Path>, | ||
28 | } | ||
29 | |||
30 | /// Data about the generic parameters of a function, struct, impl, etc. | ||
31 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
32 | pub struct GenericParams { | ||
33 | pub(crate) def: GenericDef, | ||
34 | pub(crate) parent_params: Option<Arc<GenericParams>>, | ||
35 | pub(crate) params: Vec<GenericParam>, | ||
36 | pub(crate) where_predicates: Vec<WherePredicate>, | ||
37 | } | ||
38 | |||
39 | /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined | ||
40 | /// where clauses like `where T: Foo + Bar` are turned into multiple of these. | ||
41 | /// It might still result in multiple actual predicates though, because of | ||
42 | /// associated type bindings like `Iterator<Item = u32>`. | ||
43 | #[derive(Clone, PartialEq, Eq, Debug)] | ||
44 | pub struct WherePredicate { | ||
45 | pub(crate) type_ref: TypeRef, | ||
46 | pub(crate) bound: TypeBound, | ||
47 | } | ||
48 | 10 | ||
49 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] | 11 | #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] |
50 | pub enum GenericDef { | 12 | pub enum GenericDef { |
@@ -69,150 +31,6 @@ impl_froms!( | |||
69 | Const | 31 | Const |
70 | ); | 32 | ); |
71 | 33 | ||
72 | impl GenericParams { | ||
73 | pub(crate) fn generic_params_query( | ||
74 | db: &(impl DefDatabase + AstDatabase), | ||
75 | def: GenericDef, | ||
76 | ) -> Arc<GenericParams> { | ||
77 | let parent = match def { | ||
78 | GenericDef::Function(it) => it.container(db).map(GenericDef::from), | ||
79 | GenericDef::TypeAlias(it) => it.container(db).map(GenericDef::from), | ||
80 | GenericDef::Const(it) => it.container(db).map(GenericDef::from), | ||
81 | GenericDef::EnumVariant(it) => Some(it.parent_enum(db).into()), | ||
82 | GenericDef::Adt(_) | GenericDef::Trait(_) => None, | ||
83 | GenericDef::ImplBlock(_) => None, | ||
84 | }; | ||
85 | let mut generics = GenericParams { | ||
86 | def, | ||
87 | params: Vec::new(), | ||
88 | parent_params: parent.map(|p| db.generic_params(p)), | ||
89 | where_predicates: Vec::new(), | ||
90 | }; | ||
91 | let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; | ||
92 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | ||
93 | match def { | ||
94 | GenericDef::Function(it) => generics.fill(&it.source(db).ast, start), | ||
95 | GenericDef::Adt(Adt::Struct(it)) => generics.fill(&it.source(db).ast, start), | ||
96 | GenericDef::Adt(Adt::Union(it)) => generics.fill(&it.source(db).ast, start), | ||
97 | GenericDef::Adt(Adt::Enum(it)) => generics.fill(&it.source(db).ast, start), | ||
98 | GenericDef::Trait(it) => { | ||
99 | // traits get the Self type as an implicit first type parameter | ||
100 | generics.params.push(GenericParam { | ||
101 | idx: start, | ||
102 | name: name::SELF_TYPE, | ||
103 | default: None, | ||
104 | }); | ||
105 | generics.fill(&it.source(db).ast, start + 1); | ||
106 | // add super traits as bounds on Self | ||
107 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | ||
108 | let self_param = TypeRef::Path(name::SELF_TYPE.into()); | ||
109 | generics.fill_bounds(&it.source(db).ast, self_param); | ||
110 | } | ||
111 | GenericDef::TypeAlias(it) => generics.fill(&it.source(db).ast, start), | ||
112 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | ||
113 | // type-parameter, but rather is a type-alias for impl's target | ||
114 | // type, so this is handled by the resolver. | ||
115 | GenericDef::ImplBlock(it) => generics.fill(&it.source(db).ast, start), | ||
116 | GenericDef::EnumVariant(_) | GenericDef::Const(_) => {} | ||
117 | } | ||
118 | |||
119 | Arc::new(generics) | ||
120 | } | ||
121 | |||
122 | fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { | ||
123 | if let Some(params) = node.type_param_list() { | ||
124 | self.fill_params(params, start) | ||
125 | } | ||
126 | if let Some(where_clause) = node.where_clause() { | ||
127 | self.fill_where_predicates(where_clause); | ||
128 | } | ||
129 | } | ||
130 | |||
131 | fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) { | ||
132 | for bound in | ||
133 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | ||
134 | { | ||
135 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | ||
136 | } | ||
137 | } | ||
138 | |||
139 | fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { | ||
140 | for (idx, type_param) in params.type_params().enumerate() { | ||
141 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | ||
142 | // FIXME: Use `Path::from_src` | ||
143 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); | ||
144 | |||
145 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; | ||
146 | self.params.push(param); | ||
147 | |||
148 | let type_ref = TypeRef::Path(name.into()); | ||
149 | self.fill_bounds(&type_param, type_ref); | ||
150 | } | ||
151 | } | ||
152 | |||
153 | fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) { | ||
154 | for pred in where_clause.predicates() { | ||
155 | let type_ref = match pred.type_ref() { | ||
156 | Some(type_ref) => type_ref, | ||
157 | None => continue, | ||
158 | }; | ||
159 | let type_ref = TypeRef::from_ast(type_ref); | ||
160 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | ||
161 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | ||
162 | } | ||
163 | } | ||
164 | } | ||
165 | |||
166 | fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { | ||
167 | if bound.has_question_mark() { | ||
168 | // FIXME: remove this bound | ||
169 | return; | ||
170 | } | ||
171 | let bound = TypeBound::from_ast(bound); | ||
172 | self.where_predicates.push(WherePredicate { type_ref, bound }); | ||
173 | } | ||
174 | |||
175 | pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { | ||
176 | self.params.iter().find(|p| &p.name == name) | ||
177 | } | ||
178 | |||
179 | pub fn count_parent_params(&self) -> usize { | ||
180 | self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0) | ||
181 | } | ||
182 | |||
183 | pub fn count_params_including_parent(&self) -> usize { | ||
184 | let parent_count = self.count_parent_params(); | ||
185 | parent_count + self.params.len() | ||
186 | } | ||
187 | |||
188 | fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) { | ||
189 | if let Some(parent) = &self.parent_params { | ||
190 | parent.for_each_param(f); | ||
191 | } | ||
192 | self.params.iter().for_each(f); | ||
193 | } | ||
194 | |||
195 | pub fn params_including_parent(&self) -> Vec<&GenericParam> { | ||
196 | let mut vec = Vec::with_capacity(self.count_params_including_parent()); | ||
197 | self.for_each_param(&mut |p| vec.push(p)); | ||
198 | vec | ||
199 | } | ||
200 | } | ||
201 | |||
202 | impl GenericDef { | ||
203 | pub(crate) fn resolver(&self, db: &impl HirDatabase) -> crate::Resolver { | ||
204 | match self { | ||
205 | GenericDef::Function(inner) => inner.resolver(db), | ||
206 | GenericDef::Adt(adt) => adt.resolver(db), | ||
207 | GenericDef::Trait(inner) => inner.resolver(db), | ||
208 | GenericDef::TypeAlias(inner) => inner.resolver(db), | ||
209 | GenericDef::ImplBlock(inner) => inner.resolver(db), | ||
210 | GenericDef::EnumVariant(inner) => inner.parent_enum(db).resolver(db), | ||
211 | GenericDef::Const(inner) => inner.resolver(db), | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | |||
216 | impl From<Container> for GenericDef { | 34 | impl From<Container> for GenericDef { |
217 | fn from(c: Container) -> Self { | 35 | fn from(c: Container) -> Self { |
218 | match c { | 36 | match c { |
@@ -231,6 +49,6 @@ where | |||
231 | T: Into<GenericDef> + Copy, | 49 | T: Into<GenericDef> + Copy, |
232 | { | 50 | { |
233 | fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> { | 51 | fn generic_params(self, db: &impl DefDatabase) -> Arc<GenericParams> { |
234 | db.generic_params(self.into()) | 52 | db.generic_params(self.into().into()) |
235 | } | 53 | } |
236 | } | 54 | } |