@@ -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.
237240fn 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
256275fn 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