Skip to content

Commit 38352c5

Browse files
committed
Auto merge of #17653 - Veykril:std-find-path, r=Veykril
Prefer standard library paths over shorter extern deps re-exports This should generally speed up path finding for std items as we no longer bother looking through all external dependencies. It also makes more sense to prefer importing std items from the std dependencies directly. Fixes rust-lang/rust-analyzer#17540
2 parents 449d4c4 + cfdcaa7 commit 38352c5

File tree

2 files changed

+69
-6
lines changed

2 files changed

+69
-6
lines changed

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

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
//! An algorithm to find a path to refer to a certain item.
22
3-
use std::{cell::Cell, cmp::Ordering, iter};
3+
use std::{cell::Cell, cmp::Ordering, iter, ops::BitOr};
44

5+
use base_db::CrateId;
56
use hir_expand::{
67
name::{AsName, Name},
78
Lookup,
@@ -37,7 +38,8 @@ pub fn find_path(
3738

3839
// within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
3940
// default to plain paths.
40-
if item.module(db).is_some_and(ModuleId::is_within_block) {
41+
let item_module = item.module(db)?;
42+
if item_module.is_within_block() {
4143
prefix_kind = PrefixKind::Plain;
4244
}
4345
cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
@@ -50,6 +52,7 @@ pub fn find_path(
5052
ignore_local_imports,
5153
from,
5254
from_def_map: &from.def_map(db),
55+
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
5356
fuel: Cell::new(FIND_PATH_FUEL),
5457
},
5558
item,
@@ -104,6 +107,7 @@ struct FindPathCtx<'db> {
104107
ignore_local_imports: bool,
105108
from: ModuleId,
106109
from_def_map: &'db DefMap,
110+
is_std_item: bool,
107111
fuel: Cell<usize>,
108112
}
109113

@@ -373,9 +377,12 @@ fn calculate_best_path(
373377
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
374378
// that wants to import it here, but we always prefer to use the external path here.
375379

376-
for dep in &db.crate_graph()[ctx.from.krate].dependencies {
377-
let import_map = db.import_map(dep.crate_id);
378-
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
380+
let mut process_dep = |dep: CrateId| {
381+
let import_map = db.import_map(dep);
382+
let Some(import_info_for) = import_map.import_info_for(item) else {
383+
return false;
384+
};
385+
let mut processed_something = false;
379386
for info in import_info_for {
380387
if info.is_doc_hidden {
381388
// the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
@@ -396,8 +403,33 @@ fn calculate_best_path(
396403
);
397404

398405
process(path, info.name.clone(), &mut best_path_len);
406+
processed_something = true;
407+
}
408+
processed_something
409+
};
410+
411+
let dependencies = &db.crate_graph()[ctx.from.krate].dependencies;
412+
if ctx.is_std_item {
413+
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
414+
// the sysroot libraries directly.
415+
// We do need to fallback as the item in question could be re-exported by another crate
416+
// while not being a transitive dependency of the current crate.
417+
let processed = dependencies
418+
.iter()
419+
.filter(|it| it.is_sysroot())
420+
.map(|dep| process_dep(dep.crate_id))
421+
.reduce(BitOr::bitor)
422+
.unwrap_or(false);
423+
if processed {
424+
// Found a path in a sysroot crate, so return it.
425+
return best_path;
399426
}
400427
}
428+
429+
dependencies
430+
.iter()
431+
.filter(|it| !ctx.is_std_item || !it.is_sysroot())
432+
.for_each(|dep| _ = process_dep(dep.crate_id));
401433
}
402434
best_path
403435
}
@@ -1918,4 +1950,34 @@ pub fn c() {}
19181950
"#]],
19191951
);
19201952
}
1953+
1954+
#[test]
1955+
fn prefer_long_std_over_short_extern() {
1956+
check_found_path(
1957+
r#"
1958+
//- /lib.rs crate:main deps:futures_lite,std,core
1959+
$0
1960+
//- /futures_lite.rs crate:futures_lite deps:std,core
1961+
pub use crate::future::Future;
1962+
pub mod future {
1963+
pub use core::future::Future;
1964+
}
1965+
//- /std.rs crate:std deps:core
1966+
pub use core::future;
1967+
//- /core.rs crate:core
1968+
pub mod future {
1969+
pub trait Future {}
1970+
}
1971+
"#,
1972+
"core::future::Future",
1973+
expect![[r#"
1974+
Plain (imports ✔): std::future::Future
1975+
Plain (imports ✖): std::future::Future
1976+
ByCrate(imports ✔): std::future::Future
1977+
ByCrate(imports ✖): std::future::Future
1978+
BySelf (imports ✔): std::future::Future
1979+
BySelf (imports ✖): std::future::Future
1980+
"#]],
1981+
);
1982+
}
19211983
}

src/tools/rust-analyzer/crates/test-fixture/src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,14 +246,15 @@ impl ChangeFixture {
246246
for (from, to, prelude) in crate_deps {
247247
let from_id = crates[&from];
248248
let to_id = crates[&to];
249+
let sysroot = crate_graph[to_id].origin.is_lang();
249250
crate_graph
250251
.add_dep(
251252
from_id,
252253
Dependency::with_prelude(
253254
CrateName::new(&to).unwrap(),
254255
to_id,
255256
prelude,
256-
false,
257+
sysroot,
257258
),
258259
)
259260
.unwrap();

0 commit comments

Comments
 (0)