Unnamed repository; edit this file 'description' to name the repository.
Auto merge of #14038 - Veykril:no-sysroot-hard-err, r=Veykril
Don't fail workspace loading if sysroot can't be found
bors 2023-01-27
parent 2935a89 · parent b2598f4 · commit 0063e89
-rw-r--r--crates/project-model/src/sysroot.rs16
-rw-r--r--crates/project-model/src/tests.rs2
-rw-r--r--crates/project-model/src/workspace.rs149
-rw-r--r--crates/rust-analyzer/src/reload.rs33
4 files changed, 121 insertions, 79 deletions
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 046786580e..e1dde12bad 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -70,6 +70,10 @@ impl Sysroot {
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
self.crates.iter().map(|(id, _data)| id)
}
+
+ pub fn is_empty(&self) -> bool {
+ self.crates.is_empty()
+ }
}
impl Sysroot {
@@ -79,8 +83,7 @@ impl Sysroot {
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
let sysroot_src_dir =
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
- let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
- Ok(res)
+ Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
}
pub fn discover_rustc(
@@ -97,11 +100,10 @@ impl Sysroot {
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
})?;
- let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
- Ok(res)
+ Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
}
- pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
+ 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() };
@@ -152,14 +154,14 @@ impl Sysroot {
} else {
""
};
- anyhow::bail!(
+ tracing::error!(
"could not find libcore in sysroot path `{}`{}",
sysroot.src_root.as_path().display(),
var_note,
);
}
- Ok(sysroot)
+ sysroot
}
fn by_name(&self, name: &str) -> Option<SysrootCrate> {
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index 19ee685691..505b660f34 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -81,7 +81,7 @@ fn get_fake_sysroot() -> Sysroot {
// fake sysroot, so we give them both the same path:
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
let sysroot_src_dir = sysroot_dir.clone();
- Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap()
+ Sysroot::load(sysroot_dir, sysroot_src_dir)
}
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 755bf95199..d784d3d0e9 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -63,7 +63,7 @@ pub struct PackageRoot {
pub exclude: Vec<AbsPathBuf>,
}
-#[derive(Clone, Eq, PartialEq)]
+#[derive(Clone)]
pub enum ProjectWorkspace {
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
Cargo {
@@ -83,7 +83,6 @@ pub enum ProjectWorkspace {
},
/// Project workspace was manually specified using a `rust-project.json` file.
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
-
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
// That's not the end user experience we should strive for.
// Ideally, you should be able to just open a random detached file in existing cargo projects, and get the basic features working.
@@ -163,7 +162,7 @@ impl ProjectWorkspace {
project_json,
config.target.as_deref(),
&config.extra_env,
- )?
+ )
}
ProjectManifest::CargoToml(cargo_toml) => {
let cargo_version = utf8_stdout({
@@ -193,20 +192,27 @@ impl ProjectWorkspace {
let sysroot = match &config.sysroot {
Some(RustcSource::Path(path)) => {
- Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
- format!("Failed to find sysroot at {}.", path.display())
- })?)
+ match Sysroot::with_sysroot_dir(path.clone()) {
+ Ok(it) => Some(it),
+ Err(e) => {
+ tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
+ None
+ }
+ }
+ }
+ Some(RustcSource::Discover) => {
+ match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
+ Ok(it) => Some(it),
+ Err(e) => {
+ tracing::error!(
+ %e,
+ "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
+ cargo_toml.display()
+ );
+ None
+ }
+ }
}
- Some(RustcSource::Discover) => Some(
- Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
- || {
- format!(
- "Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
- cargo_toml.display()
- )
- },
- )?,
- ),
None => None,
};
if let Some(sysroot) = &sysroot {
@@ -225,18 +231,22 @@ impl ProjectWorkspace {
}
let rustc = match rustc_dir {
- Some(rustc_dir) => Some({
- let meta = CargoWorkspace::fetch_metadata(
- &rustc_dir,
- cargo_toml.parent(),
- config,
- progress,
- )
- .with_context(|| {
- "Failed to read Cargo metadata for Rust sources".to_string()
- })?;
- CargoWorkspace::new(meta)
- }),
+ Some(rustc_dir) => match CargoWorkspace::fetch_metadata(
+ &rustc_dir,
+ cargo_toml.parent(),
+ config,
+ progress,
+ ) {
+ Ok(meta) => Some(CargoWorkspace::new(meta)),
+ Err(e) => {
+ tracing::error!(
+ %e,
+ "Failed to read Cargo metadata from rustc source at {}",
+ rustc_dir.display()
+ );
+ None
+ }
+ },
None => None,
};
@@ -272,15 +282,14 @@ impl ProjectWorkspace {
project_json: ProjectJson,
target: Option<&str>,
extra_env: &FxHashMap<String, String>,
- ) -> Result<ProjectWorkspace> {
+ ) -> ProjectWorkspace {
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
- (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
+ (Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)),
(Some(sysroot), None) => {
// assume sysroot is structured like rustup's and guess `sysroot_src`
let sysroot_src =
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
-
- Some(Sysroot::load(sysroot, sysroot_src)?)
+ Some(Sysroot::load(sysroot, sysroot_src))
}
(None, Some(sysroot_src)) => {
// assume sysroot is structured like rustup's and guess `sysroot`
@@ -288,7 +297,7 @@ impl ProjectWorkspace {
for _ in 0..5 {
sysroot.pop();
}
- Some(Sysroot::load(sysroot, sysroot_src)?)
+ Some(Sysroot::load(sysroot, sysroot_src))
}
(None, None) => None,
};
@@ -297,7 +306,7 @@ impl ProjectWorkspace {
}
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
- Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
+ ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }
}
pub fn load_detached_files(
@@ -305,18 +314,29 @@ impl ProjectWorkspace {
config: &CargoConfig,
) -> Result<ProjectWorkspace> {
let sysroot = match &config.sysroot {
- Some(RustcSource::Path(path)) => Some(
- Sysroot::with_sysroot_dir(path.clone())
- .with_context(|| format!("Failed to find sysroot at {}.", path.display()))?,
- ),
+ Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) {
+ Ok(it) => Some(it),
+ Err(e) => {
+ tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
+ None
+ }
+ },
Some(RustcSource::Discover) => {
let dir = &detached_files
.first()
.and_then(|it| it.parent())
.ok_or_else(|| format_err!("No detached files to load"))?;
- Some(Sysroot::discover(dir, &config.extra_env).with_context(|| {
- format!("Failed to find sysroot in {}. Is rust-src installed?", dir.display())
- })?)
+ match Sysroot::discover(dir, &config.extra_env) {
+ Ok(it) => Some(it),
+ Err(e) => {
+ tracing::error!(
+ %e,
+ "Failed to find sysroot for {}. Is rust-src installed?",
+ dir.display()
+ );
+ None
+ }
+ }
}
None => None,
};
@@ -541,7 +561,7 @@ impl ProjectWorkspace {
load_proc_macro,
load,
project,
- sysroot,
+ sysroot.as_ref(),
extra_env,
Err("rust-project.json projects have no target layout set".into()),
),
@@ -585,6 +605,49 @@ impl ProjectWorkspace {
}
crate_graph
}
+
+ pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
+ match (self, other) {
+ (
+ Self::Cargo {
+ cargo,
+ sysroot,
+ rustc,
+ rustc_cfg,
+ cfg_overrides,
+ toolchain,
+ build_scripts: _,
+ target_layout: _,
+ },
+ Self::Cargo {
+ cargo: o_cargo,
+ sysroot: o_sysroot,
+ rustc: o_rustc,
+ rustc_cfg: o_rustc_cfg,
+ cfg_overrides: o_cfg_overrides,
+ toolchain: o_toolchain,
+ build_scripts: _,
+ target_layout: _,
+ },
+ ) => {
+ cargo == o_cargo
+ && rustc == o_rustc
+ && rustc_cfg == o_rustc_cfg
+ && cfg_overrides == o_cfg_overrides
+ && toolchain == o_toolchain
+ && sysroot == o_sysroot
+ }
+ (
+ Self::Json { project, sysroot, rustc_cfg },
+ Self::Json { project: o_project, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
+ ) => project == o_project && rustc_cfg == o_rustc_cfg && sysroot == o_sysroot,
+ (
+ Self::DetachedFiles { files, sysroot, rustc_cfg },
+ Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
+ ) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg,
+ _ => false,
+ }
+ }
}
fn project_json_to_crate_graph(
@@ -592,7 +655,7 @@ fn project_json_to_crate_graph(
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
project: &ProjectJson,
- sysroot: &Option<Sysroot>,
+ sysroot: Option<&Sysroot>,
extra_env: &FxHashMap<String, String>,
target_layout: TargetLayoutLoadResult,
) -> CrateGraph {
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 3d7342d191..a33b8e14cf 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -148,11 +148,11 @@ impl GlobalState {
)
}
LinkedProject::InlineJsonProject(it) => {
- project_model::ProjectWorkspace::load_inline(
+ Ok(project_model::ProjectWorkspace::load_inline(
it.clone(),
cargo_config.target.as_deref(),
&cargo_config.extra_env,
- )
+ ))
}
})
.collect::<Vec<_>>();
@@ -212,35 +212,11 @@ impl GlobalState {
let workspaces =
workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>();
- fn eq_ignore_build_data<'a>(
- left: &'a ProjectWorkspace,
- right: &'a ProjectWorkspace,
- ) -> bool {
- let key = |p: &'a ProjectWorkspace| match p {
- ProjectWorkspace::Cargo {
- cargo,
- sysroot,
- rustc,
- rustc_cfg,
- cfg_overrides,
-
- build_scripts: _,
- toolchain: _,
- target_layout: _,
- } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
- _ => None,
- };
- match (key(left), key(right)) {
- (Some(lk), Some(rk)) => lk == rk,
- _ => left == right,
- }
- }
-
let same_workspaces = workspaces.len() == self.workspaces.len()
&& workspaces
.iter()
.zip(self.workspaces.iter())
- .all(|(l, r)| eq_ignore_build_data(l, r));
+ .all(|(l, r)| l.eq_ignore_build_data(r));
if same_workspaces {
let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
@@ -270,7 +246,8 @@ impl GlobalState {
// Here, we completely changed the workspace (Cargo.toml edit), so
// we don't care about build-script results, they are stale.
- self.workspaces = Arc::new(workspaces)
+ // FIXME: can we abort the build scripts here?
+ self.workspaces = Arc::new(workspaces);
}
if let FilesWatcher::Client = self.config.files().watcher {