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 https://github.com/rust-lang/rust-analyzer/issues/17540
This commit is contained in:
bors 2024-07-21 07:24:38 +00:00
commit 88258b7fd2
2 changed files with 69 additions and 6 deletions

View file

@ -1,7 +1,8 @@
//! An algorithm to find a path to refer to a certain item.
use std::{cell::Cell, cmp::Ordering, iter};
use std::{cell::Cell, cmp::Ordering, iter, ops::BitOr};
use base_db::CrateId;
use hir_expand::{
name::{AsName, Name},
Lookup,
@ -37,7 +38,8 @@ pub fn find_path(
// within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
// default to plain paths.
if item.module(db).is_some_and(ModuleId::is_within_block) {
let item_module = item.module(db)?;
if item_module.is_within_block() {
prefix_kind = PrefixKind::Plain;
}
cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
@ -50,6 +52,7 @@ pub fn find_path(
ignore_local_imports,
from,
from_def_map: &from.def_map(db),
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
fuel: Cell::new(FIND_PATH_FUEL),
},
item,
@ -104,6 +107,7 @@ struct FindPathCtx<'db> {
ignore_local_imports: bool,
from: ModuleId,
from_def_map: &'db DefMap,
is_std_item: bool,
fuel: Cell<usize>,
}
@ -373,9 +377,12 @@ fn calculate_best_path(
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
// that wants to import it here, but we always prefer to use the external path here.
for dep in &db.crate_graph()[ctx.from.krate].dependencies {
let import_map = db.import_map(dep.crate_id);
let Some(import_info_for) = import_map.import_info_for(item) else { continue };
let mut process_dep = |dep: CrateId| {
let import_map = db.import_map(dep);
let Some(import_info_for) = import_map.import_info_for(item) else {
return false;
};
let mut processed_something = false;
for info in import_info_for {
if info.is_doc_hidden {
// 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(
);
process(path, info.name.clone(), &mut best_path_len);
processed_something = true;
}
processed_something
};
let dependencies = &db.crate_graph()[ctx.from.krate].dependencies;
if ctx.is_std_item {
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
// the sysroot libraries directly.
// We do need to fallback as the item in question could be re-exported by another crate
// while not being a transitive dependency of the current crate.
let processed = dependencies
.iter()
.filter(|it| it.is_sysroot())
.map(|dep| process_dep(dep.crate_id))
.reduce(BitOr::bitor)
.unwrap_or(false);
if processed {
// Found a path in a sysroot crate, so return it.
return best_path;
}
}
dependencies
.iter()
.filter(|it| !ctx.is_std_item || !it.is_sysroot())
.for_each(|dep| _ = process_dep(dep.crate_id));
}
best_path
}
@ -1918,4 +1950,34 @@ pub fn c() {}
"#]],
);
}
#[test]
fn prefer_long_std_over_short_extern() {
check_found_path(
r#"
//- /lib.rs crate:main deps:futures_lite,std,core
$0
//- /futures_lite.rs crate:futures_lite deps:std,core
pub use crate::future::Future;
pub mod future {
pub use core::future::Future;
}
//- /std.rs crate:std deps:core
pub use core::future;
//- /core.rs crate:core
pub mod future {
pub trait Future {}
}
"#,
"core::future::Future",
expect![[r#"
Plain (imports ): std::future::Future
Plain (imports ): std::future::Future
ByCrate(imports ): std::future::Future
ByCrate(imports ): std::future::Future
BySelf (imports ): std::future::Future
BySelf (imports ): std::future::Future
"#]],
);
}
}

View file

@ -246,6 +246,7 @@ impl ChangeFixture {
for (from, to, prelude) in crate_deps {
let from_id = crates[&from];
let to_id = crates[&to];
let sysroot = crate_graph[to_id].origin.is_lang();
crate_graph
.add_dep(
from_id,
@ -253,7 +254,7 @@ impl ChangeFixture {
CrateName::new(&to).unwrap(),
to_id,
prelude,
false,
sysroot,
),
)
.unwrap();