@@ -23,12 +23,29 @@ pub fn find_path(
2323 db : & dyn DefDatabase ,
2424 item : ItemInNs ,
2525 from : ModuleId ,
26- prefix_kind : PrefixKind ,
26+ mut prefix_kind : PrefixKind ,
2727 ignore_local_imports : bool ,
28- cfg : ImportPathConfig ,
28+ mut cfg : ImportPathConfig ,
2929) -> Option < ModPath > {
3030 let _p = tracing:: span!( tracing:: Level :: INFO , "find_path" ) . entered ( ) ;
31- find_path_inner ( FindPathCtx { db, prefix : prefix_kind, cfg, ignore_local_imports } , item, from)
31+
32+ // - if the item is a builtin, it's in scope
33+ if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
34+ return Some ( ModPath :: from_segments ( PathKind :: Plain , iter:: once ( builtin. as_name ( ) ) ) ) ;
35+ }
36+
37+ // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
38+ // default to plain paths.
39+ if item. module ( db) . is_some_and ( ModuleId :: is_within_block) {
40+ prefix_kind = PrefixKind :: Plain ;
41+ }
42+ cfg. prefer_no_std = cfg. prefer_no_std || db. crate_supports_no_std ( from. krate ( ) ) ;
43+
44+ find_path_inner (
45+ & FindPathCtx { db, prefix : prefix_kind, cfg, ignore_local_imports, from } ,
46+ item,
47+ MAX_PATH_LEN ,
48+ )
3249}
3350
3451#[ derive( Copy , Clone , Debug ) ]
@@ -63,79 +80,52 @@ impl PrefixKind {
6380 #[ inline]
6481 fn path_kind ( self ) -> PathKind {
6582 match self {
66- PrefixKind :: BySelf => PathKind :: Super ( 0 ) ,
83+ PrefixKind :: BySelf => PathKind :: SELF ,
6784 PrefixKind :: Plain => PathKind :: Plain ,
6885 PrefixKind :: ByCrate => PathKind :: Crate ,
6986 }
7087 }
7188}
7289
73- #[ derive( Copy , Clone ) ]
7490struct FindPathCtx < ' db > {
7591 db : & ' db dyn DefDatabase ,
7692 prefix : PrefixKind ,
7793 cfg : ImportPathConfig ,
7894 ignore_local_imports : bool ,
95+ from : ModuleId ,
7996}
8097
8198/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
82- fn find_path_inner ( ctx : FindPathCtx < ' _ > , item : ItemInNs , from : ModuleId ) -> Option < ModPath > {
83- // - if the item is a builtin, it's in scope
84- if let ItemInNs :: Types ( ModuleDefId :: BuiltinType ( builtin) ) = item {
85- return Some ( ModPath :: from_segments ( PathKind :: Plain , iter:: once ( builtin. as_name ( ) ) ) ) ;
86- }
87-
88- let def_map = from. def_map ( ctx. db ) ;
89- let crate_root = from. derive_crate_root ( ) ;
99+ fn find_path_inner ( ctx : & FindPathCtx < ' _ > , item : ItemInNs , max_len : usize ) -> Option < ModPath > {
100+ let def_map = ctx. from . def_map ( ctx. db ) ;
90101 // - if the item is a module, jump straight to module search
91102 if let ItemInNs :: Types ( ModuleDefId :: ModuleId ( module_id) ) = item {
92103 let mut visited_modules = FxHashSet :: default ( ) ;
93- return find_path_for_module (
94- FindPathCtx {
95- cfg : ImportPathConfig {
96- prefer_no_std : ctx. cfg . prefer_no_std
97- || ctx. db . crate_supports_no_std ( crate_root. krate ) ,
98- ..ctx. cfg
99- } ,
100- ..ctx
101- } ,
102- & def_map,
103- & mut visited_modules,
104- from,
105- module_id,
106- MAX_PATH_LEN ,
107- )
108- . map ( |( item, _) | item) ;
104+ return find_path_for_module ( ctx, & def_map, & mut visited_modules, module_id, max_len)
105+ . map ( |( item, _) | item) ;
109106 }
110107
111- let prefix = if item. module ( ctx. db ) . is_some_and ( |it| it. is_within_block ( ) ) {
112- PrefixKind :: Plain
113- } else {
114- ctx. prefix
115- } ;
116- let may_be_in_scope = match prefix {
108+ let may_be_in_scope = match ctx. prefix {
117109 PrefixKind :: Plain | PrefixKind :: BySelf => true ,
118- PrefixKind :: ByCrate => from. is_crate_root ( ) ,
110+ PrefixKind :: ByCrate => ctx . from . is_crate_root ( ) ,
119111 } ;
120112 if may_be_in_scope {
121113 // - if the item is already in scope, return the name under which it is
122- let scope_name = find_in_scope ( ctx. db , & def_map, from, item, ctx. ignore_local_imports ) ;
114+ let scope_name = find_in_scope ( ctx. db , & def_map, ctx . from , item, ctx. ignore_local_imports ) ;
123115 if let Some ( scope_name) = scope_name {
124- return Some ( ModPath :: from_segments ( prefix. path_kind ( ) , iter:: once ( scope_name) ) ) ;
116+ return Some ( ModPath :: from_segments ( ctx . prefix . path_kind ( ) , iter:: once ( scope_name) ) ) ;
125117 }
126118 }
127119
128120 // - if the item is in the prelude, return the name from there
129- if let value @ Some ( _) =
130- find_in_prelude ( ctx. db , & crate_root. def_map ( ctx. db ) , & def_map, item, from)
131- {
132- return value;
121+ if let Some ( value) = find_in_prelude ( ctx. db , & def_map, item, ctx. from ) {
122+ return Some ( value) ;
133123 }
134124
135125 if let Some ( ModuleDefId :: EnumVariantId ( variant) ) = item. as_module_def_id ( ) {
136126 // - if the item is an enum variant, refer to it via the enum
137127 if let Some ( mut path) =
138- find_path_inner ( ctx, ItemInNs :: Types ( variant. lookup ( ctx. db ) . parent . into ( ) ) , from )
128+ find_path_inner ( ctx, ItemInNs :: Types ( variant. lookup ( ctx. db ) . parent . into ( ) ) , max_len )
139129 {
140130 path. push_segment ( ctx. db . enum_variant_data ( variant) . name . clone ( ) ) ;
141131 return Some ( path) ;
@@ -147,30 +137,14 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti
147137
148138 let mut visited_modules = FxHashSet :: default ( ) ;
149139
150- calculate_best_path (
151- FindPathCtx {
152- cfg : ImportPathConfig {
153- prefer_no_std : ctx. cfg . prefer_no_std
154- || ctx. db . crate_supports_no_std ( crate_root. krate ) ,
155- ..ctx. cfg
156- } ,
157- ..ctx
158- } ,
159- & def_map,
160- & mut visited_modules,
161- MAX_PATH_LEN ,
162- item,
163- from,
164- )
165- . map ( |( item, _) | item)
140+ calculate_best_path ( ctx, & def_map, & mut visited_modules, item, max_len) . map ( |( item, _) | item)
166141}
167142
168143#[ tracing:: instrument( skip_all) ]
169144fn find_path_for_module (
170- ctx : FindPathCtx < ' _ > ,
145+ ctx : & FindPathCtx < ' _ > ,
171146 def_map : & DefMap ,
172147 visited_modules : & mut FxHashSet < ModuleId > ,
173- from : ModuleId ,
174148 module_id : ModuleId ,
175149 max_len : usize ,
176150) -> Option < ( ModPath , Stability ) > {
@@ -180,20 +154,20 @@ fn find_path_for_module(
180154
181155 let is_crate_root = module_id. as_crate_root ( ) ;
182156 // - if the item is the crate root, return `crate`
183- if is_crate_root. is_some_and ( |it| it == from. derive_crate_root ( ) ) {
157+ if is_crate_root == Some ( ctx . from . derive_crate_root ( ) ) {
184158 return Some ( ( ModPath :: from_segments ( PathKind :: Crate , None ) , Stable ) ) ;
185159 }
186160
187- let root_def_map = from. derive_crate_root ( ) . def_map ( ctx. db ) ;
188161 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
189162 if let Some ( crate_root) = is_crate_root {
163+ let root_def_map = ctx. from . derive_crate_root ( ) . def_map ( ctx. db ) ;
190164 // rev here so we prefer looking at renamed extern decls first
191165 for ( name, ( def_id, _extern_crate) ) in root_def_map. extern_prelude ( ) . rev ( ) {
192166 if crate_root != def_id {
193167 continue ;
194168 }
195169 let name_already_occupied_in_type_ns = def_map
196- . with_ancestor_maps ( ctx. db , from. local_id , & mut |def_map, local_id| {
170+ . with_ancestor_maps ( ctx. db , ctx . from . local_id , & mut |def_map, local_id| {
197171 def_map[ local_id]
198172 . scope
199173 . type_ ( name)
@@ -209,49 +183,42 @@ fn find_path_for_module(
209183 return Some ( ( ModPath :: from_segments ( kind, iter:: once ( name. clone ( ) ) ) , Stable ) ) ;
210184 }
211185 }
212- let prefix = if module_id . is_within_block ( ) { PrefixKind :: Plain } else { ctx . prefix } ;
213- let may_be_in_scope = match prefix {
186+
187+ let may_be_in_scope = match ctx . prefix {
214188 PrefixKind :: Plain | PrefixKind :: BySelf => true ,
215- PrefixKind :: ByCrate => from. is_crate_root ( ) ,
189+ PrefixKind :: ByCrate => ctx . from . is_crate_root ( ) ,
216190 } ;
217191 if may_be_in_scope {
218192 let scope_name = find_in_scope (
219193 ctx. db ,
220194 def_map,
221- from,
195+ ctx . from ,
222196 ItemInNs :: Types ( module_id. into ( ) ) ,
223197 ctx. ignore_local_imports ,
224198 ) ;
225199 if let Some ( scope_name) = scope_name {
226200 // - if the item is already in scope, return the name under which it is
227201 return Some ( (
228- ModPath :: from_segments ( prefix. path_kind ( ) , iter:: once ( scope_name) ) ,
202+ ModPath :: from_segments ( ctx . prefix . path_kind ( ) , iter:: once ( scope_name) ) ,
229203 Stable ,
230204 ) ) ;
231205 }
232206 }
233207
234208 // - if the module can be referenced as self, super or crate, do that
235- if let Some ( mod_path) = is_kw_kind_relative_to_from ( def_map, module_id, from) {
209+ if let Some ( mod_path) = is_kw_kind_relative_to_from ( def_map, module_id, ctx . from ) {
236210 if ctx. prefix != PrefixKind :: ByCrate || mod_path. kind == PathKind :: Crate {
237211 return Some ( ( mod_path, Stable ) ) ;
238212 }
239213 }
240214
241215 // - if the module is in the prelude, return it by that path
242216 if let Some ( mod_path) =
243- find_in_prelude ( ctx. db , & root_def_map , def_map, ItemInNs :: Types ( module_id. into ( ) ) , from)
217+ find_in_prelude ( ctx. db , def_map, ItemInNs :: Types ( module_id. into ( ) ) , ctx . from )
244218 {
245219 return Some ( ( mod_path, Stable ) ) ;
246220 }
247- calculate_best_path (
248- ctx,
249- def_map,
250- visited_modules,
251- max_len,
252- ItemInNs :: Types ( module_id. into ( ) ) ,
253- from,
254- )
221+ calculate_best_path ( ctx, def_map, visited_modules, ItemInNs :: Types ( module_id. into ( ) ) , max_len)
255222}
256223
257224// FIXME: Do we still need this now that we record import origins, and hence aliases?
@@ -274,12 +241,11 @@ fn find_in_scope(
274241/// name doesn't clash in current scope.
275242fn find_in_prelude (
276243 db : & dyn DefDatabase ,
277- root_def_map : & DefMap ,
278244 local_def_map : & DefMap ,
279245 item : ItemInNs ,
280246 from : ModuleId ,
281247) -> Option < ModPath > {
282- let ( prelude_module, _) = root_def_map . prelude ( ) ?;
248+ let ( prelude_module, _) = local_def_map . prelude ( ) ?;
283249 // Preludes in block DefMaps are ignored, only the crate DefMap is searched
284250 let prelude_def_map = prelude_module. def_map ( db) ;
285251 let prelude_scope = & prelude_def_map[ prelude_module. local_id ] . scope ;
@@ -319,7 +285,7 @@ fn is_kw_kind_relative_to_from(
319285 let from = from. local_id ;
320286 if item == from {
321287 // - if the item is the module we're in, use `self`
322- Some ( ModPath :: from_segments ( PathKind :: Super ( 0 ) , None ) )
288+ Some ( ModPath :: from_segments ( PathKind :: SELF , None ) )
323289 } else if let Some ( parent_id) = def_map[ from] . parent {
324290 if item == parent_id {
325291 // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
@@ -337,12 +303,11 @@ fn is_kw_kind_relative_to_from(
337303
338304#[ tracing:: instrument( skip_all) ]
339305fn calculate_best_path (
340- ctx : FindPathCtx < ' _ > ,
306+ ctx : & FindPathCtx < ' _ > ,
341307 def_map : & DefMap ,
342308 visited_modules : & mut FxHashSet < ModuleId > ,
343- max_len : usize ,
344309 item : ItemInNs ,
345- from : ModuleId ,
310+ max_len : usize ,
346311) -> Option < ( ModPath , Stability ) > {
347312 if max_len <= 1 {
348313 return None ;
@@ -356,24 +321,21 @@ fn calculate_best_path(
356321 }
357322 None => * best_path = Some ( new_path) ,
358323 } ;
359- // Recursive case:
360- // - otherwise, look for modules containing (reexporting) it and import it from one of those
361- if item. krate ( ctx. db ) == Some ( from. krate ) {
324+
325+ if item. krate ( ctx. db ) == Some ( ctx. from . krate ) {
362326 let mut best_path_len = max_len;
363327 // Item was defined in the same crate that wants to import it. It cannot be found in any
364328 // dependency in this case.
365- for ( module_id, name) in find_local_import_locations ( ctx. db , item, from) {
329+ // FIXME: cache the `find_local_import_locations` output?
330+ for ( module_id, name) in find_local_import_locations ( ctx. db , item, ctx. from ) {
366331 if !visited_modules. insert ( module_id) {
367332 continue ;
368333 }
369- if let Some ( mut path) = find_path_for_module (
370- ctx,
371- def_map,
372- visited_modules,
373- from,
374- module_id,
375- best_path_len - 1 ,
376- ) {
334+ // we are looking for paths of length up to best_path_len, any longer will make it be
335+ // less optimal. The -1 is due to us pushing name onto it afterwards.
336+ if let Some ( mut path) =
337+ find_path_for_module ( ctx, def_map, visited_modules, module_id, best_path_len - 1 )
338+ {
377339 path. 0 . push_segment ( name) ;
378340
379341 let new_path = match best_path. take ( ) {
@@ -389,7 +351,7 @@ fn calculate_best_path(
389351 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
390352 // that wants to import it here, but we always prefer to use the external path here.
391353
392- for dep in & ctx. db . crate_graph ( ) [ from. krate ] . dependencies {
354+ for dep in & ctx. db . crate_graph ( ) [ ctx . from . krate ] . dependencies {
393355 let import_map = ctx. db . import_map ( dep. crate_id ) ;
394356 let Some ( import_info_for) = import_map. import_info_for ( item) else { continue } ;
395357 for info in import_info_for {
@@ -400,14 +362,15 @@ fn calculate_best_path(
400362
401363 // Determine best path for containing module and append last segment from `info`.
402364 // FIXME: we should guide this to look up the path locally, or from the same crate again?
403- let Some ( ( mut path, path_stability ) ) = find_path_for_module (
365+ let path = find_path_for_module (
404366 ctx,
405367 def_map,
406368 visited_modules,
407- from,
408369 info. container ,
409370 max_len - 1 ,
410- ) else {
371+ // fixme shouldnt we consider the best path length here?
372+ ) ;
373+ let Some ( ( mut path, path_stability) ) = path else {
411374 continue ;
412375 } ;
413376 cov_mark:: hit!( partially_imported) ;
@@ -633,15 +596,13 @@ mod tests {
633596 . into_iter ( )
634597 . cartesian_product ( [ false , true ] )
635598 {
636- let found_path = find_path_inner (
637- FindPathCtx {
638- db : & db,
639- prefix,
640- cfg : ImportPathConfig { prefer_no_std : false , prefer_prelude } ,
641- ignore_local_imports,
642- } ,
599+ let found_path = find_path (
600+ & db,
643601 resolved,
644602 module,
603+ prefix,
604+ ignore_local_imports,
605+ ImportPathConfig { prefer_no_std : false , prefer_prelude } ,
645606 ) ;
646607 format_to ! (
647608 res,
0 commit comments