diff options
Diffstat (limited to 'crates/ra_hir_def')
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/scope.rs | 18 | ||||
-rw-r--r-- | crates/ra_hir_def/src/lib.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/resolver.rs | 608 | ||||
-rw-r--r-- | crates/ra_hir_def/src/traits.rs | 9 |
6 files changed, 637 insertions, 2 deletions
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index a5bb60e85..77f091288 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -12,6 +12,7 @@ use ra_syntax::{ | |||
12 | }, | 12 | }, |
13 | AstNode, AstPtr, | 13 | AstNode, AstPtr, |
14 | }; | 14 | }; |
15 | use test_utils::tested_by; | ||
15 | 16 | ||
16 | use crate::{ | 17 | use crate::{ |
17 | body::{Body, BodySourceMap, Expander, PatPtr}, | 18 | body::{Body, BodySourceMap, Expander, PatPtr}, |
@@ -153,6 +154,7 @@ where | |||
153 | None => self.collect_expr_opt(condition.expr()), | 154 | None => self.collect_expr_opt(condition.expr()), |
154 | // if let -- desugar to match | 155 | // if let -- desugar to match |
155 | Some(pat) => { | 156 | Some(pat) => { |
157 | tested_by!(infer_resolve_while_let); | ||
156 | let pat = self.collect_pat(pat); | 158 | let pat = self.collect_pat(pat); |
157 | let match_expr = self.collect_expr_opt(condition.expr()); | 159 | let match_expr = self.collect_expr_opt(condition.expr()); |
158 | let placeholder_pat = self.missing_pat(); | 160 | let placeholder_pat = self.missing_pat(); |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index aeb71ff22..5d7d17231 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -174,7 +174,7 @@ mod tests { | |||
174 | use hir_expand::{name::AsName, Source}; | 174 | use hir_expand::{name::AsName, Source}; |
175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; | 175 | use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; |
176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; | 176 | use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; |
177 | use test_utils::{assert_eq_text, extract_offset}; | 177 | use test_utils::{assert_eq_text, covers, extract_offset}; |
178 | 178 | ||
179 | use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId}; | 179 | use crate::{db::DefDatabase2, test_db::TestDB, FunctionId, ModuleDefId}; |
180 | 180 | ||
@@ -382,4 +382,20 @@ mod tests { | |||
382 | 53, | 382 | 53, |
383 | ); | 383 | ); |
384 | } | 384 | } |
385 | |||
386 | #[test] | ||
387 | fn infer_resolve_while_let() { | ||
388 | covers!(infer_resolve_while_let); | ||
389 | do_check_local_name( | ||
390 | r#" | ||
391 | fn test() { | ||
392 | let foo: Option<f32> = None; | ||
393 | while let Option::Some(spam) = foo { | ||
394 | spam<|> | ||
395 | } | ||
396 | } | ||
397 | "#, | ||
398 | 75, | ||
399 | ); | ||
400 | } | ||
385 | } | 401 | } |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index 0af41de87..d579f5c7e 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -19,6 +19,7 @@ pub mod expr; | |||
19 | pub mod body; | 19 | pub mod body; |
20 | pub mod generics; | 20 | pub mod generics; |
21 | pub mod traits; | 21 | pub mod traits; |
22 | pub mod resolver; | ||
22 | 23 | ||
23 | #[cfg(test)] | 24 | #[cfg(test)] |
24 | mod test_db; | 25 | mod test_db; |
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs index 0b99eac71..65239ca0a 100644 --- a/crates/ra_hir_def/src/marks.rs +++ b/crates/ra_hir_def/src/marks.rs | |||
@@ -11,4 +11,5 @@ test_utils::marks!( | |||
11 | prelude_is_macro_use | 11 | prelude_is_macro_use |
12 | macro_dollar_crate_self | 12 | macro_dollar_crate_self |
13 | macro_dollar_crate_other | 13 | macro_dollar_crate_other |
14 | infer_resolve_while_let | ||
14 | ); | 15 | ); |
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs new file mode 100644 index 000000000..840785baa --- /dev/null +++ b/crates/ra_hir_def/src/resolver.rs | |||
@@ -0,0 +1,608 @@ | |||
1 | //! Name resolution façade. | ||
2 | use std::sync::Arc; | ||
3 | |||
4 | use hir_expand::{ | ||
5 | name::{self, Name}, | ||
6 | MacroDefId, | ||
7 | }; | ||
8 | use ra_db::CrateId; | ||
9 | use rustc_hash::FxHashSet; | ||
10 | |||
11 | use crate::{ | ||
12 | body::scope::{ExprScopes, ScopeId}, | ||
13 | builtin_type::BuiltinType, | ||
14 | db::DefDatabase2, | ||
15 | expr::{ExprId, PatId}, | ||
16 | generics::GenericParams, | ||
17 | nameres::{per_ns::PerNs, CrateDefMap}, | ||
18 | path::{Path, PathKind}, | ||
19 | AdtId, AstItemDef, ConstId, ContainerId, CrateModuleId, DefWithBodyId, EnumId, EnumVariantId, | ||
20 | FunctionId, GenericDefId, ImplId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, | ||
21 | TypeAliasId, UnionId, | ||
22 | }; | ||
23 | |||
24 | #[derive(Debug, Clone, Default)] | ||
25 | pub struct Resolver { | ||
26 | scopes: Vec<Scope>, | ||
27 | } | ||
28 | |||
29 | // FIXME how to store these best | ||
30 | #[derive(Debug, Clone)] | ||
31 | pub(crate) struct ModuleItemMap { | ||
32 | crate_def_map: Arc<CrateDefMap>, | ||
33 | module_id: CrateModuleId, | ||
34 | } | ||
35 | |||
36 | #[derive(Debug, Clone)] | ||
37 | pub(crate) struct ExprScope { | ||
38 | owner: DefWithBodyId, | ||
39 | expr_scopes: Arc<ExprScopes>, | ||
40 | scope_id: ScopeId, | ||
41 | } | ||
42 | |||
43 | #[derive(Debug, Clone)] | ||
44 | pub(crate) enum Scope { | ||
45 | /// All the items and imported names of a module | ||
46 | ModuleScope(ModuleItemMap), | ||
47 | /// Brings the generic parameters of an item into scope | ||
48 | GenericParams { def: GenericDefId, params: Arc<GenericParams> }, | ||
49 | /// Brings `Self` in `impl` block into scope | ||
50 | ImplBlockScope(ImplId), | ||
51 | /// Brings `Self` in enum, struct and union definitions into scope | ||
52 | AdtScope(AdtId), | ||
53 | /// Local bindings | ||
54 | ExprScope(ExprScope), | ||
55 | } | ||
56 | |||
57 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
58 | pub enum TypeNs { | ||
59 | SelfType(ImplId), | ||
60 | GenericParam(u32), | ||
61 | AdtId(AdtId), | ||
62 | AdtSelfType(AdtId), | ||
63 | EnumVariantId(EnumVariantId), | ||
64 | TypeAliasId(TypeAliasId), | ||
65 | BuiltinType(BuiltinType), | ||
66 | TraitId(TraitId), | ||
67 | // Module belong to type ns, but the resolver is used when all module paths | ||
68 | // are fully resolved. | ||
69 | // ModuleId(ModuleId) | ||
70 | } | ||
71 | |||
72 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
73 | pub enum ResolveValueResult { | ||
74 | ValueNs(ValueNs), | ||
75 | Partial(TypeNs, usize), | ||
76 | } | ||
77 | |||
78 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
79 | pub enum ValueNs { | ||
80 | LocalBinding(PatId), | ||
81 | FunctionId(FunctionId), | ||
82 | ConstId(ConstId), | ||
83 | StaticId(StaticId), | ||
84 | StructId(StructId), | ||
85 | EnumVariantId(EnumVariantId), | ||
86 | } | ||
87 | |||
88 | impl Resolver { | ||
89 | /// Resolve known trait from std, like `std::futures::Future` | ||
90 | pub fn resolve_known_trait(&self, db: &impl DefDatabase2, path: &Path) -> Option<TraitId> { | ||
91 | let res = self.resolve_module_path(db, path).take_types()?; | ||
92 | match res { | ||
93 | ModuleDefId::TraitId(it) => Some(it), | ||
94 | _ => None, | ||
95 | } | ||
96 | } | ||
97 | |||
98 | /// Resolve known struct from std, like `std::boxed::Box` | ||
99 | pub fn resolve_known_struct(&self, db: &impl DefDatabase2, path: &Path) -> Option<StructId> { | ||
100 | let res = self.resolve_module_path(db, path).take_types()?; | ||
101 | match res { | ||
102 | ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), | ||
103 | _ => None, | ||
104 | } | ||
105 | } | ||
106 | |||
107 | /// Resolve known enum from std, like `std::result::Result` | ||
108 | pub fn resolve_known_enum(&self, db: &impl DefDatabase2, path: &Path) -> Option<EnumId> { | ||
109 | let res = self.resolve_module_path(db, path).take_types()?; | ||
110 | match res { | ||
111 | ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), | ||
112 | _ => None, | ||
113 | } | ||
114 | } | ||
115 | |||
116 | /// pub only for source-binder | ||
117 | pub fn resolve_module_path(&self, db: &impl DefDatabase2, path: &Path) -> PerNs { | ||
118 | let (item_map, module) = match self.module() { | ||
119 | Some(it) => it, | ||
120 | None => return PerNs::none(), | ||
121 | }; | ||
122 | let (module_res, segment_index) = item_map.resolve_path(db, module, path); | ||
123 | if segment_index.is_some() { | ||
124 | return PerNs::none(); | ||
125 | } | ||
126 | module_res | ||
127 | } | ||
128 | |||
129 | pub fn resolve_path_in_type_ns( | ||
130 | &self, | ||
131 | db: &impl DefDatabase2, | ||
132 | path: &Path, | ||
133 | ) -> Option<(TypeNs, Option<usize>)> { | ||
134 | if path.is_type_relative() { | ||
135 | return None; | ||
136 | } | ||
137 | let first_name = &path.segments.first()?.name; | ||
138 | let skip_to_mod = path.kind != PathKind::Plain; | ||
139 | for scope in self.scopes.iter().rev() { | ||
140 | match scope { | ||
141 | Scope::ExprScope(_) => continue, | ||
142 | Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, | ||
143 | |||
144 | Scope::GenericParams { params, .. } => { | ||
145 | if let Some(param) = params.find_by_name(first_name) { | ||
146 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | ||
147 | return Some((TypeNs::GenericParam(param.idx), idx)); | ||
148 | } | ||
149 | } | ||
150 | Scope::ImplBlockScope(impl_) => { | ||
151 | if first_name == &name::SELF_TYPE { | ||
152 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | ||
153 | return Some((TypeNs::SelfType(*impl_), idx)); | ||
154 | } | ||
155 | } | ||
156 | Scope::AdtScope(adt) => { | ||
157 | if first_name == &name::SELF_TYPE { | ||
158 | let idx = if path.segments.len() == 1 { None } else { Some(1) }; | ||
159 | return Some((TypeNs::AdtSelfType(*adt), idx)); | ||
160 | } | ||
161 | } | ||
162 | Scope::ModuleScope(m) => { | ||
163 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | ||
164 | let res = match module_def.take_types()? { | ||
165 | ModuleDefId::AdtId(it) => TypeNs::AdtId(it), | ||
166 | ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), | ||
167 | |||
168 | ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), | ||
169 | ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), | ||
170 | |||
171 | ModuleDefId::TraitId(it) => TypeNs::TraitId(it), | ||
172 | |||
173 | ModuleDefId::FunctionId(_) | ||
174 | | ModuleDefId::ConstId(_) | ||
175 | | ModuleDefId::StaticId(_) | ||
176 | | ModuleDefId::ModuleId(_) => return None, | ||
177 | }; | ||
178 | return Some((res, idx)); | ||
179 | } | ||
180 | } | ||
181 | } | ||
182 | None | ||
183 | } | ||
184 | |||
185 | pub fn resolve_path_in_type_ns_fully( | ||
186 | &self, | ||
187 | db: &impl DefDatabase2, | ||
188 | path: &Path, | ||
189 | ) -> Option<TypeNs> { | ||
190 | let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; | ||
191 | if unresolved.is_some() { | ||
192 | return None; | ||
193 | } | ||
194 | Some(res) | ||
195 | } | ||
196 | |||
197 | pub fn resolve_path_in_value_ns<'p>( | ||
198 | &self, | ||
199 | db: &impl DefDatabase2, | ||
200 | path: &'p Path, | ||
201 | ) -> Option<ResolveValueResult> { | ||
202 | if path.is_type_relative() { | ||
203 | return None; | ||
204 | } | ||
205 | let n_segments = path.segments.len(); | ||
206 | let tmp = name::SELF_PARAM; | ||
207 | let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; | ||
208 | let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); | ||
209 | for scope in self.scopes.iter().rev() { | ||
210 | match scope { | ||
211 | Scope::AdtScope(_) | ||
212 | | Scope::ExprScope(_) | ||
213 | | Scope::GenericParams { .. } | ||
214 | | Scope::ImplBlockScope(_) | ||
215 | if skip_to_mod => | ||
216 | { | ||
217 | continue | ||
218 | } | ||
219 | |||
220 | Scope::ExprScope(scope) if n_segments <= 1 => { | ||
221 | let entry = scope | ||
222 | .expr_scopes | ||
223 | .entries(scope.scope_id) | ||
224 | .iter() | ||
225 | .find(|entry| entry.name() == first_name); | ||
226 | |||
227 | if let Some(e) = entry { | ||
228 | return Some(ResolveValueResult::ValueNs(ValueNs::LocalBinding(e.pat()))); | ||
229 | } | ||
230 | } | ||
231 | Scope::ExprScope(_) => continue, | ||
232 | |||
233 | Scope::GenericParams { params, .. } if n_segments > 1 => { | ||
234 | if let Some(param) = params.find_by_name(first_name) { | ||
235 | let ty = TypeNs::GenericParam(param.idx); | ||
236 | return Some(ResolveValueResult::Partial(ty, 1)); | ||
237 | } | ||
238 | } | ||
239 | Scope::GenericParams { .. } => continue, | ||
240 | |||
241 | Scope::ImplBlockScope(impl_) if n_segments > 1 => { | ||
242 | if first_name == &name::SELF_TYPE { | ||
243 | let ty = TypeNs::SelfType(*impl_); | ||
244 | return Some(ResolveValueResult::Partial(ty, 1)); | ||
245 | } | ||
246 | } | ||
247 | Scope::AdtScope(adt) if n_segments > 1 => { | ||
248 | if first_name == &name::SELF_TYPE { | ||
249 | let ty = TypeNs::AdtSelfType(*adt); | ||
250 | return Some(ResolveValueResult::Partial(ty, 1)); | ||
251 | } | ||
252 | } | ||
253 | Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue, | ||
254 | |||
255 | Scope::ModuleScope(m) => { | ||
256 | let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); | ||
257 | return match idx { | ||
258 | None => { | ||
259 | let value = match module_def.take_values()? { | ||
260 | ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it), | ||
261 | ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it), | ||
262 | ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it), | ||
263 | ModuleDefId::ConstId(it) => ValueNs::ConstId(it), | ||
264 | ModuleDefId::StaticId(it) => ValueNs::StaticId(it), | ||
265 | |||
266 | ModuleDefId::AdtId(AdtId::EnumId(_)) | ||
267 | | ModuleDefId::AdtId(AdtId::UnionId(_)) | ||
268 | | ModuleDefId::TraitId(_) | ||
269 | | ModuleDefId::TypeAliasId(_) | ||
270 | | ModuleDefId::BuiltinType(_) | ||
271 | | ModuleDefId::ModuleId(_) => return None, | ||
272 | }; | ||
273 | Some(ResolveValueResult::ValueNs(value)) | ||
274 | } | ||
275 | Some(idx) => { | ||
276 | let ty = match module_def.take_types()? { | ||
277 | ModuleDefId::AdtId(it) => TypeNs::AdtId(it), | ||
278 | ModuleDefId::TraitId(it) => TypeNs::TraitId(it), | ||
279 | ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), | ||
280 | ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), | ||
281 | |||
282 | ModuleDefId::ModuleId(_) | ||
283 | | ModuleDefId::FunctionId(_) | ||
284 | | ModuleDefId::EnumVariantId(_) | ||
285 | | ModuleDefId::ConstId(_) | ||
286 | | ModuleDefId::StaticId(_) => return None, | ||
287 | }; | ||
288 | Some(ResolveValueResult::Partial(ty, idx)) | ||
289 | } | ||
290 | }; | ||
291 | } | ||
292 | } | ||
293 | } | ||
294 | None | ||
295 | } | ||
296 | |||
297 | pub fn resolve_path_in_value_ns_fully( | ||
298 | &self, | ||
299 | db: &impl DefDatabase2, | ||
300 | path: &Path, | ||
301 | ) -> Option<ValueNs> { | ||
302 | match self.resolve_path_in_value_ns(db, path)? { | ||
303 | ResolveValueResult::ValueNs(it) => Some(it), | ||
304 | ResolveValueResult::Partial(..) => None, | ||
305 | } | ||
306 | } | ||
307 | |||
308 | pub fn resolve_path_as_macro(&self, db: &impl DefDatabase2, path: &Path) -> Option<MacroDefId> { | ||
309 | let (item_map, module) = self.module()?; | ||
310 | item_map.resolve_path(db, module, path).0.get_macros() | ||
311 | } | ||
312 | |||
313 | pub fn process_all_names(&self, db: &impl DefDatabase2, f: &mut dyn FnMut(Name, ScopeDef)) { | ||
314 | for scope in self.scopes.iter().rev() { | ||
315 | scope.process_names(db, f); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | pub fn traits_in_scope(&self, db: &impl DefDatabase2) -> FxHashSet<TraitId> { | ||
320 | let mut traits = FxHashSet::default(); | ||
321 | for scope in &self.scopes { | ||
322 | if let Scope::ModuleScope(m) = scope { | ||
323 | if let Some(prelude) = m.crate_def_map.prelude() { | ||
324 | let prelude_def_map = db.crate_def_map(prelude.krate); | ||
325 | traits.extend(prelude_def_map[prelude.module_id].scope.traits()); | ||
326 | } | ||
327 | traits.extend(m.crate_def_map[m.module_id].scope.traits()); | ||
328 | } | ||
329 | } | ||
330 | traits | ||
331 | } | ||
332 | |||
333 | fn module(&self) -> Option<(&CrateDefMap, CrateModuleId)> { | ||
334 | self.scopes.iter().rev().find_map(|scope| match scope { | ||
335 | Scope::ModuleScope(m) => Some((&*m.crate_def_map, m.module_id)), | ||
336 | |||
337 | _ => None, | ||
338 | }) | ||
339 | } | ||
340 | |||
341 | pub fn krate(&self) -> Option<CrateId> { | ||
342 | self.module().map(|t| t.0.krate()) | ||
343 | } | ||
344 | |||
345 | pub fn where_predicates_in_scope<'a>( | ||
346 | &'a self, | ||
347 | ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { | ||
348 | self.scopes | ||
349 | .iter() | ||
350 | .filter_map(|scope| match scope { | ||
351 | Scope::GenericParams { params, .. } => Some(params), | ||
352 | _ => None, | ||
353 | }) | ||
354 | .flat_map(|params| params.where_predicates.iter()) | ||
355 | } | ||
356 | |||
357 | pub fn generic_def(&self) -> Option<GenericDefId> { | ||
358 | self.scopes.iter().find_map(|scope| match scope { | ||
359 | Scope::GenericParams { def, .. } => Some(*def), | ||
360 | _ => None, | ||
361 | }) | ||
362 | } | ||
363 | |||
364 | pub fn body_owner(&self) -> Option<DefWithBodyId> { | ||
365 | self.scopes.iter().find_map(|scope| match scope { | ||
366 | Scope::ExprScope(it) => Some(it.owner), | ||
367 | _ => None, | ||
368 | }) | ||
369 | } | ||
370 | } | ||
371 | |||
372 | impl Resolver { | ||
373 | pub(crate) fn push_scope(mut self, scope: Scope) -> Resolver { | ||
374 | self.scopes.push(scope); | ||
375 | self | ||
376 | } | ||
377 | |||
378 | pub(crate) fn push_generic_params_scope( | ||
379 | self, | ||
380 | db: &impl DefDatabase2, | ||
381 | def: GenericDefId, | ||
382 | ) -> Resolver { | ||
383 | let params = db.generic_params(def); | ||
384 | if params.params.is_empty() { | ||
385 | self | ||
386 | } else { | ||
387 | self.push_scope(Scope::GenericParams { def, params }) | ||
388 | } | ||
389 | } | ||
390 | |||
391 | pub(crate) fn push_impl_block_scope(self, impl_block: ImplId) -> Resolver { | ||
392 | self.push_scope(Scope::ImplBlockScope(impl_block)) | ||
393 | } | ||
394 | |||
395 | pub(crate) fn push_module_scope( | ||
396 | self, | ||
397 | crate_def_map: Arc<CrateDefMap>, | ||
398 | module_id: CrateModuleId, | ||
399 | ) -> Resolver { | ||
400 | self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) | ||
401 | } | ||
402 | |||
403 | pub(crate) fn push_expr_scope( | ||
404 | self, | ||
405 | owner: DefWithBodyId, | ||
406 | expr_scopes: Arc<ExprScopes>, | ||
407 | scope_id: ScopeId, | ||
408 | ) -> Resolver { | ||
409 | self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id })) | ||
410 | } | ||
411 | } | ||
412 | |||
413 | pub enum ScopeDef { | ||
414 | PerNs(PerNs), | ||
415 | ImplSelfType(ImplId), | ||
416 | AdtSelfType(AdtId), | ||
417 | GenericParam(u32), | ||
418 | Local(PatId), | ||
419 | } | ||
420 | |||
421 | impl Scope { | ||
422 | fn process_names(&self, db: &impl DefDatabase2, f: &mut dyn FnMut(Name, ScopeDef)) { | ||
423 | match self { | ||
424 | Scope::ModuleScope(m) => { | ||
425 | // FIXME: should we provide `self` here? | ||
426 | // f( | ||
427 | // Name::self_param(), | ||
428 | // PerNs::types(Resolution::Def { | ||
429 | // def: m.module.into(), | ||
430 | // }), | ||
431 | // ); | ||
432 | m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { | ||
433 | f(name.clone(), ScopeDef::PerNs(res.def)); | ||
434 | }); | ||
435 | m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { | ||
436 | f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); | ||
437 | }); | ||
438 | m.crate_def_map.extern_prelude().iter().for_each(|(name, &def)| { | ||
439 | f(name.clone(), ScopeDef::PerNs(PerNs::types(def.into()))); | ||
440 | }); | ||
441 | if let Some(prelude) = m.crate_def_map.prelude() { | ||
442 | let prelude_def_map = db.crate_def_map(prelude.krate); | ||
443 | prelude_def_map[prelude.module_id].scope.entries().for_each(|(name, res)| { | ||
444 | f(name.clone(), ScopeDef::PerNs(res.def)); | ||
445 | }); | ||
446 | } | ||
447 | } | ||
448 | Scope::GenericParams { params, .. } => { | ||
449 | for param in params.params.iter() { | ||
450 | f(param.name.clone(), ScopeDef::GenericParam(param.idx)) | ||
451 | } | ||
452 | } | ||
453 | Scope::ImplBlockScope(i) => { | ||
454 | f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into())); | ||
455 | } | ||
456 | Scope::AdtScope(i) => { | ||
457 | f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into())); | ||
458 | } | ||
459 | Scope::ExprScope(scope) => { | ||
460 | scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { | ||
461 | f(e.name().clone(), ScopeDef::Local(e.pat())); | ||
462 | }); | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | |||
468 | // needs arbitrary_self_types to be a method... or maybe move to the def? | ||
469 | pub fn resolver_for_expr( | ||
470 | db: &impl DefDatabase2, | ||
471 | owner: DefWithBodyId, | ||
472 | expr_id: ExprId, | ||
473 | ) -> Resolver { | ||
474 | let scopes = db.expr_scopes(owner); | ||
475 | resolver_for_scope(db, owner, scopes.scope_for(expr_id)) | ||
476 | } | ||
477 | |||
478 | pub fn resolver_for_scope( | ||
479 | db: &impl DefDatabase2, | ||
480 | owner: DefWithBodyId, | ||
481 | scope_id: Option<ScopeId>, | ||
482 | ) -> Resolver { | ||
483 | let mut r = owner.resolver(db); | ||
484 | let scopes = db.expr_scopes(owner); | ||
485 | let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); | ||
486 | for scope in scope_chain.into_iter().rev() { | ||
487 | r = r.push_expr_scope(owner, Arc::clone(&scopes), scope); | ||
488 | } | ||
489 | r | ||
490 | } | ||
491 | |||
492 | pub trait HasResolver { | ||
493 | /// Builds a resolver for type references inside this def. | ||
494 | fn resolver(self, db: &impl DefDatabase2) -> Resolver; | ||
495 | } | ||
496 | |||
497 | impl HasResolver for ModuleId { | ||
498 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
499 | let def_map = db.crate_def_map(self.krate); | ||
500 | Resolver::default().push_module_scope(def_map, self.module_id) | ||
501 | } | ||
502 | } | ||
503 | |||
504 | impl HasResolver for TraitId { | ||
505 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
506 | self.module(db).resolver(db).push_generic_params_scope(db, self.into()) | ||
507 | } | ||
508 | } | ||
509 | |||
510 | impl HasResolver for AdtId { | ||
511 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
512 | let module = match self { | ||
513 | AdtId::StructId(it) => it.0.module(db), | ||
514 | AdtId::UnionId(it) => it.0.module(db), | ||
515 | AdtId::EnumId(it) => it.module(db), | ||
516 | }; | ||
517 | |||
518 | module | ||
519 | .resolver(db) | ||
520 | .push_generic_params_scope(db, self.into()) | ||
521 | .push_scope(Scope::AdtScope(self.into())) | ||
522 | } | ||
523 | } | ||
524 | |||
525 | impl HasResolver for StructId { | ||
526 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
527 | AdtId::from(self).resolver(db) | ||
528 | } | ||
529 | } | ||
530 | |||
531 | impl HasResolver for UnionId { | ||
532 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
533 | AdtId::from(self).resolver(db) | ||
534 | } | ||
535 | } | ||
536 | |||
537 | impl HasResolver for EnumId { | ||
538 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
539 | AdtId::from(self).resolver(db) | ||
540 | } | ||
541 | } | ||
542 | |||
543 | impl HasResolver for FunctionId { | ||
544 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
545 | self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) | ||
546 | } | ||
547 | } | ||
548 | |||
549 | impl HasResolver for DefWithBodyId { | ||
550 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
551 | match self { | ||
552 | DefWithBodyId::ConstId(c) => c.resolver(db), | ||
553 | DefWithBodyId::FunctionId(f) => f.resolver(db), | ||
554 | DefWithBodyId::StaticId(s) => s.resolver(db), | ||
555 | } | ||
556 | } | ||
557 | } | ||
558 | |||
559 | impl HasResolver for ConstId { | ||
560 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
561 | self.lookup(db).container.resolver(db) | ||
562 | } | ||
563 | } | ||
564 | |||
565 | impl HasResolver for StaticId { | ||
566 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
567 | self.module(db).resolver(db) | ||
568 | } | ||
569 | } | ||
570 | |||
571 | impl HasResolver for TypeAliasId { | ||
572 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
573 | self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into()) | ||
574 | } | ||
575 | } | ||
576 | |||
577 | impl HasResolver for ContainerId { | ||
578 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
579 | match self { | ||
580 | ContainerId::TraitId(it) => it.resolver(db), | ||
581 | ContainerId::ImplId(it) => it.resolver(db), | ||
582 | ContainerId::ModuleId(it) => it.resolver(db), | ||
583 | } | ||
584 | } | ||
585 | } | ||
586 | |||
587 | impl HasResolver for GenericDefId { | ||
588 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
589 | match self { | ||
590 | GenericDefId::FunctionId(inner) => inner.resolver(db), | ||
591 | GenericDefId::AdtId(adt) => adt.resolver(db), | ||
592 | GenericDefId::TraitId(inner) => inner.resolver(db), | ||
593 | GenericDefId::TypeAliasId(inner) => inner.resolver(db), | ||
594 | GenericDefId::ImplId(inner) => inner.resolver(db), | ||
595 | GenericDefId::EnumVariantId(inner) => inner.parent.resolver(db), | ||
596 | GenericDefId::ConstId(inner) => inner.resolver(db), | ||
597 | } | ||
598 | } | ||
599 | } | ||
600 | |||
601 | impl HasResolver for ImplId { | ||
602 | fn resolver(self, db: &impl DefDatabase2) -> Resolver { | ||
603 | self.module(db) | ||
604 | .resolver(db) | ||
605 | .push_generic_params_scope(db, self.into()) | ||
606 | .push_impl_block_scope(self) | ||
607 | } | ||
608 | } | ||
diff --git a/crates/ra_hir_def/src/traits.rs b/crates/ra_hir_def/src/traits.rs index 877d73d66..6c2d5b2a9 100644 --- a/crates/ra_hir_def/src/traits.rs +++ b/crates/ra_hir_def/src/traits.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::ast::{self, NameOwner}; | |||
11 | 11 | ||
12 | use crate::{ | 12 | use crate::{ |
13 | db::DefDatabase2, AssocItemId, AstItemDef, ConstLoc, ContainerId, FunctionLoc, Intern, TraitId, | 13 | db::DefDatabase2, AssocItemId, AstItemDef, ConstLoc, ContainerId, FunctionLoc, Intern, TraitId, |
14 | TypeAliasLoc, | 14 | TypeAliasId, TypeAliasLoc, |
15 | }; | 15 | }; |
16 | 16 | ||
17 | #[derive(Debug, Clone, PartialEq, Eq)] | 17 | #[derive(Debug, Clone, PartialEq, Eq)] |
@@ -56,4 +56,11 @@ impl TraitData { | |||
56 | }; | 56 | }; |
57 | Arc::new(TraitData { name, items, auto }) | 57 | Arc::new(TraitData { name, items, auto }) |
58 | } | 58 | } |
59 | |||
60 | pub fn associated_types(&self) -> impl Iterator<Item = TypeAliasId> + '_ { | ||
61 | self.items.iter().filter_map(|item| match item { | ||
62 | AssocItemId::TypeAliasId(t) => Some(*t), | ||
63 | _ => None, | ||
64 | }) | ||
65 | } | ||
59 | } | 66 | } |