Make extern crates in the root module add to the extern prelude

To accomplish this, separate the extern prelude from the per-module item maps.
This commit is contained in:
Florian Diebold 2019-02-03 23:23:22 +01:00
parent d69023fc72
commit 1056b480d6
4 changed files with 68 additions and 39 deletions

View file

@ -134,7 +134,7 @@ impl Module {
}
/// Returns the crate this module is part of.
pub fn krate(&self, _db: &impl HirDatabase) -> Option<Crate> {
pub fn krate(&self, _db: &impl PersistentHirDatabase) -> Option<Crate> {
Some(self.krate)
}

View file

@ -34,6 +34,7 @@ use crate::{
/// module, the set of visible items.
#[derive(Default, Debug, PartialEq, Eq)]
pub struct ItemMap {
extern_prelude: FxHashMap<Name, ModuleDef>,
per_module: ArenaMap<ModuleId, ModuleScope>,
}
@ -204,6 +205,7 @@ where
}
pub(crate) fn resolve(mut self) -> ItemMap {
self.populate_extern_prelude();
for (&module_id, items) in self.input.iter() {
self.populate_module(module_id, Arc::clone(items));
}
@ -227,29 +229,19 @@ where
self.result
}
fn populate_extern_prelude(&mut self) {
for dep in self.krate.dependencies(self.db) {
log::debug!("crate dep {:?} -> {:?}", dep.name, dep.krate);
if let Some(module) = dep.krate.root_module(self.db) {
self.result
.extern_prelude
.insert(dep.name.clone(), module.into());
}
}
}
fn populate_module(&mut self, module_id: ModuleId, input: Arc<LoweredModule>) {
let mut module_items = ModuleScope::default();
// Populate extern crates prelude
{
let root_id = module_id.crate_root(&self.module_tree);
let file_id = root_id.file_id(&self.module_tree);
let crate_graph = self.db.crate_graph();
if let Some(crate_id) = crate_graph.crate_id_for_crate_root(file_id.as_original_file())
{
let krate = Crate { crate_id };
for dep in krate.dependencies(self.db) {
if let Some(module) = dep.krate.root_module(self.db) {
let def = module.into();
self.add_module_item(
&mut module_items,
dep.name.clone(),
PerNs::types(def),
);
}
}
};
}
for (import_id, import_data) in input.imports.iter() {
if let Some(last_segment) = import_data.path.segments.iter().last() {
if !import_data.is_glob {
@ -327,7 +319,16 @@ where
.alias
.clone()
.unwrap_or_else(|| last_segment.name.clone());
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def,);
log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
// extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
if let Some(root_module) = self.krate.root_module(self.db) {
if import.is_extern_crate && module_id == root_module.module_id {
if let Some(def) = def.take_types() {
self.result.extern_prelude.insert(name.clone(), def);
}
}
}
self.update(module_id, |items| {
let res = Resolution {
def,
@ -389,24 +390,53 @@ impl ItemMap {
original_module: Module,
path: &Path,
) -> (PerNs<ModuleDef>, ReachedFixedPoint) {
let mut curr_per_ns: PerNs<ModuleDef> = PerNs::types(match path.kind {
PathKind::Crate => original_module.crate_root(db).into(),
PathKind::Self_ | PathKind::Plain => original_module.into(),
let mut segments = path.segments.iter().enumerate();
let mut curr_per_ns: PerNs<ModuleDef> = match path.kind {
PathKind::Crate => PerNs::types(original_module.crate_root(db).into()),
PathKind::Self_ => PerNs::types(original_module.into()),
PathKind::Plain => {
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return (PerNs::none(), ReachedFixedPoint::Yes),
};
// Resolve in:
// - current module / scope
// - extern prelude
match self[original_module.module_id].items.get(&segment.name) {
Some(res) if !res.def.is_none() => res.def,
_ => {
if let Some(def) = self.extern_prelude.get(&segment.name) {
PerNs::types(*def)
} else {
return (PerNs::none(), ReachedFixedPoint::No);
}
}
}
}
PathKind::Super => {
if let Some(p) = original_module.parent(db) {
p.into()
PerNs::types(p.into())
} else {
log::debug!("super path in root module");
return (PerNs::none(), ReachedFixedPoint::Yes);
}
}
PathKind::Abs => {
// TODO: absolute use is not supported
// 2018-style absolute path -- only extern prelude
let segment = match segments.next() {
Some((_, segment)) => segment,
None => return (PerNs::none(), ReachedFixedPoint::Yes),
};
if let Some(def) = self.extern_prelude.get(&segment.name) {
log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
PerNs::types(*def)
} else {
return (PerNs::none(), ReachedFixedPoint::Yes);
}
});
}
};
for (i, segment) in path.segments.iter().enumerate() {
for (i, segment) in segments {
let curr = match curr_per_ns.as_ref().take_types() {
Some(r) => r,
None => {

View file

@ -23,6 +23,7 @@ pub(super) struct ImportData {
pub(super) path: Path,
pub(super) alias: Option<Name>,
pub(super) is_glob: bool,
pub(super) is_extern_crate: bool,
}
/// A set of items and imports declared inside a module, without relation to
@ -199,6 +200,7 @@ impl LoweredModule {
path,
alias,
is_glob: false,
is_extern_crate: true,
});
}
}
@ -228,6 +230,7 @@ impl LoweredModule {
path,
alias,
is_glob: segment.is_none(),
is_extern_crate: false,
});
if let Some(segment) = segment {
source_map.insert(import, segment)

View file

@ -329,7 +329,6 @@ fn item_map_across_crates() {
module.module_id,
"
Baz: t v
test_crate: t
",
);
}
@ -342,7 +341,9 @@ fn extern_crate_rename() {
extern crate alloc as alloc_crate;
mod alloc;
mod sync;
//- /sync.rs
use alloc_crate::Arc;
//- /lib.rs
@ -350,6 +351,7 @@ fn extern_crate_rename() {
",
);
let main_id = sr.files[RelativePath::new("/main.rs")];
let sync_id = sr.files[RelativePath::new("/sync.rs")];
let lib_id = sr.files[RelativePath::new("/lib.rs")];
let mut crate_graph = CrateGraph::default();
@ -361,7 +363,7 @@ fn extern_crate_rename() {
db.set_crate_graph(Arc::new(crate_graph));
let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
let module = crate::source_binder::module_from_file_id(&db, sync_id).unwrap();
let krate = module.krate(&db).unwrap();
let item_map = db.item_map(krate);
@ -370,8 +372,6 @@ fn extern_crate_rename() {
module.module_id,
"
Arc: t v
alloc: t
alloc_crate: t
",
);
}
@ -403,8 +403,6 @@ fn import_across_source_roots() {
let main_id = sr2.files[RelativePath::new("/main.rs")];
eprintln!("lib = {:?}, main = {:?}", lib_id, main_id);
let mut crate_graph = CrateGraph::default();
let main_crate = crate_graph.add_crate_root(main_id);
let lib_crate = crate_graph.add_crate_root(lib_id);
@ -423,7 +421,6 @@ fn import_across_source_roots() {
module.module_id,
"
C: t v
test_crate: t
",
);
}
@ -465,7 +462,6 @@ fn reexport_across_crates() {
module.module_id,
"
Baz: t v
test_crate: t
",
);
}