Skip to content

internal: Add RA_UNSTABLE_SYSROOT_HACK #14599

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 47 additions & 7 deletions crates/base-db/src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,24 +386,64 @@ impl CrateGraph {
self.arena.alloc(data)
}

/// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced
/// with the second input.
pub fn remove_and_replace(
&mut self,
id: CrateId,
replace_with: CrateId,
) -> Result<(), CyclicDependenciesError> {
for (x, data) in self.arena.iter() {
if x == id {
continue;
}
for edge in &data.dependencies {
if edge.crate_id == id {
self.check_cycle_after_dependency(edge.crate_id, replace_with)?;
}
}
}
// if everything was ok, start to replace
for (x, data) in self.arena.iter_mut() {
if x == id {
continue;
}
for edge in &mut data.dependencies {
if edge.crate_id == id {
edge.crate_id = replace_with;
}
}
}
Ok(())
}

pub fn add_dep(
&mut self,
from: CrateId,
dep: Dependency,
) -> Result<(), CyclicDependenciesError> {
let _p = profile::span("add_dep");

// Check if adding a dep from `from` to `to` creates a cycle. To figure
// that out, look for a path in the *opposite* direction, from `to` to
// `from`.
if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
self.check_cycle_after_dependency(from, dep.crate_id)?;

self.arena[from].add_dep(dep);
Ok(())
}

/// Check if adding a dep from `from` to `to` creates a cycle. To figure
/// that out, look for a path in the *opposite* direction, from `to` to
/// `from`.
fn check_cycle_after_dependency(
&self,
from: CrateId,
to: CrateId,
) -> Result<(), CyclicDependenciesError> {
if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) {
let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
let err = CyclicDependenciesError { path };
assert!(err.from().0 == from && err.to().0 == dep.crate_id);
assert!(err.from().0 == from && err.to().0 == to);
return Err(err);
}

self.arena[from].add_dep(dep);
Ok(())
}

Expand Down
32 changes: 28 additions & 4 deletions crates/project-model/src/sysroot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,15 @@ use la_arena::{Arena, Idx};
use paths::{AbsPath, AbsPathBuf};
use rustc_hash::FxHashMap;

use crate::{utf8_stdout, ManifestPath};
use crate::{utf8_stdout, CargoConfig, CargoWorkspace, ManifestPath};

#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Sysroot {
root: AbsPathBuf,
src_root: AbsPathBuf,
crates: Arena<SysrootCrateData>,
/// Stores the result of `cargo metadata` of the `RA_UNSTABLE_SYSROOT_HACK` workspace.
pub hack_cargo_workspace: Option<CargoWorkspace>,
}

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

pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
let mut sysroot =
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
pub fn load(sysroot_dir: AbsPathBuf, mut sysroot_src_dir: AbsPathBuf) -> Sysroot {
// FIXME: Remove this `hack_cargo_workspace` field completely once we support sysroot dependencies
let hack_cargo_workspace = if let Ok(path) = std::env::var("RA_UNSTABLE_SYSROOT_HACK") {
let cargo_toml = ManifestPath::try_from(
AbsPathBuf::try_from(&*format!("{path}/Cargo.toml")).unwrap(),
)
.unwrap();
sysroot_src_dir = AbsPathBuf::try_from(&*path).unwrap().join("library");
CargoWorkspace::fetch_metadata(
&cargo_toml,
&AbsPathBuf::try_from("/").unwrap(),
&CargoConfig::default(),
&|_| (),
)
.map(CargoWorkspace::new)
.ok()
} else {
None
};
let mut sysroot = Sysroot {
root: sysroot_dir,
src_root: sysroot_src_dir,
crates: Arena::default(),
hack_cargo_workspace,
};

for path in SYSROOT_CRATES.trim().lines() {
let name = path.split('/').last().unwrap();
Expand Down
126 changes: 99 additions & 27 deletions crates/project-model/src/workspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,6 +622,7 @@ impl ProjectWorkspace {
sysroot.as_ref().ok(),
rustc_cfg.clone(),
cfg_overrides,
None,
build_scripts,
match target_layout.as_ref() {
Ok(it) => Ok(Arc::from(it.as_str())),
Expand Down Expand Up @@ -821,6 +822,8 @@ fn cargo_to_crate_graph(
sysroot: Option<&Sysroot>,
rustc_cfg: Vec<CfgFlag>,
override_cfg: &CfgOverrides,
// Don't compute cfg and use this if present
forced_cfg: Option<CfgOptions>,
build_scripts: &WorkspaceBuildScripts,
target_layout: TargetLayoutLoadResult,
channel: Option<ReleaseChannel>,
Expand Down Expand Up @@ -858,7 +861,7 @@ fn cargo_to_crate_graph(
for pkg in cargo.packages() {
has_private |= cargo[pkg].metadata.rustc_private;

let cfg_options = {
let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
let mut cfg_options = cfg_options.clone();

// Add test cfg for local crates
Expand All @@ -882,7 +885,7 @@ fn cargo_to_crate_graph(
cfg_options.apply_diff(overrides.clone());
};
cfg_options
};
});

let mut lib_tgt = None;
for &tgt in cargo[pkg].targets.iter() {
Expand Down Expand Up @@ -1280,31 +1283,43 @@ fn sysroot_to_crate_graph(
) -> (SysrootPublicDeps, Option<CrateId>) {
let _p = profile::span("sysroot_to_crate_graph");
let mut cfg_options = CfgOptions::default();
cfg_options.extend(rustc_cfg);
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = sysroot
.crates()
.filter_map(|krate| {
let file_id = load(&sysroot[krate].root)?;

let env = Env::default();
let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
let crate_id = crate_graph.add_crate_root(
file_id,
Edition::CURRENT,
Some(display_name),
None,
cfg_options.clone(),
None,
env,
false,
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
target_layout.clone(),
channel,
);
Some((krate, crate_id))
})
.collect();

cfg_options.extend(rustc_cfg.clone());
let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = match &sysroot.hack_cargo_workspace {
Some(cargo) => handle_hack_cargo_workspace(
load,
cargo,
rustc_cfg,
cfg_options,
target_layout,
channel,
crate_graph,
sysroot,
),
None => sysroot
.crates()
.filter_map(|krate| {
let file_id = load(&sysroot[krate].root)?;

let env = Env::default();
let display_name =
CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
let crate_id = crate_graph.add_crate_root(
file_id,
Edition::CURRENT,
Some(display_name),
None,
cfg_options.clone(),
None,
env,
false,
CrateOrigin::Lang(LangCrateOrigin::from(&*sysroot[krate].name)),
target_layout.clone(),
channel,
);
Some((krate, crate_id))
})
.collect(),
};
for from in sysroot.crates() {
for &to in sysroot[from].deps.iter() {
let name = CrateName::new(&sysroot[to].name).unwrap();
Expand All @@ -1325,6 +1340,63 @@ fn sysroot_to_crate_graph(
(public_deps, libproc_macro)
}

fn handle_hack_cargo_workspace(
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
cargo: &CargoWorkspace,
rustc_cfg: Vec<CfgFlag>,
cfg_options: CfgOptions,
target_layout: Result<Arc<str>, Arc<str>>,
channel: Option<ReleaseChannel>,
crate_graph: &mut CrateGraph,
sysroot: &Sysroot,
) -> FxHashMap<SysrootCrate, CrateId> {
let (cg, mut pm) = cargo_to_crate_graph(
load,
None,
cargo,
None,
rustc_cfg,
&CfgOverrides::default(),
Some(cfg_options),
&WorkspaceBuildScripts::default(),
target_layout,
channel,
);
crate_graph.extend(cg, &mut pm);
for crate_name in ["std", "alloc", "core"] {
let original = crate_graph
.iter()
.find(|x| {
crate_graph[*x]
.display_name
.as_ref()
.map(|x| x.canonical_name() == crate_name)
.unwrap_or(false)
})
.unwrap();
let fake_crate_name = format!("rustc-std-workspace-{}", crate_name);
let fake = crate_graph
.iter()
.find(|x| {
crate_graph[*x]
.display_name
.as_ref()
.map(|x| x.canonical_name() == fake_crate_name)
.unwrap_or(false)
})
.unwrap();
crate_graph.remove_and_replace(fake, original).unwrap();
}
sysroot
.crates()
.filter_map(|krate| {
let file_id = load(&sysroot[krate].root)?;
let crate_id = crate_graph.crate_id_for_crate_root(file_id)?;
Some((krate, crate_id))
})
.collect()
}

fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
add_dep_inner(graph, from, Dependency::new(name, to))
}
Expand Down