diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-21 15:35:51 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2018-11-21 15:35:51 +0000 |
commit | ac874b64550c103249e2b951d92e2f1a8c9a5828 (patch) | |
tree | 50fdd5d9681ff57a5cd15de3c401cd478e6f3ab5 /crates/ra_analysis/src/descriptors/module/nameres.rs | |
parent | 031bc868293539714157e3d93cc338b011f5661d (diff) | |
parent | edeec6a41487e6458a9d96b328c9b784525d8f06 (diff) |
Merge #237
237: This moves parts of completion from ad-hockery to descriptors-based resolve r=matklad a=matklad
Co-authored-by: Aleksey Kladov <[email protected]>
Diffstat (limited to 'crates/ra_analysis/src/descriptors/module/nameres.rs')
-rw-r--r-- | crates/ra_analysis/src/descriptors/module/nameres.rs | 162 |
1 files changed, 54 insertions, 108 deletions
diff --git a/crates/ra_analysis/src/descriptors/module/nameres.rs b/crates/ra_analysis/src/descriptors/module/nameres.rs index c5bf467ca..4c555421d 100644 --- a/crates/ra_analysis/src/descriptors/module/nameres.rs +++ b/crates/ra_analysis/src/descriptors/module/nameres.rs | |||
@@ -1,4 +1,19 @@ | |||
1 | //! Name resolution algorithm | 1 | //! Name resolution algorithm. The end result of the algorithm is `ItemMap`: a |
2 | //! map with maps each module to it's scope: the set of items, visible in the | ||
3 | //! module. That is, we only resolve imports here, name resolution of item | ||
4 | //! bodies will be done in a separate step. | ||
5 | //! | ||
6 | //! Like Rustc, we use an interative per-crate algorithm: we start with scopes | ||
7 | //! containing only directly defined items, and then iteratively resolve | ||
8 | //! imports. | ||
9 | //! | ||
10 | //! To make this work nicely in the IDE scenarios, we place `InputModuleItems` | ||
11 | //! in between raw syntax and name resolution. `InputModuleItems` are computed | ||
12 | //! using only the module's syntax, and it is all directly defined items plus | ||
13 | //! imports. The plain is to make `InputModuleItems` independent of local | ||
14 | //! modifications (that is, typing inside a function shold not change IMIs), | ||
15 | //! such that the results of name resolution can be preserved unless the module | ||
16 | //! structure itself is modified. | ||
2 | use std::{ | 17 | use std::{ |
3 | sync::Arc, | 18 | sync::Arc, |
4 | time::Instant, | 19 | time::Instant, |
@@ -8,13 +23,14 @@ use rustc_hash::FxHashMap; | |||
8 | 23 | ||
9 | use ra_syntax::{ | 24 | use ra_syntax::{ |
10 | SmolStr, SyntaxKind::{self, *}, | 25 | SmolStr, SyntaxKind::{self, *}, |
11 | ast::{self, AstNode, ModuleItemOwner} | 26 | ast::{self, ModuleItemOwner} |
12 | }; | 27 | }; |
13 | 28 | ||
14 | use crate::{ | 29 | use crate::{ |
15 | Cancelable, | 30 | Cancelable, |
16 | loc2id::{DefId, DefLoc}, | 31 | loc2id::{DefId, DefLoc}, |
17 | descriptors::{ | 32 | descriptors::{ |
33 | Path, PathKind, | ||
18 | DescriptorDatabase, | 34 | DescriptorDatabase, |
19 | module::{ModuleId, ModuleTree, ModuleSourceNode}, | 35 | module::{ModuleId, ModuleTree, ModuleSourceNode}, |
20 | }, | 36 | }, |
@@ -32,7 +48,6 @@ pub(crate) struct ItemMap { | |||
32 | #[derive(Debug, Default, PartialEq, Eq, Clone)] | 48 | #[derive(Debug, Default, PartialEq, Eq, Clone)] |
33 | pub(crate) struct ModuleScope { | 49 | pub(crate) struct ModuleScope { |
34 | pub(crate) items: FxHashMap<SmolStr, Resolution>, | 50 | pub(crate) items: FxHashMap<SmolStr, Resolution>, |
35 | pub(crate) import_resolutions: FxHashMap<LocalSyntaxPtr, DefId>, | ||
36 | } | 51 | } |
37 | 52 | ||
38 | /// A set of items and imports declared inside a module, without relation to | 53 | /// A set of items and imports declared inside a module, without relation to |
@@ -44,22 +59,20 @@ pub(crate) struct ModuleScope { | |||
44 | #[derive(Debug, Default, PartialEq, Eq)] | 59 | #[derive(Debug, Default, PartialEq, Eq)] |
45 | pub(crate) struct InputModuleItems { | 60 | pub(crate) struct InputModuleItems { |
46 | items: Vec<ModuleItem>, | 61 | items: Vec<ModuleItem>, |
47 | glob_imports: Vec<Path>, | 62 | imports: Vec<Import>, |
48 | imports: Vec<Path>, | ||
49 | } | 63 | } |
50 | 64 | ||
51 | #[derive(Debug, Clone, PartialEq, Eq)] | 65 | #[derive(Debug, Clone, PartialEq, Eq)] |
52 | struct Path { | 66 | struct Import { |
53 | kind: PathKind, | 67 | path: Path, |
54 | segments: Vec<(LocalSyntaxPtr, SmolStr)>, | 68 | kind: ImportKind, |
55 | } | 69 | } |
56 | 70 | ||
57 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] | 71 | #[derive(Debug, Clone, PartialEq, Eq)] |
58 | enum PathKind { | 72 | enum ImportKind { |
59 | Abs, | 73 | Glob, |
60 | Self_, | 74 | // TODO: make offset independent |
61 | Super, | 75 | Named(LocalSyntaxPtr), |
62 | Crate, | ||
63 | } | 76 | } |
64 | 77 | ||
65 | pub(crate) fn input_module_items( | 78 | pub(crate) fn input_module_items( |
@@ -182,86 +195,16 @@ impl InputModuleItems { | |||
182 | } | 195 | } |
183 | 196 | ||
184 | fn add_use_item(&mut self, item: ast::UseItem) { | 197 | fn add_use_item(&mut self, item: ast::UseItem) { |
185 | if let Some(tree) = item.use_tree() { | 198 | Path::expand_use_item(item, |path, ptr| { |
186 | self.add_use_tree(None, tree); | 199 | let kind = match ptr { |
187 | } | 200 | None => ImportKind::Glob, |
188 | } | 201 | Some(ptr) => ImportKind::Named(ptr), |
189 | |||
190 | fn add_use_tree(&mut self, prefix: Option<Path>, tree: ast::UseTree) { | ||
191 | if let Some(use_tree_list) = tree.use_tree_list() { | ||
192 | let prefix = match tree.path() { | ||
193 | None => prefix, | ||
194 | Some(path) => match convert_path(prefix, path) { | ||
195 | Some(it) => Some(it), | ||
196 | None => return, // TODO: report errors somewhere | ||
197 | }, | ||
198 | }; | 202 | }; |
199 | for tree in use_tree_list.use_trees() { | 203 | self.imports.push(Import { kind, path }) |
200 | self.add_use_tree(prefix.clone(), tree); | 204 | }) |
201 | } | ||
202 | } else { | ||
203 | if let Some(path) = tree.path() { | ||
204 | if let Some(path) = convert_path(prefix, path) { | ||
205 | if tree.has_star() { | ||
206 | &mut self.glob_imports | ||
207 | } else { | ||
208 | &mut self.imports | ||
209 | } | ||
210 | .push(path); | ||
211 | } | ||
212 | } | ||
213 | } | ||
214 | } | 205 | } |
215 | } | 206 | } |
216 | 207 | ||
217 | fn convert_path(prefix: Option<Path>, path: ast::Path) -> Option<Path> { | ||
218 | let prefix = if let Some(qual) = path.qualifier() { | ||
219 | Some(convert_path(prefix, qual)?) | ||
220 | } else { | ||
221 | None | ||
222 | }; | ||
223 | let segment = path.segment()?; | ||
224 | let res = match segment.kind()? { | ||
225 | ast::PathSegmentKind::Name(name) => { | ||
226 | let mut res = prefix.unwrap_or_else(|| Path { | ||
227 | kind: PathKind::Abs, | ||
228 | segments: Vec::with_capacity(1), | ||
229 | }); | ||
230 | let ptr = LocalSyntaxPtr::new(name.syntax()); | ||
231 | res.segments.push((ptr, name.text())); | ||
232 | res | ||
233 | } | ||
234 | ast::PathSegmentKind::CrateKw => { | ||
235 | if prefix.is_some() { | ||
236 | return None; | ||
237 | } | ||
238 | Path { | ||
239 | kind: PathKind::Crate, | ||
240 | segments: Vec::new(), | ||
241 | } | ||
242 | } | ||
243 | ast::PathSegmentKind::SelfKw => { | ||
244 | if prefix.is_some() { | ||
245 | return None; | ||
246 | } | ||
247 | Path { | ||
248 | kind: PathKind::Self_, | ||
249 | segments: Vec::new(), | ||
250 | } | ||
251 | } | ||
252 | ast::PathSegmentKind::SuperKw => { | ||
253 | if prefix.is_some() { | ||
254 | return None; | ||
255 | } | ||
256 | Path { | ||
257 | kind: PathKind::Super, | ||
258 | segments: Vec::new(), | ||
259 | } | ||
260 | } | ||
261 | }; | ||
262 | Some(res) | ||
263 | } | ||
264 | |||
265 | impl ModuleItem { | 208 | impl ModuleItem { |
266 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { | 209 | fn new<'a>(item: impl ast::NameOwner<'a>) -> Option<ModuleItem> { |
267 | let name = item.name()?.text(); | 210 | let name = item.name()?.text(); |
@@ -308,14 +251,16 @@ where | |||
308 | let mut module_items = ModuleScope::default(); | 251 | let mut module_items = ModuleScope::default(); |
309 | 252 | ||
310 | for import in input.imports.iter() { | 253 | for import in input.imports.iter() { |
311 | if let Some((ptr, name)) = import.segments.last() { | 254 | if let Some(name) = import.path.segments.iter().last() { |
312 | module_items.items.insert( | 255 | if let ImportKind::Named(ptr) = import.kind { |
313 | name.clone(), | 256 | module_items.items.insert( |
314 | Resolution { | 257 | name.clone(), |
315 | def_id: None, | 258 | Resolution { |
316 | import_name: Some(*ptr), | 259 | def_id: None, |
317 | }, | 260 | import_name: Some(ptr), |
318 | ); | 261 | }, |
262 | ); | ||
263 | } | ||
319 | } | 264 | } |
320 | } | 265 | } |
321 | 266 | ||
@@ -356,10 +301,15 @@ where | |||
356 | } | 301 | } |
357 | } | 302 | } |
358 | 303 | ||
359 | fn resolve_import(&mut self, module_id: ModuleId, import: &Path) { | 304 | fn resolve_import(&mut self, module_id: ModuleId, import: &Import) { |
360 | let mut curr = match import.kind { | 305 | let ptr = match import.kind { |
306 | ImportKind::Glob => return, | ||
307 | ImportKind::Named(ptr) => ptr, | ||
308 | }; | ||
309 | |||
310 | let mut curr = match import.path.kind { | ||
361 | // TODO: handle extern crates | 311 | // TODO: handle extern crates |
362 | PathKind::Abs => return, | 312 | PathKind::Plain => return, |
363 | PathKind::Self_ => module_id, | 313 | PathKind::Self_ => module_id, |
364 | PathKind::Super => { | 314 | PathKind::Super => { |
365 | match module_id.parent(&self.module_tree) { | 315 | match module_id.parent(&self.module_tree) { |
@@ -371,8 +321,8 @@ where | |||
371 | PathKind::Crate => module_id.crate_root(&self.module_tree), | 321 | PathKind::Crate => module_id.crate_root(&self.module_tree), |
372 | }; | 322 | }; |
373 | 323 | ||
374 | for (i, (ptr, name)) in import.segments.iter().enumerate() { | 324 | for (i, name) in import.path.segments.iter().enumerate() { |
375 | let is_last = i == import.segments.len() - 1; | 325 | let is_last = i == import.path.segments.len() - 1; |
376 | 326 | ||
377 | let def_id = match self.result.per_module[&curr].items.get(name) { | 327 | let def_id = match self.result.per_module[&curr].items.get(name) { |
378 | None => return, | 328 | None => return, |
@@ -382,10 +332,6 @@ where | |||
382 | }, | 332 | }, |
383 | }; | 333 | }; |
384 | 334 | ||
385 | self.update(module_id, |items| { | ||
386 | items.import_resolutions.insert(*ptr, def_id); | ||
387 | }); | ||
388 | |||
389 | if !is_last { | 335 | if !is_last { |
390 | curr = match self.db.id_maps().def_loc(def_id) { | 336 | curr = match self.db.id_maps().def_loc(def_id) { |
391 | DefLoc::Module { id, .. } => id, | 337 | DefLoc::Module { id, .. } => id, |
@@ -395,7 +341,7 @@ where | |||
395 | self.update(module_id, |items| { | 341 | self.update(module_id, |items| { |
396 | let res = Resolution { | 342 | let res = Resolution { |
397 | def_id: Some(def_id), | 343 | def_id: Some(def_id), |
398 | import_name: Some(*ptr), | 344 | import_name: Some(ptr), |
399 | }; | 345 | }; |
400 | items.items.insert(name.clone(), res); | 346 | items.items.insert(name.clone(), res); |
401 | }) | 347 | }) |