aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorian Diebold <[email protected]>2019-01-07 18:40:31 +0000
committerFlorian Diebold <[email protected]>2019-01-08 11:53:31 +0000
commitdc186c0fcca5155a4b11aeb8b48ebcf68ef9c82c (patch)
treed79ff83ca775ab4d298ad8f18e9de442a96a3531
parente2592cf09087ae0a6cad5b588cbf1ab1161440e9 (diff)
Import fixpoint loop for name resolution
-rw-r--r--crates/ra_hir/src/nameres.rs47
-rw-r--r--crates/ra_hir/src/nameres/tests.rs31
2 files changed, 62 insertions, 16 deletions
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index 9a412bc82..bd66b5d2c 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -16,7 +16,7 @@
16//! structure itself is modified. 16//! structure itself is modified.
17use std::sync::Arc; 17use std::sync::Arc;
18 18
19use rustc_hash::FxHashMap; 19use rustc_hash::{FxHashMap, FxHashSet};
20use ra_syntax::{ 20use ra_syntax::{
21 TextRange, 21 TextRange,
22 SyntaxKind::{self, *}, 22 SyntaxKind::{self, *},
@@ -295,6 +295,7 @@ pub(crate) struct Resolver<'a, DB> {
295 input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, 295 input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
296 source_root: SourceRootId, 296 source_root: SourceRootId,
297 module_tree: Arc<ModuleTree>, 297 module_tree: Arc<ModuleTree>,
298 processed_imports: FxHashSet<(ModuleId, usize)>,
298 result: ItemMap, 299 result: ItemMap,
299} 300}
300 301
@@ -313,6 +314,7 @@ where
313 input, 314 input,
314 source_root, 315 source_root,
315 module_tree, 316 module_tree,
317 processed_imports: FxHashSet::default(),
316 result: ItemMap::default(), 318 result: ItemMap::default(),
317 } 319 }
318 } 320 }
@@ -322,9 +324,16 @@ where
322 self.populate_module(module_id, Arc::clone(items))?; 324 self.populate_module(module_id, Arc::clone(items))?;
323 } 325 }
324 326
325 for &module_id in self.input.keys() { 327 loop {
326 self.db.check_canceled()?; 328 let processed_imports_count = self.processed_imports.len();
327 self.resolve_imports(module_id)?; 329 for &module_id in self.input.keys() {
330 self.db.check_canceled()?;
331 self.resolve_imports(module_id)?;
332 }
333 if processed_imports_count == self.processed_imports.len() {
334 // no new imports resolved
335 break;
336 }
328 } 337 }
329 Ok(self.result) 338 Ok(self.result)
330 } 339 }
@@ -418,15 +427,21 @@ where
418 } 427 }
419 428
420 fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { 429 fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> {
421 for import in self.input[&module_id].imports.iter() { 430 for (i, import) in self.input[&module_id].imports.iter().enumerate() {
422 self.resolve_import(module_id, import)?; 431 if self.processed_imports.contains(&(module_id, i)) {
432 // already done
433 continue;
434 }
435 if self.resolve_import(module_id, import)? {
436 self.processed_imports.insert((module_id, i));
437 }
423 } 438 }
424 Ok(()) 439 Ok(())
425 } 440 }
426 441
427 fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { 442 fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<bool> {
428 let ptr = match import.kind { 443 let ptr = match import.kind {
429 ImportKind::Glob => return Ok(()), 444 ImportKind::Glob => return Ok(false),
430 ImportKind::Named(ptr) => ptr, 445 ImportKind::Named(ptr) => ptr,
431 }; 446 };
432 447
@@ -436,7 +451,7 @@ where
436 match module_id.parent(&self.module_tree) { 451 match module_id.parent(&self.module_tree) {
437 Some(it) => it, 452 Some(it) => it,
438 // TODO: error 453 // TODO: error
439 None => return Ok(()), 454 None => return Ok(true), // this can't suddenly resolve if we just resolve some other imports
440 } 455 }
441 } 456 }
442 PathKind::Crate => module_id.crate_root(&self.module_tree), 457 PathKind::Crate => module_id.crate_root(&self.module_tree),
@@ -447,14 +462,14 @@ where
447 462
448 let def_id = match self.result.per_module[&curr].items.get(name) { 463 let def_id = match self.result.per_module[&curr].items.get(name) {
449 Some(res) if !res.def_id.is_none() => res.def_id, 464 Some(res) if !res.def_id.is_none() => res.def_id,
450 _ => return Ok(()), 465 _ => return Ok(false),
451 }; 466 };
452 467
453 if !is_last { 468 if !is_last {
454 let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { 469 let type_def_id = if let Some(d) = def_id.take(Namespace::Types) {
455 d 470 d
456 } else { 471 } else {
457 return Ok(()); 472 return Ok(false);
458 }; 473 };
459 curr = match type_def_id.loc(self.db) { 474 curr = match type_def_id.loc(self.db) {
460 DefLoc { 475 DefLoc {
@@ -479,12 +494,14 @@ where
479 import: Some(ptr), 494 import: Some(ptr),
480 }; 495 };
481 items.items.insert(name.clone(), res); 496 items.items.insert(name.clone(), res);
482 }) 497 });
498 return Ok(true);
499 } else {
500 return Ok(false);
483 } 501 }
484 return Ok(());
485 } 502 }
486 } 503 }
487 _ => return Ok(()), 504 _ => return Ok(true), // this resolved to a non-module, so the path won't ever resolve
488 } 505 }
489 } else { 506 } else {
490 self.update(module_id, |items| { 507 self.update(module_id, |items| {
@@ -496,7 +513,7 @@ where
496 }) 513 })
497 } 514 }
498 } 515 }
499 Ok(()) 516 Ok(true)
500 } 517 }
501 518
502 fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { 519 fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index dcbe65aec..04faec4fb 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -35,7 +35,7 @@ fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected:
35 .map(|it| it.trim()) 35 .map(|it| it.trim())
36 .collect::<Vec<_>>() 36 .collect::<Vec<_>>()
37 .join("\n"); 37 .join("\n");
38 assert_eq_text!(&actual, &expected); 38 assert_eq_text!(&expected, &actual);
39 39
40 fn dump_resolution(resolution: &hir::Resolution) -> &'static str { 40 fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
41 match ( 41 match (
@@ -78,6 +78,35 @@ fn item_map_smoke_test() {
78} 78}
79 79
80#[test] 80#[test]
81fn re_exports() {
82 let (item_map, module_id) = item_map(
83 "
84 //- /lib.rs
85 mod foo;
86
87 use self::foo::Baz;
88 <|>
89
90 //- /foo/mod.rs
91 pub mod bar;
92
93 pub use self::bar::Baz;
94
95 //- /foo/bar.rs
96 pub struct Baz;
97 ",
98 );
99 check_module_item_map(
100 &item_map,
101 module_id,
102 "
103 Baz: t v
104 foo: t
105 ",
106 );
107}
108
109#[test]
81fn item_map_contains_items_from_expansions() { 110fn item_map_contains_items_from_expansions() {
82 let (item_map, module_id) = item_map( 111 let (item_map, module_id) = item_map(
83 " 112 "