Skip to content

Commit 39715ce

Browse files
committed
Add RA_UNSTABLE_SYSROOT_HACK
1 parent 9b54e39 commit 39715ce

File tree

3 files changed

+174
-38
lines changed

3 files changed

+174
-38
lines changed

crates/base-db/src/input.rs

+47-7
Original file line numberDiff line numberDiff line change
@@ -386,24 +386,64 @@ impl CrateGraph {
386386
self.arena.alloc(data)
387387
}
388388

389+
/// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced
390+
/// with the second input.
391+
pub fn remove_and_replace(
392+
&mut self,
393+
id: CrateId,
394+
replace_with: CrateId,
395+
) -> Result<(), CyclicDependenciesError> {
396+
for (x, data) in self.arena.iter() {
397+
if x == id {
398+
continue;
399+
}
400+
for edge in &data.dependencies {
401+
if edge.crate_id == id {
402+
self.check_cycle_after_dependency(edge.crate_id, replace_with)?;
403+
}
404+
}
405+
}
406+
// if everything was ok, start to replace
407+
for (x, data) in self.arena.iter_mut() {
408+
if x == id {
409+
continue;
410+
}
411+
for edge in &mut data.dependencies {
412+
if edge.crate_id == id {
413+
edge.crate_id = replace_with;
414+
}
415+
}
416+
}
417+
Ok(())
418+
}
419+
389420
pub fn add_dep(
390421
&mut self,
391422
from: CrateId,
392423
dep: Dependency,
393424
) -> Result<(), CyclicDependenciesError> {
394425
let _p = profile::span("add_dep");
395426

396-
// Check if adding a dep from `from` to `to` creates a cycle. To figure
397-
// that out, look for a path in the *opposite* direction, from `to` to
398-
// `from`.
399-
if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
427+
self.check_cycle_after_dependency(from, dep.crate_id)?;
428+
429+
self.arena[from].add_dep(dep);
430+
Ok(())
431+
}
432+
433+
/// Check if adding a dep from `from` to `to` creates a cycle. To figure
434+
/// that out, look for a path in the *opposite* direction, from `to` to
435+
/// `from`.
436+
fn check_cycle_after_dependency(
437+
&self,
438+
from: CrateId,
439+
to: CrateId,
440+
) -> Result<(), CyclicDependenciesError> {
441+
if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) {
400442
let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
401443
let err = CyclicDependenciesError { path };
402-
assert!(err.from().0 == from && err.to().0 == dep.crate_id);
444+
assert!(err.from().0 == from && err.to().0 == to);
403445
return Err(err);
404446
}
405-
406-
self.arena[from].add_dep(dep);
407447
Ok(())
408448
}
409449

crates/project-model/src/sysroot.rs

+28-4
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ use la_arena::{Arena, Idx};
1212
use paths::{AbsPath, AbsPathBuf};
1313
use rustc_hash::FxHashMap;
1414

15-
use crate::{utf8_stdout, ManifestPath};
15+
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};
1616

1717
#[derive(Debug, Clone, Eq, PartialEq)]
1818
pub struct Sysroot {
1919
root: AbsPathBuf,
2020
src_root: AbsPathBuf,
2121
crates: Arena<SysrootCrateData>,
22+
/// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace.
23+
pub hack_cargo_workspace: Option<CargoWorkspace>,
2224
}
2325

2426
pub(crate) type SysrootCrate = Idx<SysrootCrateData>;
@@ -125,9 +127,31 @@ impl Sysroot {
125127
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
126128
}
127129

128-
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
129-
let mut sysroot =
130-
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
130+
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
131+
// FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
132+
let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") {
133+
let cargo_toml = ManifestPath::try_from(
134+
AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(),
135+
)
136+
.unwrap();
137+
sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library");
138+
CargoWorkspace::fetch_metadata(
139+
&cargo_toml,
140+
&AbsPathBuf::try_from("/").unwrap(),
141+
&CargoConfig::default(),
142+
&|_| (),
143+
)
144+
.map(CargoWorkspace::new)
145+
.ok()
146+
} else {
147+
None
148+
};
149+
let mut sysroot = Sysroot {
150+
root: sysroot_dir,
151+
src_root: sysroot_src_dir,
152+
crates: Arena::default(),
153+
hack_cargo_workspace,
154+
};
131155

