Skip to content

Commit 484db3a

Browse files
Merge pull request #20475 from ShoyuVanilla/analysis-std-panic
fix: Make lang items query properly filter out overwritten/excluded sysroots
2 parents e10fa93 + 15ac6a2 commit 484db3a

File tree

7 files changed

+166
-68
lines changed

7 files changed

+166
-68
lines changed

crates/base-db/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ use triomphe::Arc;
3030
pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet};
3131

3232
pub type FxIndexSet<T> = indexmap::IndexSet<T, rustc_hash::FxBuildHasher>;
33+
pub type FxIndexMap<K, V> =
34+
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
3335

3436
#[macro_export]
3537
macro_rules! impl_intern_key {

crates/hir-def/src/lang_item.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::{
1212
StaticId, StructId, TraitId, TypeAliasId, UnionId,
1313
db::DefDatabase,
1414
expr_store::path::Path,
15-
nameres::{assoc::TraitItems, crate_def_map},
15+
nameres::{assoc::TraitItems, crate_def_map, crate_local_def_map},
1616
};
1717

1818
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -170,7 +170,19 @@ pub fn lang_item(
170170
{
171171
return Some(target);
172172
}
173-
start_crate.data(db).dependencies.iter().find_map(|dep| lang_item(db, dep.crate_id, item))
173+
174+
// Our `CrateGraph` eagerly inserts sysroot dependencies like `core` or `std` into dependencies
175+
// even if the target crate has `#![no_std]`, `#![no_core]` or shadowed sysroot dependencies
176+
// like `dependencies.std.path = ".."`. So we use `extern_prelude()` instead of
177+
// `CrateData.dependencies` here, which has already come through such sysroot complexities
178+
// while nameres.
179+
//
180+
// See https://github.com/rust-lang/rust-analyzer/pull/20475 for details.
181+
crate_local_def_map(db, start_crate).local(db).extern_prelude().find_map(|(_, (krate, _))| {
182+
// Some crates declares themselves as extern crate like `extern crate self as core`.
183+
// Ignore these to prevent cycles.
184+
if krate.krate == start_crate { None } else { lang_item(db, krate.krate, item) }
185+
})
174186
}
175187

176188
#[derive(Default, Debug, Clone, PartialEq, Eq)]

crates/hir-def/src/nameres.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -545,6 +545,10 @@ impl DefMap {
545545
self.data.no_std || self.data.no_core
546546
}
547547

548+
pub fn is_no_core(&self) -> bool {
549+
self.data.no_core
550+
}
551+
548552
pub fn fn_as_proc_macro(&self, id: FunctionId) -> Option<ProcMacroId> {
549553
self.data.fn_proc_macro_mapping.get(&id).copied()
550554
}

crates/hir-def/src/nameres/collector.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ use triomphe::Arc;
2727

2828
use crate::{
2929
AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
30-
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
31-
LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
32-
MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
33-
StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId, UseLoc,
30+
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern,
31+
ItemContainerId, LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
32+
MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
33+
ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId,
34+
UseLoc,
3435
attr::Attrs,
3536
db::DefDatabase,
3637
item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
@@ -69,7 +70,7 @@ pub(super) fn collect_defs(
6970

7071
// populate external prelude and dependency list
7172
let mut deps =
72-
FxHashMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default());
73+
FxIndexMap::with_capacity_and_hasher(krate.dependencies.len(), Default::default());
7374
for dep in &krate.dependencies {
7475
tracing::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
7576

@@ -220,7 +221,7 @@ struct DefCollector<'db> {
220221
/// Set only in case of blocks.
221222
crate_local_def_map: Option<&'db LocalDefMap>,
222223
// The dependencies of the current crate, including optional deps like `test`.
223-
deps: FxHashMap<Name, BuiltDependency>,
224+
deps: FxIndexMap<Name, BuiltDependency>,
224225
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
225226
unresolved_imports: Vec<ImportDirective>,
226227
indeterminate_imports: Vec<(ImportDirective, PerNs)>,
@@ -332,7 +333,9 @@ impl<'db> DefCollector<'db> {
332333
let skip = dep.is_sysroot()
333334
&& match dep.crate_id.data(self.db).origin {
334335
CrateOrigin::Lang(LangCrateOrigin::Core) => crate_data.no_core,
335-
CrateOrigin::Lang(LangCrateOrigin::Std) => crate_data.no_std,
336+
CrateOrigin::Lang(LangCrateOrigin::Std) => {
337+
crate_data.no_core || crate_data.no_std
338+
}
336339
_ => false,
337340
};
338341
if skip {
@@ -2550,7 +2553,7 @@ mod tests {
25502553
def_map,
25512554
local_def_map: LocalDefMap::default(),
25522555
crate_local_def_map: None,
2553-
deps: FxHashMap::default(),
2556+
deps: FxIndexMap::default(),
25542557
glob_imports: FxHashMap::default(),
25552558
unresolved_imports: Vec::new(),
25562559
indeterminate_imports: Vec::new(),

crates/hir-ty/src/tests/regression.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2388,3 +2388,54 @@ pub trait Destruct {}
23882388
"#,
23892389
);
23902390
}
2391+
2392+
#[test]
2393+
fn no_duplicated_lang_item_metadata() {
2394+
check_types(
2395+
r#"
2396+
//- minicore: pointee
2397+
//- /main.rs crate:main deps:std,core
2398+
use std::AtomicPtr;
2399+
use std::null_mut;
2400+
2401+
fn main() {
2402+
let x: AtomicPtr<()> = AtomicPtr::new(null_mut());
2403+
//^ AtomicPtr<()>
2404+
}
2405+
2406+
//- /lib.rs crate:r#std deps:core
2407+
#![no_std]
2408+
pub use core::*;
2409+
2410+
//- /lib.rs crate:r#core
2411+
#![no_core]
2412+
2413+
#[lang = "pointee_trait"]
2414+
pub trait Pointee {
2415+
#[lang = "metadata_type"]
2416+
type Metadata;
2417+
}
2418+
2419+
pub struct AtomicPtr<T>(T);
2420+
2421+
impl<T> AtomicPtr<T> {
2422+
pub fn new(p: *mut T) -> AtomicPtr<T> {
2423+
loop {}
2424+
}
2425+
}
2426+
2427+
#[lang = "pointee_sized"]
2428+
pub trait PointeeSized {}
2429+
#[lang = "meta_sized"]
2430+
pub trait MetaSized: PointeeSized {}
2431+
#[lang = "sized"]
2432+
pub trait Sized: MetaSized {}
2433+
2434+
pub trait Thin = Pointee<Metadata = ()> + PointeeSized;
2435+
2436+
pub fn null_mut<T: PointeeSized + Thin>() -> *mut T {
2437+
loop {}
2438+
}
2439+
"#,
2440+
);
2441+
}

crates/ide-db/src/lib.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,9 @@ pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
6666
pub use ::line_index;
6767

6868
/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
69-
pub use base_db;
69+
pub use base_db::{self, FxIndexMap, FxIndexSet};
7070
pub use span::{self, FileId};
7171

72-
pub type FxIndexSet<T> = indexmap::IndexSet<T, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
73-
pub type FxIndexMap<K, V> =
74-
indexmap::IndexMap<K, V, std::hash::BuildHasherDefault<rustc_hash::FxHasher>>;
75-
7672
pub type FilePosition = FilePositionWrapper<FileId>;
7773
pub type FileRange = FileRangeWrapper<FileId>;
7874

crates/test-fixture/src/lib.rs

Lines changed: 83 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use std::{any::TypeId, mem, str::FromStr, sync};
33

44
use base_db::{
55
Crate, CrateDisplayName, CrateGraphBuilder, CrateName, CrateOrigin, CrateWorkspaceData,
6-
DependencyBuilder, Env, FileChange, FileSet, LangCrateOrigin, SourceDatabase, SourceRoot,
7-
Version, VfsPath, salsa,
6+
DependencyBuilder, Env, FileChange, FileSet, FxIndexMap, LangCrateOrigin, SourceDatabase,
7+
SourceRoot, Version, VfsPath, salsa,
88
};
99
use cfg::CfgOptions;
1010
use hir_expand::{
@@ -20,7 +20,6 @@ use hir_expand::{
2020
};
2121
use intern::{Symbol, sym};
2222
use paths::AbsPathBuf;
23-
use rustc_hash::FxHashMap;
2423
use span::{Edition, FileId, Span};
2524
use stdx::itertools::Itertools;
2625
use test_utils::{
@@ -147,7 +146,7 @@ impl ChangeFixture {
147146

148147
let mut files = Vec::new();
149148
let mut crate_graph = CrateGraphBuilder::default();
150-
let mut crates = FxHashMap::default();
149+
let mut crates = FxIndexMap::default();
151150
let mut crate_deps = Vec::new();
152151
let mut default_crate_root: Option<FileId> = None;
153152
let mut default_edition = Edition::CURRENT;
@@ -249,37 +248,7 @@ impl ChangeFixture {
249248
file_id = FileId::from_raw(file_id.index() + 1);
250249
}
251250

252-
if crates.is_empty() {
253-
let crate_root = default_crate_root
254-
.expect("missing default crate root, specify a main.rs or lib.rs");
255-
crate_graph.add_crate_root(
256-
crate_root,
257-
default_edition,
258-
Some(CrateName::new("ra_test_fixture").unwrap().into()),
259-
None,
260-
default_cfg.clone(),
261-
Some(default_cfg),
262-
default_env,
263-
CrateOrigin::Local { repo: None, name: None },
264-
false,
265-
proc_macro_cwd.clone(),
266-
crate_ws_data.clone(),
267-
);
268-
} else {
269-
for (from, to, prelude) in crate_deps {
270-
let from_id = crates[&from];
271-
let to_id = crates[&to];
272-
let sysroot = crate_graph[to_id].basic.origin.is_lang();
273-
crate_graph
274-
.add_dep(
275-
from_id,
276-
DependencyBuilder::with_prelude(to.clone(), to_id, prelude, sysroot),
277-
)
278-
.unwrap();
279-
}
280-
}
281-
282-
if let Some(mini_core) = mini_core {
251+
let mini_core = mini_core.map(|mini_core| {
283252
let core_file = file_id;
284253
file_id = FileId::from_raw(file_id.index() + 1);
285254

@@ -289,8 +258,6 @@ impl ChangeFixture {
289258

290259
source_change.change_file(core_file, Some(mini_core.source_code()));
291260

292-
let all_crates = crate_graph.iter().collect::<Vec<_>>();
293-
294261
let core_crate = crate_graph.add_crate_root(
295262
core_file,
296263
Edition::CURRENT,
@@ -308,16 +275,58 @@ impl ChangeFixture {
308275
crate_ws_data.clone(),
309276
);
310277

311-
for krate in all_crates {
278+
(
279+
move || {
280+
DependencyBuilder::with_prelude(
281+
CrateName::new("core").unwrap(),
282+
core_crate,
283+
true,
284+
true,
285+
)
286+
},
287+
core_crate,
288+
)
289+
});
290+
291+
if crates.is_empty() {
292+
let crate_root = default_crate_root
293+
.expect("missing default crate root, specify a main.rs or lib.rs");
294+
let root = crate_graph.add_crate_root(
295+
crate_root,
296+
default_edition,
297+
Some(CrateName::new("ra_test_fixture").unwrap().into()),
298+
None,
299+
default_cfg.clone(),
300+
Some(default_cfg),
301+
default_env,
302+
CrateOrigin::Local { repo: None, name: None },
303+
false,
304+
proc_macro_cwd.clone(),
305+
crate_ws_data.clone(),
306+
);
307+
if let Some((mini_core, _)) = mini_core {
308+
crate_graph.add_dep(root, mini_core()).unwrap();
309+
}
310+
} else {
311+
// Insert minicore first to match with `project-model::workspace`
312+
if let Some((mini_core, core_crate)) = mini_core {
313+
let all_crates = crate_graph.iter().collect::<Vec<_>>();
314+
for krate in all_crates {
315+
if krate == core_crate {
316+
continue;
317+
}
318+
crate_graph.add_dep(krate, mini_core()).unwrap();
319+
}
320+
}
321+
322+
for (from, to, prelude) in crate_deps {
323+
let from_id = crates[&from];
324+
let to_id = crates[&to];
325+
let sysroot = crate_graph[to_id].basic.origin.is_lang();
312326
crate_graph
313327
.add_dep(
314-
krate,
315-
DependencyBuilder::with_prelude(
316-
CrateName::new("core").unwrap(),
317-
core_crate,
318-
true,
319-
true,
320-
),
328+
from_id,
329+
DependencyBuilder::with_prelude(to.clone(), to_id, prelude, sysroot),
321330
)
322331
.unwrap();
323332
}
@@ -627,11 +636,23 @@ impl FileMeta {
627636
}
628637
}
629638

639+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
640+
enum ForceNoneLangOrigin {
641+
Yes,
642+
No,
643+
}
644+
630645
fn parse_crate(
631646
crate_str: String,
632647
current_source_root_kind: SourceRootKind,
633648
explicit_non_workspace_member: bool,
634649
) -> (String, CrateOrigin, Option<String>) {
650+
let (crate_str, force_non_lang_origin) = if let Some(s) = crate_str.strip_prefix("r#") {
651+
(s.to_owned(), ForceNoneLangOrigin::Yes)
652+
} else {
653+
(crate_str, ForceNoneLangOrigin::No)
654+
};
655+
635656
// syntax:
636657
// "my_awesome_crate"
637658
// "[email protected],http://example.com"
@@ -646,16 +667,25 @@ fn parse_crate(
646667
let non_workspace_member = explicit_non_workspace_member
647668
|| matches!(current_source_root_kind, SourceRootKind::Library);
648669

649-
let origin = match LangCrateOrigin::from(&*name) {
650-
LangCrateOrigin::Other => {
651-
let name = Symbol::intern(&name);
652-
if non_workspace_member {
653-
CrateOrigin::Library { repo, name }
654-
} else {
655-
CrateOrigin::Local { repo, name: Some(name) }
670+
let origin = if force_non_lang_origin == ForceNoneLangOrigin::Yes {
671+
let name = Symbol::intern(&name);
672+
if non_workspace_member {
673+
CrateOrigin::Library { repo, name }
674+
} else {
675+
CrateOrigin::Local { repo, name: Some(name) }
676+
}
677+
} else {
678+
match LangCrateOrigin::from(&*name) {
679+
LangCrateOrigin::Other => {
680+
let name = Symbol::intern(&name);
681+
if non_workspace_member {
682+
CrateOrigin::Library { repo, name }
683+
} else {
684+
CrateOrigin::Local { repo, name: Some(name) }
685+
}
656686
}
687+
origin => CrateOrigin::Lang(origin),
657688
}
658-
origin => CrateOrigin::Lang(origin),
659689
};
660690

661691
(name, origin, version)

0 commit comments

Comments
 (0)