Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit d934433

Browse files
committed
Use out parameter instead of return value for find_path choice
1 parent 5a02f69 commit d934433

File tree

1 file changed

+53
-56
lines changed

1 file changed

+53
-56
lines changed

src/tools/rust-analyzer/crates/hir-def/src/find_path.rs

Lines changed: 53 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -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

255263
fn 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

482472
struct 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 {
494484
impl 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

Comments
 (0)