@@ -107,7 +107,7 @@ fn find_path_inner(
107
107
}
108
108
109
109
// - 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) {
111
111
return value;
112
112
}
113
113
@@ -205,7 +205,8 @@ fn find_path_for_module(
205
205
}
206
206
}
207
207
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)
209
210
{
210
211
return value;
211
212
}
@@ -234,23 +235,41 @@ fn find_in_scope(
234
235
} )
235
236
}
236
237
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.
237
240
fn find_in_prelude (
238
241
db : & dyn DefDatabase ,
239
242
root_def_map : & DefMap ,
243
+ local_def_map : & DefMap ,
240
244
item : ItemInNs ,
241
245
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
252
272
}
253
- None
254
273
}
255
274
256
275
fn find_self_super ( def_map : & DefMap , item : ModuleId , from : ModuleId ) -> Option < ModPath > {
@@ -808,6 +827,48 @@ pub mod prelude {
808
827
) ;
809
828
}
810
829
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
+
811
872
#[ test]
812
873
fn enum_variant_from_prelude ( ) {
813
874
let code = r#"
0 commit comments