Skip to content

Commit 0daeb5c

Browse files
committed
Auto merge of #17844 - Veykril:find-path-std-fix, r=Veykril
fix: Fix find_path not respecting non-std preference config correctly Fixes #17840
2 parents 0832df8 + 24c0e0b commit 0daeb5c

File tree

11 files changed

+124
-104
lines changed

11 files changed

+124
-104
lines changed

crates/hir-def/src/find_path.rs

+98-45
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,13 @@ pub fn find_path(
5050
prefix: prefix_kind,
5151
cfg,
5252
ignore_local_imports,
53+
is_std_item: db.crate_graph()[item_module.krate()].origin.is_lang(),
5354
from,
5455
from_def_map: &from.def_map(db),
5556
fuel: Cell::new(FIND_PATH_FUEL),
5657
},
5758
item,
5859
MAX_PATH_LEN,
59-
db.crate_graph()[item_module.krate()].origin.is_lang(),
6060
)
6161
}
6262

@@ -98,20 +98,16 @@ struct FindPathCtx<'db> {
9898
prefix: PrefixKind,
9999
cfg: ImportPathConfig,
100100
ignore_local_imports: bool,
101+
is_std_item: bool,
101102
from: ModuleId,
102103
from_def_map: &'db DefMap,
103104
fuel: Cell<usize>,
104105
}
105106

