455: Import fixpoint loop for name resolution r=matklad a=flodiebold

This implements reexports, so only the glob import part of #231 remains.

Co-authored-by: Florian Diebold <flodiebold@gmail.com>
This commit is contained in:
bors[bot] 2019-01-08 12:02:06 +00:00
commit 3bb1cb7017
2 changed files with 62 additions and 16 deletions

View file

@ -16,7 +16,7 @@
//! structure itself is modified. //! structure itself is modified.
use std::sync::Arc; use std::sync::Arc;
use rustc_hash::FxHashMap; use rustc_hash::{FxHashMap, FxHashSet};
use ra_syntax::{ use ra_syntax::{
TextRange, TextRange,
SyntaxKind::{self, *}, SyntaxKind::{self, *},
@ -295,6 +295,7 @@ pub(crate) struct Resolver<'a, DB> {
input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>, input: &'a FxHashMap<ModuleId, Arc<InputModuleItems>>,
source_root: SourceRootId, source_root: SourceRootId,
module_tree: Arc<ModuleTree>, module_tree: Arc<ModuleTree>,
processed_imports: FxHashSet<(ModuleId, usize)>,
result: ItemMap, result: ItemMap,
} }
@ -313,6 +314,7 @@ where
input, input,
source_root, source_root,
module_tree, module_tree,
processed_imports: FxHashSet::default(),
result: ItemMap::default(), result: ItemMap::default(),
} }
} }
@ -322,10 +324,17 @@ where
self.populate_module(module_id, Arc::clone(items))?; self.populate_module(module_id, Arc::clone(items))?;
} }
loop {
let processed_imports_count = self.processed_imports.len();
for &module_id in self.input.keys() { for &module_id in self.input.keys() {
self.db.check_canceled()?; self.db.check_canceled()?;
self.resolve_imports(module_id)?; self.resolve_imports(module_id)?;
} }
if processed_imports_count == self.processed_imports.len() {
// no new imports resolved
break;
}
}
Ok(self.result) Ok(self.result)
} }
@ -418,15 +427,21 @@ where
} }
fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> { fn resolve_imports(&mut self, module_id: ModuleId) -> Cancelable<()> {
for import in self.input[&module_id].imports.iter() { for (i, import) in self.input[&module_id].imports.iter().enumerate() {
self.resolve_import(module_id, import)?; if self.processed_imports.contains(&(module_id, i)) {
// already done
continue;
}
if self.resolve_import(module_id, import)? {
self.processed_imports.insert((module_id, i));
}
} }
Ok(()) Ok(())
} }
fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<()> { fn resolve_import(&mut self, module_id: ModuleId, import: &Import) -> Cancelable<bool> {
let ptr = match import.kind { let ptr = match import.kind {
ImportKind::Glob => return Ok(()), ImportKind::Glob => return Ok(false),
ImportKind::Named(ptr) => ptr, ImportKind::Named(ptr) => ptr,
}; };
@ -436,7 +451,7 @@ where
match module_id.parent(&self.module_tree) { match module_id.parent(&self.module_tree) {
Some(it) => it, Some(it) => it,
// TODO: error // TODO: error
None => return Ok(()), None => return Ok(true), // this can't suddenly resolve if we just resolve some other imports
} }
} }
PathKind::Crate => module_id.crate_root(&self.module_tree), PathKind::Crate => module_id.crate_root(&self.module_tree),
@ -447,14 +462,14 @@ where
let def_id = match self.result.per_module[&curr].items.get(name) { let def_id = match self.result.per_module[&curr].items.get(name) {
Some(res) if !res.def_id.is_none() => res.def_id, Some(res) if !res.def_id.is_none() => res.def_id,
_ => return Ok(()), _ => return Ok(false),
}; };
if !is_last { if !is_last {
let type_def_id = if let Some(d) = def_id.take(Namespace::Types) { let type_def_id = if let Some(d) = def_id.take(Namespace::Types) {
d d
} else { } else {
return Ok(()); return Ok(false);
}; };
curr = match type_def_id.loc(self.db) { curr = match type_def_id.loc(self.db) {
DefLoc { DefLoc {
@ -479,12 +494,14 @@ where
import: Some(ptr), import: Some(ptr),
}; };
items.items.insert(name.clone(), res); items.items.insert(name.clone(), res);
}) });
} return Ok(true);
return Ok(()); } else {
return Ok(false);
} }
} }
_ => return Ok(()), }
_ => return Ok(true), // this resolved to a non-module, so the path won't ever resolve
} }
} else { } else {
self.update(module_id, |items| { self.update(module_id, |items| {
@ -496,7 +513,7 @@ where
}) })
} }
} }
Ok(()) Ok(true)
} }
fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) { fn update(&mut self, module_id: ModuleId, f: impl FnOnce(&mut ModuleScope)) {

View file

@ -35,7 +35,7 @@ fn check_module_item_map(map: &hir::ItemMap, module_id: hir::ModuleId, expected:
.map(|it| it.trim()) .map(|it| it.trim())
.collect::<Vec<_>>() .collect::<Vec<_>>()
.join("\n"); .join("\n");
assert_eq_text!(&actual, &expected); assert_eq_text!(&expected, &actual);
fn dump_resolution(resolution: &hir::Resolution) -> &'static str { fn dump_resolution(resolution: &hir::Resolution) -> &'static str {
match ( match (
@ -77,6 +77,35 @@ fn item_map_smoke_test() {
); );
} }
#[test]
fn re_exports() {
let (item_map, module_id) = item_map(
"
//- /lib.rs
mod foo;
use self::foo::Baz;
<|>
//- /foo/mod.rs
pub mod bar;
pub use self::bar::Baz;
//- /foo/bar.rs
pub struct Baz;
",
);
check_module_item_map(
&item_map,
module_id,
"
Baz: t v
foo: t
",
);
}
#[test] #[test]
fn item_map_contains_items_from_expansions() { fn item_map_contains_items_from_expansions() {
let (item_map, module_id) = item_map( let (item_map, module_id) = item_map(