mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-26 11:55:04 +00:00
Merge #455
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:
commit
3bb1cb7017
2 changed files with 62 additions and 16 deletions
|
@ -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)) {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
Loading…
Reference in a new issue