132156
for path in SYSROOT_CRATES.trim().lines() {
133157
let name = path.split('/').last().unwrap();

crates/project-model/src/workspace.rs

+99-27
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ impl ProjectWorkspace {
622622
sysroot.as_ref().ok(),
623623
rustc_cfg.clone(),
624624
cfg_overrides,
625+
None,
625626
build_scripts,
626627
match target_layout.as_ref() {
627628
Ok(it) => Ok(Arc::from(it.as_str())),
@@ -821,6 +822,8 @@ fn cargo_to_crate_graph(
821822
sysroot: Option<&Sysroot>,
822823
rustc_cfg: Vec<CfgFlag>,
823824
override_cfg: &CfgOverrides,
825+
// Don't compute cfg and use this if present
826+
forced_cfg: Option<CfgOptions>,
824827
build_scripts: &WorkspaceBuildScripts,
825828
target_layout: TargetLayoutLoadResult,
826829
channel: Option<ReleaseChannel>,
@@ -858,7 +861,7 @@ fn cargo_to_crate_graph(
858861
for pkg in cargo.packages() {
859862
has_private |= cargo[pkg].metadata.rustc_private;
860863

861-
let cfg_options = {
864+
let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
862865
let mut cfg_options = cfg_options.clone();
863866

864867
// Add test cfg for local crates
@@ -882,7 +885,7 @@ fn cargo_to_crate_graph(
882885
cfg_options.apply_diff(overrides.clone());
883886
};
884887
cfg_options
885-
};
888+
});
886889

887890
let mut lib_tgt = None;
888891
for &tgt in cargo[pkg].targets.iter() {
@@ -1280,31 +1283,43 @@ fn sysroot_to_crate_graph(
12801283
) -> (SysrootPublicDeps, Option<CrateId>) {
12811284
let _p = profile::span("sysroot_to_crate_graph");
12821285
let mut cfg_options = CfgOptions::default();
1283-
cfg_options.extend(rustc_cfg);
1284-
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
1285-
.crates()
1286-
.filter_map(|krate| {
1287-
let file_id = load(&sysroot[krate].root)?;
1288-
1289-
let env = Env::default();
1290-
let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
1291-
let crate_id = crate_graph.add_crate_root(
1292-
file_id,
1293-
Edition::CURRENT,
1294-
Some(display_name),
1295-
None,
1296-
cfg_options.clone(),
1297-
None,
1298-
env,
1299-
false,
1300-
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
1301-
target_layout.clone(),
1302-
channel,
1303-
);
1304-
Some((krate, crate_id))
1305-
})
1306-
.collect();
1307-
1286+
cfg_options.extend(rustc_cfg.clone());
1287+
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
1288+
Some(cargo) => handle_hack_cargo_workspace(
1289+
load,
1290+
cargo,
1291+
rustc_cfg,
1292+
cfg_options,
1293+
target_layout,
1294+
channel,
1295+
crate_graph,
1296+
sysroot,
1297+
),
1298+
None => sysroot
1299+
.crates()
1300+
.filter_map(|krate| {
1301+
let file_id = load(&sysroot[krate].root)?;
1302+
1303+
let env = Env::default();
1304+
let display_name =
1305+
CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
1306+
let crate_id = crate_graph.add_crate_root(
1307+
file_id,
1308+
Edition::CURRENT,
1309+
Some(display_name),
1310+
None,
1311+
cfg_options.clone(),
1312+
None,
1313+
env,
1314+
false,
1315+
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
1316+
target_layout.clone(),
1317+
channel,
1318+
);
1319+
Some((krate, crate_id))
1320+
})
1321+
.collect(),
1322+
};
13081323
for from in sysroot.crates() {
13091324
for &to in sysroot[from].deps.iter() {
13101325
let name = CrateName::new(&sysroot[to].name).unwrap();
@@ -1325,6 +1340,63 @@ fn sysroot_to_crate_graph(
13251340
(public_deps, libproc_macro)
13261341
}
13271342

1343+
fn handle_hack_cargo_workspace(
1344+
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
1345+
cargo: &CargoWorkspace,
1346+
rustc_cfg: Vec<CfgFlag>,
1347+
cfg_options: CfgOptions,
1348+
target_layout: Result<Arc<str>, Arc<str>>,
1349+
channel: Option<ReleaseChannel>,
1350+
crate_graph: &mut CrateGraph,
1351+
sysroot: &Sysroot,
1352+
) -> FxHashMap<SysrootCrate, CrateId> {
1353+
let (cg, mut pm) = cargo_to_crate_graph(
1354+
load,
1355+
None,
1356+
cargo,
1357+
None,
1358+
rustc_cfg,
1359+
&CfgOverrides::default(),
1360+
Some(cfg_options),
1361+
&WorkspaceBuildScripts::default(),
1362+
target_layout,
1363+
channel,
1364+
);
1365+
crate_graph.extend(cg, &mut pm);
1366+
for crate_name in ["std", "alloc", "core"] {
1367+
let original = crate_graph
1368+
.iter()
1369+
.find(|x| {
1370+
crate_graph[*x]
1371+
.display_name
1372+
.as_ref()
1373+
.map(|x| x.canonical_name() == crate_name)
1374+
.unwrap_or(false)
1375+
})
1376+
.unwrap();
1377+
let fake_crate_name = format!("rustc-std-workspace-{}", crate_name);
1378+
let fake = crate_graph
1379+
.iter()
1380+
.find(|x| {
1381+
crate_graph[*x]
1382+
.display_name
1383+
.as_ref()
1384+
.map(|x| x.canonical_name() == fake_crate_name)
1385+
.unwrap_or(false)
1386+
})
1387+
.unwrap();
1388+
crate_graph.remove_and_replace(fake, original).unwrap();
1389+
}
1390+
sysroot
1391+
.crates()
1392+
.filter_map(|krate| {
1393+
let file_id = load(&sysroot[krate].root)?;
1394+
let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
1395+
Some((krate, crate_id))
1396+
})
1397+
.collect()
1398+
}
1399+
13281400
fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
13291401
add_dep_inner(graph, from, Dependency::new(name, to))
13301402
}

0 commit comments

Comments
 (0)