@@ -153,7 +153,9 @@ fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Opt
153
153
154
154
let mut visited_modules = FxHashSet :: default ( ) ;
155
155
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 )
157
159
}
158
160
159
161
#[ tracing:: instrument( skip_all) ]
@@ -164,12 +166,16 @@ fn find_path_for_module(
164
166
maybe_extern : bool ,
165
167
max_len : usize ,
166
168
) -> Option < Choice > {
169
+ if max_len == 0 {
170
+ // recursive base case, we can't find a path of length 0
171
+ return None ;
172
+ }
167
173
if let Some ( crate_root) = module_id. as_crate_root ( ) {
168
174
if !maybe_extern || crate_root == ctx. from . derive_crate_root ( ) {
169
175
// - if the item is the crate root, return `crate`
170
176
return Some ( Choice {
171
177
path : ModPath :: from_segments ( PathKind :: Crate , None ) ,
172
- path_len : 5 ,
178
+ path_text_len : 5 ,
173
179
stability : Stable ,
174
180
prefer_due_to_prelude : false ,
175
181
sysroot_score : 0 ,
@@ -232,7 +238,7 @@ fn find_path_for_module(
232
238
if ctx. prefix != PrefixKind :: ByCrate || kind == PathKind :: Crate {
233
239
return Some ( Choice {
234
240
path : ModPath :: from_segments ( kind, None ) ,
235
- path_len : path_kind_len ( kind) ,
241
+ path_text_len : path_kind_len ( kind) ,
236
242
stability : Stable ,
237
243
prefer_due_to_prelude : false ,
238
244
sysroot_score : 0 ,
@@ -245,11 +251,13 @@ fn find_path_for_module(
245
251
if let Some ( choice) = find_in_prelude ( ctx. db , ctx. from_def_map , item, ctx. from ) {
246
252
return Some ( choice) ;
247
253
}
254
+ let mut best_choice = None ;
248
255
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 ) ;
250
257
} 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 ) ;
252
259
}
260
+ best_choice
253
261
}
254
262
255
263
fn find_in_scope (
@@ -333,12 +341,8 @@ fn calculate_best_path(
333
341
visited_modules : & mut FxHashSet < ModuleId > ,
334
342
item : ItemInNs ,
335
343
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
+ ) {
342
346
let fuel = ctx. fuel . get ( ) ;
343
347
if fuel == 0 {
344
348
// we ran out of fuel, so we stop searching here
@@ -347,16 +351,15 @@ fn calculate_best_path(
347
351
item. krate( ctx. db) ,
348
352
ctx. from. krate( )
349
353
) ;
350
- return None ;
354
+ return ;
351
355
}
352
356
ctx. fuel . set ( fuel - 1 ) ;
353
357
354
358
if item. krate ( ctx. db ) == Some ( ctx. from . krate ) {
355
359
// Item was defined in the same crate that wants to import it. It cannot be found in any
356
360
// 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 )
358
362
} else {
359
- let mut best_choice = None :: < Choice > ;
360
363
let db = ctx. db ;
361
364
// Item was defined in some upstream crate. This means that it must be exported from one,
362
365
// 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(
393
396
if info. is_unstable { Unstable } else { Stable } ,
394
397
) ;
395
398
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 ( ) ) ;
400
400
processed_something = true ;
401
401
}
402
402
processed_something
@@ -415,12 +415,12 @@ fn calculate_best_path(
415
415
. map ( |dep| {
416
416
(
417
417
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 ,
419
419
CrateOrigin :: Lang ( LangCrateOrigin :: Std ) => 1 ,
420
- CrateOrigin :: Lang ( LangCrateOrigin :: Alloc ) => 3 ,
420
+ CrateOrigin :: Lang ( LangCrateOrigin :: Alloc ) => 2 ,
421
421
CrateOrigin :: Lang ( LangCrateOrigin :: ProcMacro ) => 3 ,
422
422
CrateOrigin :: Lang ( LangCrateOrigin :: Test ) => 3 ,
423
- CrateOrigin :: Lang ( LangCrateOrigin :: Core ) => 2 ,
423
+ CrateOrigin :: Lang ( LangCrateOrigin :: Core ) => 4 ,
424
424
CrateOrigin :: Lang ( LangCrateOrigin :: Other ) => 1 ,
425
425
_ => 0 ,
426
426
} ,
@@ -431,16 +431,15 @@ fn calculate_best_path(
431
431
. reduce ( BitOr :: bitor)
432
432
. unwrap_or ( false ) ;
433
433
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 ;
436
436
}
437
437
}
438
438
439
439
dependencies
440
440
. iter ( )
441
441
. filter ( |it| !ctx. is_std_item || !it. is_sysroot ( ) )
442
442
. for_each ( |dep| _ = process_dep ( dep. crate_id , 0 ) ) ;
443
- best_choice
444
443
}
445
444
}
446
445
@@ -449,40 +448,31 @@ fn calculate_best_path_local(
449
448
visited_modules : & mut FxHashSet < ModuleId > ,
450
449
item : ItemInNs ,
451
450
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
+ ) {
459
453
// FIXME: cache the `find_local_import_locations` output?
460
454
find_local_import_locations ( ctx. db , item, ctx. from , ctx. from_def_map , |name, module_id| {
461
455
if !visited_modules. insert ( module_id) {
462
456
return ;
463
457
}
464
458
// we are looking for paths of length up to best_path_len, any longer will make it be
465
459
// 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 (
467
461
ctx,
468
462
visited_modules,
469
463
module_id,
470
464
false ,
471
465
best_choice. as_ref ( ) . map_or ( max_len, |it| it. path . len ( ) ) - 1 ,
472
466
) {
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 ( ) ) ;
477
468
}
478
469
} ) ;
479
- best_choice
480
470
}
481
471
482
472
struct Choice {
483
473
path : ModPath ,
484
474
/// The length in characters of the path
485
- path_len : usize ,
475
+ path_text_len : usize ,
486
476
/// The stability of the path
487
477
stability : Stability ,
488
478
/// Whether this path contains a prelude segment and preference for it has been signaled
@@ -494,7 +484,7 @@ struct Choice {
494
484
impl Choice {
495
485
fn new ( prefer_prelude : bool , kind : PathKind , name : Name , stability : Stability ) -> Self {
496
486
Self {
497
- path_len : path_kind_len ( kind) + name. as_str ( ) . len ( ) ,
487
+ path_text_len : path_kind_len ( kind) + name. as_str ( ) . len ( ) ,
498
488
stability,
499
489
prefer_due_to_prelude : prefer_prelude && name == sym:: prelude,
500
490
sysroot_score : 0 ,
@@ -503,37 +493,44 @@ impl Choice {
503
493
}
504
494
505
495
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 ( ) ;
507
497
self . prefer_due_to_prelude |= prefer_prelude && name == sym:: prelude;
508
498
self . path . push_segment ( name) ;
509
499
self
510
500
}
511
501
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
+ } ;
513
512
match other
514
513
. 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 ) ) )
519
518
{
520
- Ordering :: Less => self ,
519
+ Ordering :: Less => return ,
521
520
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 ;
530
526
}
531
527
}
532
528
Ordering :: Greater => {
533
- other. path . push_segment ( name) ;
534
- other
529
+ other. path_text_len += name. as_str ( ) . len ( ) ;
535
530
}
536
531
}
532
+ other. path . push_segment ( name) ;
533
+ * current = other;
537
534
}
538
535
}
539
536
0 commit comments