Handle extern crates better, so they work correctly in 2015 edition

(see the removed comment.)
This commit is contained in:
Florian Diebold 2019-02-13 20:42:43 +01:00
parent 70839b7ef8
commit 92c595a6a6
3 changed files with 55 additions and 15 deletions

View File

@ -287,12 +287,18 @@ where
) -> ReachedFixedPoint {
log::debug!("resolving import: {:?} ({:?})", import, self.result.edition);
let original_module = Module { krate: self.krate, module_id };
let (def, reached_fixedpoint) = self.result.resolve_path_fp(
self.db,
ResolveMode::Import,
original_module,
&import.path,
);
let (def, reached_fixedpoint) = if import.is_extern_crate {
let res = self.result.resolve_name_in_extern_prelude(
&import
.path
.as_ident()
.expect("extern crate should have been desugared to one-element path"),
);
(res, if res.is_none() { ReachedFixedPoint::No } else { ReachedFixedPoint::Yes })
} else {
self.result.resolve_path_fp(self.db, ResolveMode::Import, original_module, &import.path)
};
if reached_fixedpoint != ReachedFixedPoint::Yes {
return reached_fixedpoint;
@ -502,6 +508,10 @@ impl ItemMap {
from_scope.or(from_extern_prelude).or(from_prelude)
}
fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs<ModuleDef> {
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it))
}
fn resolve_name_in_crate_root_or_extern_prelude(
&self,
db: &impl PersistentHirDatabase,
@ -511,8 +521,7 @@ impl ItemMap {
let crate_root = module.crate_root(db);
let from_crate_root =
self[crate_root.module_id].items.get(name).map_or(PerNs::none(), |it| it.def);
let from_extern_prelude =
self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
from_crate_root.or(from_extern_prelude)
}

View File

@ -8,7 +8,7 @@ use ra_arena::{Arena, RawId, impl_arena_id, map::ArenaMap};
use rustc_hash::FxHashMap;
use crate::{
SourceItemId, Path, PathKind, ModuleSource, Name,
SourceItemId, Path, ModuleSource, Name,
HirFileId, MacroCallLoc, AsName, PerNs, Function,
ModuleDef, Module, Struct, Enum, Const, Static, Trait, Type,
ids::LocationCtx, PersistentHirDatabase,
@ -180,13 +180,8 @@ impl LoweredModule {
self.add_use_item(source_map, it);
}
ast::ModuleItemKind::ExternCrateItem(it) => {
// Lower `extern crate x` to `use ::x`. This is kind of cheating
// and only works if we always interpret absolute paths in the
// 2018 style; otherwise `::x` could also refer to a module in
// the crate root.
if let Some(name_ref) = it.name_ref() {
let mut path = Path::from_name_ref(name_ref);
path.kind = PathKind::Abs;
let path = Path::from_name_ref(name_ref);
let alias = it.alias().and_then(|a| a.name()).map(AsName::as_name);
self.imports.alloc(ImportData {
path,

View File

@ -542,6 +542,42 @@ fn extern_crate_rename() {
);
}
#[test]
fn extern_crate_rename_2015_edition() {
let mut db = MockDatabase::with_files(
"
//- /main.rs
extern crate alloc as alloc_crate;
mod alloc;
mod sync;
//- /sync.rs
use alloc_crate::Arc;
//- /lib.rs
struct Arc;
",
);
db.set_crate_graph_from_fixture(crate_graph! {
"main": ("/main.rs", "2015", ["alloc"]),
"alloc": ("/lib.rs", []),
});
let sync_id = db.file_id_of("/sync.rs");
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);
check_module_item_map(
&item_map,
module.module_id,
"
Arc: t v
",
);
}
#[test]
fn import_across_source_roots() {
let mut db = MockDatabase::with_files(