Skip to content

Commit e986de0

Browse files
committed
Auto merge of rust-lang#13877 - lowr:fix/find-path-prefix-shadowed-prelude, r=Veykril
fix: prefix prelude items whose name collides in current scope Fixes rust-lang#13873 When we assemble path for prelude items whose name collides with other item in scope, we should always prefix it with module paths.
2 parents 643bc02 + cf2fa14 commit e986de0

File tree

1 file changed

+74
-13
lines changed

1 file changed

+74
-13
lines changed

crates/hir-def/src/find_path.rs

+74-13
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ fn find_path_inner(
107107
}
108108

109109
// - if the item is in the prelude, return the name from there
110-
if let Some(value) = find_in_prelude(db, &crate_root.def_map(db), item, from) {
110+
if let value @ Some(_) = find_in_prelude(db, &crate_root.def_map(db), &def_map, item, from) {
111111
return value;
112112
}
113113

@@ -205,7 +205,8 @@ fn find_path_for_module(
205205
}
206206
}
207207

208-
if let Some(value) = find_in_prelude(db, &root_def_map, ItemInNs::Types(module_id.into()), from)
208+
if let value @ Some(_) =
209+
find_in_prelude(db, &root_def_map, &def_map, ItemInNs::Types(module_id.into()), from)
209210
{
210211
return value;
211212
}
@@ -234,23 +235,41 @@ fn find_in_scope(
234235
})
235236
}
236237

238+
/// Returns single-segment path (i.e. without any prefix) if `item` is found in prelude and its
239+
/// name doesn't clash in current scope.
237240
fn find_in_prelude(
238241
db: &dyn DefDatabase,
239242
root_def_map: &DefMap,
243+
local_def_map: &DefMap,
240244
item: ItemInNs,
241245
from: ModuleId,
242-
) -> Option<Option<ModPath>> {
243-
if let Some(prelude_module) = root_def_map.prelude() {
244-
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
245-
let prelude_def_map = prelude_module.def_map(db);
246-
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
247-
if let Some((name, vis)) = prelude_scope.name_of(item) {
248-
if vis.is_visible_from(db, from) {
249-
return Some(Some(ModPath::from_segments(PathKind::Plain, Some(name.clone()))));
250-
}
251-
}
246+
) -> Option<ModPath> {
247+
let prelude_module = root_def_map.prelude()?;
248+
// Preludes in block DefMaps are ignored, only the crate DefMap is searched
249+
let prelude_def_map = prelude_module.def_map(db);
250+
let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
251+
let (name, vis) = prelude_scope.name_of(item)?;
252+
if !vis.is_visible_from(db, from) {
253+
return None;
254+
}
255+
256+
// Check if the name is in current scope and it points to the same def.
257+
let found_and_same_def =
258+
local_def_map.with_ancestor_maps(db, from.local_id, &mut |def_map, local_id| {
259+
let per_ns = def_map[local_id].scope.get(name);
260+
let same_def = match item {
261+
ItemInNs::Types(it) => per_ns.take_types()? == it,
262+
ItemInNs::Values(it) => per_ns.take_values()? == it,
263+
ItemInNs::Macros(it) => per_ns.take_macros()? == it,
264+
};
265+
Some(same_def)
266+
});
267+
268+
if found_and_same_def.unwrap_or(true) {
269+
Some(ModPath::from_segments(PathKind::Plain, Some(name.clone())))
270+
} else {
271+
None
252272
}
253-
None
254273
}
255274

256275
fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<ModPath> {
@@ -808,6 +827,48 @@ pub mod prelude {
808827
);
809828
}
810829

830+
#[test]
831+
fn shadowed_prelude() {
832+
check_found_path(
833+
r#"
834+
//- /main.rs crate:main deps:std
835+
struct S;
836+
$0
837+
//- /std.rs crate:std
838+
pub mod prelude {
839+
pub mod rust_2018 {
840+
pub struct S;
841+
}
842+
}
843+
"#,
844+
"std::prelude::rust_2018::S",
845+
"std::prelude::rust_2018::S",
846+
"std::prelude::rust_2018::S",
847+
"std::prelude::rust_2018::S",
848+
);
849+
}
850+
851+
#[test]
852+
fn imported_prelude() {
853+
check_found_path(
854+
r#"
855+
//- /main.rs crate:main deps:std
856+
use S;
857+
$0
858+
//- /std.rs crate:std
859+
pub mod prelude {
860+
pub mod rust_2018 {
861+
pub struct S;
862+
}
863+
}
864+
"#,
865+
"S",
866+
"S",
867+
"S",
868+
"S",
869+
);
870+
}
871+
811872
#[test]
812873
fn enum_variant_from_prelude() {
813874
let code = r#"

0 commit comments

Comments
 (0)