106107
/// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
107-
fn find_path_inner(
108-
ctx: &FindPathCtx<'_>,
109-
item: ItemInNs,
110-
max_len: usize,
111-
is_std_item: bool,
112-
) -> Option<ModPath> {
108+
fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
113109
// - if the item is a module, jump straight to module search
114-
if !is_std_item {
110+
if !ctx.is_std_item {
115111
if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
116112
return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
117113
.map(|choice| choice.path);
@@ -138,12 +134,9 @@ fn find_path_inner(
138134

139135
if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
140136
// - if the item is an enum variant, refer to it via the enum
141-
if let Some(mut path) = find_path_inner(
142-
ctx,
143-
ItemInNs::Types(variant.lookup(ctx.db).parent.into()),
144-
max_len,
145-
is_std_item,
146-
) {
137+
if let Some(mut path) =
138+
find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len)
139+
{
147140
path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
148141
return Some(path);
149142
}
@@ -152,16 +145,6 @@ fn find_path_inner(
152145
// variant somewhere
153146
}
154147

155-
if is_std_item {
156-
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
157-
// the sysroot libraries directly.
158-
// We do need to fallback as the item in question could be re-exported by another crate
159-
// while not being a transitive dependency of the current crate.
160-
if let Some(choice) = find_in_sysroot(ctx, &mut FxHashSet::default(), item, max_len) {
161-
return Some(choice.path);
162-
}
163-
}
164-
165148
let mut best_choice = None;
166149
calculate_best_path(ctx, &mut FxHashSet::default(), item, max_len, &mut best_choice);
167150
best_choice.map(|choice| choice.path)
@@ -366,6 +349,12 @@ fn calculate_best_path(
366349
// Item was defined in the same crate that wants to import it. It cannot be found in any
367350
// dependency in this case.
368351
calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
352+
} else if ctx.is_std_item {
353+
// The item we are searching for comes from the sysroot libraries, so skip prefer looking in
354+
// the sysroot libraries directly.
355+
// We do need to fallback as the item in question could be re-exported by another crate
356+
// while not being a transitive dependency of the current crate.
357+
find_in_sysroot(ctx, visited_modules, item, max_len, best_choice)
369358
} else {
370359
// Item was defined in some upstream crate. This means that it must be exported from one,
371360
// too (unless we can't name it at all). It could *also* be (re)exported by the same crate
@@ -382,10 +371,10 @@ fn find_in_sysroot(
382371
visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
383372
item: ItemInNs,
384373
max_len: usize,
385-
) -> Option<Choice> {
374+
best_choice: &mut Option<Choice>,
375+
) {
386376
let crate_graph = ctx.db.crate_graph();
387377
let dependencies = &crate_graph[ctx.from.krate].dependencies;
388-
let mut best_choice = None;
389378
let mut search = |lang, best_choice: &mut _| {
390379
if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
391380
match crate_graph[dep.crate_id].origin {
@@ -397,29 +386,31 @@ fn find_in_sysroot(
397386
}
398387
};
399388
if ctx.cfg.prefer_no_std {
400-
search(LangCrateOrigin::Core, &mut best_choice);
389+
search(LangCrateOrigin::Core, best_choice);
401390
if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
402-
return best_choice;
391+
return;
403392
}
404-
search(LangCrateOrigin::Std, &mut best_choice);
393+
search(LangCrateOrigin::Std, best_choice);
405394
if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
406-
return best_choice;
395+
return;
407396
}
408397
} else {
409-
search(LangCrateOrigin::Std, &mut best_choice);
398+
search(LangCrateOrigin::Std, best_choice);
410399
if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
411-
return best_choice;
400+
return;
412401
}
413-
search(LangCrateOrigin::Core, &mut best_choice);
402+
search(LangCrateOrigin::Core, best_choice);
414403
if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
415-
return best_choice;
404+
return;
416405
}
417406
}
418-
let mut best_choice = None;
419-
dependencies.iter().filter(|it| it.is_sysroot()).for_each(|dep| {
420-
find_in_dep(ctx, visited_modules, item, max_len, &mut best_choice, dep.crate_id);
421-
});
422-
best_choice
407+
dependencies
408+
.iter()
409+
.filter(|it| it.is_sysroot())
410+
.chain(dependencies.iter().filter(|it| !it.is_sysroot()))
411+
.for_each(|dep| {
412+
find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id);
413+
});
423414
}
424415

425416
fn find_in_dep(
@@ -491,6 +482,7 @@ fn calculate_best_path_local(
491482
);
492483
}
493484

485+
#[derive(Debug)]
494486
struct Choice {
495487
path: ModPath,
496488
/// The length in characters of the path
@@ -676,6 +668,7 @@ mod tests {
676668
path: &str,
677669
prefer_prelude: bool,
678670
prefer_absolute: bool,
671+
prefer_no_std: bool,
679672
expect: Expect,
680673
) {
681674
let (db, pos) = TestDB::with_position(ra_fixture);
@@ -717,7 +710,7 @@ mod tests {
717710
module,
718711
prefix,
719712
ignore_local_imports,
720-
ImportPathConfig { prefer_no_std: false, prefer_prelude, prefer_absolute },
713+
ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
721714
);
722715
format_to!(
723716
res,
@@ -732,15 +725,19 @@ mod tests {
732725
}
733726

734727
fn check_found_path(ra_fixture: &str, path: &str, expect: Expect) {
735-
check_found_path_(ra_fixture, path, false, false, expect);
728+
check_found_path_(ra_fixture, path, false, false, false, expect);
736729
}
737730

738731
fn check_found_path_prelude(ra_fixture: &str, path: &str, expect: Expect) {
739-
check_found_path_(ra_fixture, path, true, false, expect);
732+
check_found_path_(ra_fixture, path, true, false, false, expect);
740733
}
741734

742735
fn check_found_path_absolute(ra_fixture: &str, path: &str, expect: Expect) {
743-
check_found_path_(ra_fixture, path, false, true, expect);
736+
check_found_path_(ra_fixture, path, false, true, false, expect);
737+
}
738+
739+
fn check_found_path_prefer_no_std(ra_fixture: &str, path: &str, expect: Expect) {
740+
check_found_path_(ra_fixture, path, false, false, true, expect);
744741
}
745742

746743
#[test]
@@ -1361,9 +1358,66 @@ pub mod sync {
13611358
"#]],
13621359
);
13631360
}
1361+
#[test]
1362+
fn prefer_core_paths_over_std_for_mod_reexport() {
1363+
check_found_path_prefer_no_std(
1364+
r#"
1365+
//- /main.rs crate:main deps:core,std
1366+
1367+
$0
1368+
1369+
//- /stdlib.rs crate:std deps:core
1370+
1371+
pub use core::pin;
1372+
1373+
//- /corelib.rs crate:core
1374+
1375+
pub mod pin {
1376+
pub struct Pin;
1377+
}
1378+
"#,
1379+
"std::pin::Pin",
1380+
expect![[r#"
1381+
Plain (imports ✔): core::pin::Pin
1382+
Plain (imports ✖): core::pin::Pin
1383+
ByCrate(imports ✔): core::pin::Pin
1384+
ByCrate(imports ✖): core::pin::Pin
1385+
BySelf (imports ✔): core::pin::Pin
1386+
BySelf (imports ✖): core::pin::Pin
1387+
"#]],
1388+
);
1389+
}
13641390

13651391
#[test]
13661392
fn prefer_core_paths_over_std() {
1393+
check_found_path_prefer_no_std(
1394+
r#"
1395+
//- /main.rs crate:main deps:core,std
1396+
1397+
$0
1398+
1399+
//- /std.rs crate:std deps:core
1400+
1401+
pub mod fmt {
1402+
pub use core::fmt::Error;
1403+
}
1404+
1405+
//- /zzz.rs crate:core
1406+
1407+
pub mod fmt {
1408+
pub struct Error;
1409+
}
1410+
"#,
1411+
"core::fmt::Error",
1412+
expect![[r#"
1413+
Plain (imports ✔): core::fmt::Error
1414+
Plain (imports ✖): core::fmt::Error
1415+
ByCrate(imports ✔): core::fmt::Error
1416+
ByCrate(imports ✖): core::fmt::Error
1417+
BySelf (imports ✔): core::fmt::Error
1418+
BySelf (imports ✖): core::fmt::Error
1419+
"#]],
1420+
);
13671421
check_found_path(
13681422
r#"
13691423
//- /main.rs crate:main deps:core,std
@@ -1878,10 +1932,9 @@ pub mod ops {
18781932

18791933
#[test]
18801934
fn respect_unstable_modules() {
1881-
check_found_path(
1935+
check_found_path_prefer_no_std(
18821936
r#"
18831937
//- /main.rs crate:main deps:std,core
1884-
#![no_std]
18851938
extern crate std;
18861939
$0
18871940
//- /longer.rs crate:std deps:core

crates/hir-def/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ use crate::{
105105

106106
type FxIndexMap<K, V> =
107107
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
108-
/// A wrapper around two booleans, [`ImportPathConfig::prefer_no_std`] and [`ImportPathConfig::prefer_prelude`].
108+
/// A wrapper around three booleans
109109
#[derive(Debug, Clone, PartialEq, Eq, Hash, Copy)]
110110
pub struct ImportPathConfig {
111111
/// If true, prefer to unconditionally use imports of the `core` and `alloc` crate

crates/hir-ty/src/display.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1069,6 +1069,7 @@ impl HirDisplay for Ty {
10691069
module_id,
10701070
PrefixKind::Plain,
10711071
false,
1072+
// FIXME: no_std Cfg?
10721073
ImportPathConfig {
10731074
prefer_no_std: false,
10741075
prefer_prelude: true,

crates/ide-completion/src/completions.rs

+2-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub(crate) mod vis;
2424

2525
use std::iter;
2626

27-
use hir::{sym, HasAttrs, ImportPathConfig, Name, ScopeDef, Variant};
27+
use hir::{sym, HasAttrs, Name, ScopeDef, Variant};
2828
use ide_db::{imports::import_assets::LocatedImport, RootDatabase, SymbolKind};
2929
use syntax::{ast, SmolStr, ToSmolStr};
3030

@@ -645,11 +645,7 @@ fn enum_variants_with_paths(
645645
if let Some(path) = ctx.module.find_path(
646646
ctx.db,
647647
hir::ModuleDef::from(variant),
648-
ImportPathConfig {
649-
prefer_no_std: ctx.config.prefer_no_std,
650-
prefer_prelude: ctx.config.prefer_prelude,
651-
prefer_absolute: ctx.config.prefer_absolute,
652-
},
648+
ctx.config.import_path_config(),
653649
) {
654650
// Variants with trivial paths are already added by the existing completion logic,
655651
// so we should avoid adding these twice

crates/ide-completion/src/completions/expr.rs

+3-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Completion of names from the current scope in expression position.
22
3-
use hir::{sym, ImportPathConfig, Name, ScopeDef};
3+
use hir::{sym, Name, ScopeDef};
44
use syntax::ast;
55

66
use crate::{
@@ -174,11 +174,7 @@ pub(crate) fn complete_expr_path(
174174
.find_path(
175175
ctx.db,
176176
hir::ModuleDef::from(strukt),
177-
ImportPathConfig {
178-
prefer_no_std: ctx.config.prefer_no_std,
179-
prefer_prelude: ctx.config.prefer_prelude,
180-
prefer_absolute: ctx.config.prefer_absolute,
181-
},
177+
ctx.config.import_path_config(),
182178
)
183179
.filter(|it| it.len() > 1);
184180

@@ -200,11 +196,7 @@ pub(crate) fn complete_expr_path(
200196
.find_path(
201197
ctx.db,
202198
hir::ModuleDef::from(un),
203-
ImportPathConfig {
204-
prefer_no_std: ctx.config.prefer_no_std,
205-
prefer_prelude: ctx.config.prefer_prelude,
206-
prefer_absolute: ctx.config.prefer_absolute,
207-
},
199+
ctx.config.import_path_config(),
208200
)
209201
.filter(|it| it.len() > 1);
210202

crates/ide-completion/src/completions/flyimport.rs

+4-17
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
//! See [`import_on_the_fly`].
2-
use hir::{ImportPathConfig, ItemInNs, ModuleDef};
2+
use hir::{ItemInNs, ModuleDef};
33
use ide_db::imports::{
44
import_assets::{ImportAssets, LocatedImport},
55
insert_use::ImportScope,
@@ -256,11 +256,7 @@ fn import_on_the_fly(
256256
};
257257
let user_input_lowercased = potential_import_name.to_lowercase();
258258

259-
let import_cfg = ImportPathConfig {
260-
prefer_no_std: ctx.config.prefer_no_std,
261-
prefer_prelude: ctx.config.prefer_prelude,
262-
prefer_absolute: ctx.config.prefer_absolute,
263-
};
259+
let import_cfg = ctx.config.import_path_config();
264260

265261
import_assets
266262
.search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@@ -306,12 +302,7 @@ fn import_on_the_fly_pat_(
306302
ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
307303
};
308304
let user_input_lowercased = potential_import_name.to_lowercase();
309-
310-
let cfg = ImportPathConfig {
311-
prefer_no_std: ctx.config.prefer_no_std,
312-
prefer_prelude: ctx.config.prefer_prelude,
313-
prefer_absolute: ctx.config.prefer_absolute,
314-
};
305+
let cfg = ctx.config.import_path_config();
315306

316307
import_assets
317308
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -353,11 +344,7 @@ fn import_on_the_fly_method(
353344

354345
let user_input_lowercased = potential_import_name.to_lowercase();
355346

356-
let cfg = ImportPathConfig {
357-
prefer_no_std: ctx.config.prefer_no_std,
358-
prefer_prelude: ctx.config.prefer_prelude,
359-
prefer_absolute: ctx.config.prefer_absolute,
360-
};
347+
let cfg = ctx.config.import_path_config();
361348

362349
import_assets
363350
.search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)

0 commit comments

Comments
 (0)