@@ -153,7 +153,9 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
153153
154154 let mut visited_modules = FxHashSet :: default ( ) ;
155155
156- calculate_best_path ( ctx, & mut visited_modules, item, max_len) . map ( |choice| choice. path )
156+ let mut best_choice = None ;
157+ calculate_best_path ( ctx, & mut visited_modules, item, max_len, & mut best_choice) ;
158+ best_choice. map ( |choice| choice. path )
157159}
158160
159161#[ tracing:: instrument( skip_all) ]
@@ -164,12 +166,16 @@ fn find_path_for_module(
164166 maybe_extern : bool ,
165167 max_len : usize ,
166168) -> Option < Choice > {
169+ if max_len == 0 {
170+ // recursive base case, we can't find a path of length 0
171+ return None ;
172+ }
167173 if let Some ( crate_root) = module_id. as_crate_root ( ) {
168174 if !maybe_extern || crate_root == ctx. from . derive_crate_root ( ) {
169175 // - if the item is the crate root, return `crate`
170176 return Some ( Choice {
171177 path : ModPath :: from_segments ( PathKind :: Crate , None ) ,
172- path_len : 5 ,
178+ path_text_len : 5 ,
173179 stability : Stable ,
174180 prefer_due_to_prelude : false ,
175181 sysroot_score : 0 ,
@@ -232,7 +238,7 @@ fn find_path_for_module(
232238 if ctx. prefix != PrefixKind :: ByCrate || kind == PathKind :: Crate {
233239 return Some ( Choice {
234240 path : ModPath :: from_segments ( kind, None ) ,
235- path_len : path_kind_len ( kind) ,
241+ path_text_len : path_kind_len ( kind) ,
236242 stability : Stable ,
237243 prefer_due_to_prelude : false ,
238244 sysroot_score : 0 ,
@@ -245,11 +251,13 @@ fn find_path_for_module(
245251 if let Some ( choice) = find_in_prelude ( ctx. db , ctx. from_def_map , item, ctx. from ) {
246252 return Some ( choice) ;
247253 }
254+ let mut best_choice = None ;
248255 if maybe_extern {
249- calculate_best_path ( ctx, visited_modules, item, max_len)
256+ calculate_best_path ( ctx, visited_modules, item, max_len, & mut best_choice ) ;
250257 } else {
251- calculate_best_path_local ( ctx, visited_modules, item, max_len)
258+ calculate_best_path_local ( ctx, visited_modules, item, max_len, & mut best_choice ) ;
252259 }
260+ best_choice
253261}
254262
255263fn find_in_scope (
@@ -333,12 +341,8 @@ fn calculate_best_path(
333341 visited_modules : & mut FxHashSet < ModuleId > ,
334342 item : ItemInNs ,
335343 max_len : usize ,
336- ) -> Option < Choice > {
337- if max_len <= 1 {
338- // recursive base case, we can't find a path prefix of length 0, one segment is occupied by
339- // the item's name itself.
340- return None ;
341- }
344+ best_choice : & mut Option < Choice > ,
345+ ) {
342346 let fuel = ctx. fuel . get ( ) ;
343347 if fuel == 0 {
344348 // we ran out of fuel, so we stop searching here
@@ -347,16 +351,15 @@ fn calculate_best_path(
347351 item. krate( ctx. db) ,
348352 ctx. from. krate( )
349353 ) ;
350- return None ;
354+ return ;
351355 }
352356 ctx. fuel . set ( fuel - 1 ) ;
353357
354358 if item. krate ( ctx. db ) == Some ( ctx. from . krate ) {
355359 // Item was defined in the same crate that wants to import it. It cannot be found in any
356360 // dependency in this case.
357- calculate_best_path_local ( ctx, visited_modules, item, max_len)
361+ calculate_best_path_local ( ctx, visited_modules, item, max_len, best_choice )
358362 } else {
359- let mut best_choice = None :: < Choice > ;
360363 let db = ctx. db ;
361364 // Item was defined in some upstream crate. This means that it must be exported from one,
362365 // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
@@ -393,10 +396,7 @@ fn calculate_best_path(
393396 if info. is_unstable { Unstable } else { Stable } ,
394397 ) ;
395398
396- best_choice = Some ( match best_choice. take ( ) {
397- Some ( best_choice) => best_choice. select ( choice, info. name . clone ( ) ) ,
398- None => choice. push ( ctx. cfg . prefer_prelude , info. name . clone ( ) ) ,
399- } ) ;
399+ Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , info. name . clone ( ) ) ;
400400 processed_something = true ;
401401 }
402402 processed_something
@@ -415,12 +415,12 @@ fn calculate_best_path(
415415 . map ( |dep| {
416416 (
417417 match crate_graph[ dep. crate_id ] . origin {
418- CrateOrigin :: Lang ( LangCrateOrigin :: Std ) if ctx. cfg . prefer_no_std => 4 ,
418+ CrateOrigin :: Lang ( LangCrateOrigin :: Std ) if ctx. cfg . prefer_no_std => 5 ,
419419 CrateOrigin :: Lang ( LangCrateOrigin :: Std ) => 1 ,
420- CrateOrigin :: Lang ( LangCrateOrigin :: Alloc ) => 3 ,
420+ CrateOrigin :: Lang ( LangCrateOrigin :: Alloc ) => 2 ,
421421 CrateOrigin :: Lang ( LangCrateOrigin :: ProcMacro ) => 3 ,
422422 CrateOrigin :: Lang ( LangCrateOrigin :: Test ) => 3 ,
423- CrateOrigin :: Lang ( LangCrateOrigin :: Core ) => 2 ,
423+ CrateOrigin :: Lang ( LangCrateOrigin :: Core ) => 4 ,
424424 CrateOrigin :: Lang ( LangCrateOrigin :: Other ) => 1 ,
425425 _ => 0 ,
426426 } ,
@@ -431,16 +431,15 @@ fn calculate_best_path(
431431 . reduce ( BitOr :: bitor)
432432 . unwrap_or ( false ) ;
433433 if processed {
434- // Found a path in a sysroot crate, so return it.
435- return best_choice ;
434+ // Found a path in a sysroot crate
435+ return ;
436436 }
437437 }
438438
439439 dependencies
440440 . iter ( )
441441 . filter ( |it| !ctx. is_std_item || !it. is_sysroot ( ) )
442442 . for_each ( |dep| _ = process_dep ( dep. crate_id , 0 ) ) ;
443- best_choice
444443 }
445444}
446445
@@ -449,40 +448,31 @@ fn calculate_best_path_local(
449448 visited_modules : & mut FxHashSet < ModuleId > ,
450449 item : ItemInNs ,
451450 max_len : usize ,
452- ) -> Option < Choice > {
453- if max_len <= 1 {
454- // recursive base case, we can't find a path prefix of length 0, one segment is occupied by
455- // the item's name itself.
456- return None ;
457- }
458- let mut best_choice = None :: < Choice > ;
451+ best_choice : & mut Option < Choice > ,
452+ ) {
459453 // FIXME: cache the `find_local_import_locations` output?
460454 find_local_import_locations ( ctx. db , item, ctx. from , ctx. from_def_map , |name, module_id| {
461455 if !visited_modules. insert ( module_id) {
462456 return ;
463457 }
464458 // we are looking for paths of length up to best_path_len, any longer will make it be
465459 // less optimal. The -1 is due to us pushing name onto it afterwards.
466- if let Some ( path ) = find_path_for_module (
460+ if let Some ( choice ) = find_path_for_module (
467461 ctx,
468462 visited_modules,
469463 module_id,
470464 false ,
471465 best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
472466 ) {
473- best_choice = Some ( match best_choice. take ( ) {
474- Some ( best_choice) => best_choice. select ( path, name. clone ( ) ) ,
475- None => path. push ( ctx. cfg . prefer_prelude , name. clone ( ) ) ,
476- } ) ;
467+ Choice :: try_select ( best_choice, choice, ctx. cfg . prefer_prelude , name. clone ( ) ) ;
477468 }
478469 } ) ;
479- best_choice
480470}
481471
482472struct Choice {
483473 path : ModPath ,
484474 /// The length in characters of the path
485- path_len : usize ,
475+ path_text_len : usize ,
486476 /// The stability of the path
487477 stability : Stability ,
488478 /// Whether this path contains a prelude segment and preference for it has been signaled
@@ -494,7 +484,7 @@ struct Choice {
494484impl Choice {
495485 fn new ( prefer_prelude : bool , kind : PathKind , name : Name , stability : Stability ) -> Self {
496486 Self {
497- path_len : path_kind_len ( kind) + name. as_str ( ) . len ( ) ,
487+ path_text_len : path_kind_len ( kind) + name. as_str ( ) . len ( ) ,
498488 stability,
499489 prefer_due_to_prelude : prefer_prelude && name == sym:: prelude,
500490 sysroot_score : 0 ,
@@ -503,37 +493,44 @@ impl Choice {
503493 }
504494
505495 fn push ( mut self , prefer_prelude : bool , name : Name ) -> Self {
506- self . path_len += name. as_str ( ) . len ( ) ;
496+ self . path_text_len += name. as_str ( ) . len ( ) ;
507497 self . prefer_due_to_prelude |= prefer_prelude && name == sym:: prelude;
508498 self . path . push_segment ( name) ;
509499 self
510500 }
511501
512- fn select ( self , mut other : Choice , name : Name ) -> Self {
502+ fn try_select (
503+ current : & mut Option < Choice > ,
504+ mut other : Choice ,
505+ prefer_prelude : bool ,
506+ name : Name ,
507+ ) {
508+ let Some ( current) = current else {
509+ * current = Some ( other. push ( prefer_prelude, name) ) ;
510+ return ;
511+ } ;
513512 match other
514513 . stability
515- . cmp ( & self . stability )
516- . then_with ( || other. prefer_due_to_prelude . cmp ( & self . prefer_due_to_prelude ) )
517- . then_with ( || self . sysroot_score . cmp ( & other. sysroot_score ) )
518- . then_with ( || ( self . path . len ( ) ) . cmp ( & ( other. path . len ( ) + 1 ) ) )
514+ . cmp ( & current . stability )
515+ . then_with ( || other. prefer_due_to_prelude . cmp ( & current . prefer_due_to_prelude ) )
516+ . then_with ( || current . sysroot_score . cmp ( & other. sysroot_score ) )
517+ . then_with ( || ( current . path . len ( ) ) . cmp ( & ( other. path . len ( ) + 1 ) ) )
519518 {
520- Ordering :: Less => self ,
519+ Ordering :: Less => return ,
521520 Ordering :: Equal => {
522- other. path_len += name. as_str ( ) . len ( ) ;
523-
524- match self . path_len . cmp ( & other. path_len ) {
525- Ordering :: Less | Ordering :: Equal => self ,
526- Ordering :: Greater => {
527- other. path . push_segment ( name) ;
528- other
529- }
521+ other. path_text_len += name. as_str ( ) . len ( ) ;
522+ if let Ordering :: Less | Ordering :: Equal =
523+ current. path_text_len . cmp ( & other. path_text_len )
524+ {
525+ return ;
530526 }
531527 }
532528 Ordering :: Greater => {
533- other. path . push_segment ( name) ;
534- other
529+ other. path_text_len += name. as_str ( ) . len ( ) ;
535530 }
536531 }
532+ other. path . push_segment ( name) ;
533+ * current = other;
537534 }
538535}
539536
0 commit comments