use extern prelude in Resolver

This fixes two bugs:

- completion for paths works again
- we handle extern prelude shadowing more correctly
This commit is contained in:
Aleksey Kladov 2019-02-11 15:39:26 +03:00
parent 2babbbb978
commit 58ed8ee665
5 changed files with 81 additions and 18 deletions

View file

@ -434,6 +434,14 @@ impl ItemMap {
self.resolve_path_fp(db, original_module, path).0
}
pub(crate) fn resolve_name_in_module(&self, module: Module, name: &Name) -> PerNs<ModuleDef> {
let from_scope = self[module.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));
from_scope.combine(from_extern_prelude)
}
// Returns Yes if we are sure that additions to `ItemMap` wouldn't change
// the result.
fn resolve_path_fp(
@ -451,19 +459,7 @@ impl ItemMap {
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);
}
}
}
self.resolve_name_in_module(original_module, &segment.name)
}
PathKind::Super => {
if let Some(p) = original_module.parent(db) {

View file

@ -536,6 +536,38 @@ fn reexport_across_crates() {
);
}
#[test]
fn values_dont_shadow_extern_crates() {
let mut db = MockDatabase::with_files(
"
//- /main.rs
fn foo() {}
use foo::Bar;
//- /foo/lib.rs
pub struct Bar;
",
);
db.set_crate_graph_from_fixture(crate_graph! {
"main": ("/main.rs", ["foo"]),
"foo": ("/foo/lib.rs", []),
});
let main_id = db.file_id_of("/main.rs");
let module = crate::source_binder::module_from_file_id(&db, main_id).unwrap();
let krate = module.krate(&db).unwrap();
let item_map = db.item_map(krate);
check_module_item_map(
&item_map,
module.module_id,
"
Bar: t v
foo: v
",
);
}
fn check_item_map_is_not_recomputed(initial: &str, file_change: &str) {
let (mut db, pos) = MockDatabase::with_position(initial);
let module = crate::source_binder::module_from_file_id(&db, pos.file_id).unwrap();

View file

@ -149,10 +149,7 @@ impl Scope {
if let Some(KnownName::SelfParam) = name.as_known_name() {
PerNs::types(Resolution::Def(m.module.into()))
} else {
match m.item_map[m.module.module_id].get(name) {
Some(res) => res.def.map(Resolution::Def),
None => PerNs::none(),
}
m.item_map.resolve_name_in_module(m.module, name).map(Resolution::Def)
}
}
Scope::GenericParams(gp) => match gp.find_by_name(name) {
@ -177,7 +174,7 @@ impl Scope {
}
}
fn collect_names(&self, f: &mut FnMut(Name, PerNs<Resolution>)) {
fn collect_names(&self, f: &mut dyn FnMut(Name, PerNs<Resolution>)) {
match self {
Scope::ModuleScope(m) => {
// TODO: should we provide `self` here?

View file

@ -186,4 +186,20 @@ mod tests {
",
);
}
#[test]
fn completes_use_paths_across_crates() {
check_reference_completion(
"completes_use_paths_across_crates",
"
//- /main.rs
use foo::<|>;
//- /foo/lib.rs
pub mod bar {
pub struct S;
}
",
);
}
}

View file

@ -0,0 +1,22 @@
---
created: "2019-02-11T11:53:02.410665254Z"
creator: insta@0.6.1
source: crates/ra_ide_api/src/completion/completion_item.rs
expression: kind_completions
---
[
CompletionItem {
completion_kind: Reference,
label: "bar",
kind: Some(
Module
),
detail: None,
documentation: None,
lookup: None,
insert_text: None,
insert_text_format: PlainText,
source_range: [9; 9),
text_edit: None
}
]