Skip to content

Commit 0063e89

Browse files
committed
Auto merge of #14038 - Veykril:no-sysroot-hard-err, r=Veykril
Don't fail workspace loading if sysroot can't be found
2 parents 2935a89 + b2598f4 commit 0063e89

File tree

4 files changed

+121
-79
lines changed

4 files changed

+121
-79
lines changed

crates/project-model/src/sysroot.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ impl Sysroot {
7070
pub fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
7171
self.crates.iter().map(|(id, _data)| id)
7272
}
73+
74+
pub fn is_empty(&self) -> bool {
75+
self.crates.is_empty()
76+
}
7377
}
7478

7579
impl Sysroot {
@@ -79,8 +83,7 @@ impl Sysroot {
7983
let sysroot_dir = discover_sysroot_dir(dir, extra_env)?;
8084
let sysroot_src_dir =
8185
discover_sysroot_src_dir_or_add_component(&sysroot_dir, dir, extra_env)?;
82-
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
83-
Ok(res)
86+
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
8487
}
8588

8689
pub fn discover_rustc(
@@ -97,11 +100,10 @@ impl Sysroot {
97100
let sysroot_src_dir = discover_sysroot_src_dir(&sysroot_dir).ok_or_else(|| {
98101
format_err!("can't load standard library from sysroot {}", sysroot_dir.display())
99102
})?;
100-
let res = Sysroot::load(sysroot_dir, sysroot_src_dir)?;
101-
Ok(res)
103+
Ok(Sysroot::load(sysroot_dir, sysroot_src_dir))
102104
}
103105

104-
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Result<Sysroot> {
106+
pub fn load(sysroot_dir: AbsPathBuf, sysroot_src_dir: AbsPathBuf) -> Sysroot {
105107
let mut sysroot =
106108
Sysroot { root: sysroot_dir, src_root: sysroot_src_dir, crates: Arena::default() };
107109

@@ -152,14 +154,14 @@ impl Sysroot {
152154
} else {
153155
""
154156
};
155-
anyhow::bail!(
157+
tracing::error!(
156158
"could not find libcore in sysroot path `{}`{}",
157159
sysroot.src_root.as_path().display(),
158160
var_note,
159161
);
160162
}
161163

162-
Ok(sysroot)
164+
sysroot
163165
}
164166

165167
fn by_name(&self, name: &str) -> Option<SysrootCrate> {

crates/project-model/src/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ fn get_fake_sysroot() -> Sysroot {
8181
// fake sysroot, so we give them both the same path:
8282
let sysroot_dir = AbsPathBuf::assert(sysroot_path);
8383
let sysroot_src_dir = sysroot_dir.clone();
84-
Sysroot::load(sysroot_dir, sysroot_src_dir).unwrap()
84+
Sysroot::load(sysroot_dir, sysroot_src_dir)
8585
}
8686

8787
fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {

crates/project-model/src/workspace.rs

+106-43
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ pub struct PackageRoot {
6363
pub exclude: Vec<AbsPathBuf>,
6464
}
6565

66-
#[derive(Clone, Eq, PartialEq)]
66+
#[derive(Clone)]
6767
pub enum ProjectWorkspace {
6868
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
6969
Cargo {
@@ -83,7 +83,6 @@ pub enum ProjectWorkspace {
8383
},
8484
/// Project workspace was manually specified using a `rust-project.json` file.
8585
Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
86-
8786
// FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
8887
// That's not the end user experience we should strive for.
8988
// 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 {
163162
project_json,
164163
config.target.as_deref(),
165164
&config.extra_env,
166-
)?
165+
)
167166
}
168167
ProjectManifest::CargoToml(cargo_toml) => {
169168
let cargo_version = utf8_stdout({
@@ -193,20 +192,27 @@ impl ProjectWorkspace {
193192

194193
let sysroot = match &config.sysroot {
195194
Some(RustcSource::Path(path)) => {
196-
Some(Sysroot::with_sysroot_dir(path.clone()).with_context(|| {
197-
format!("Failed to find sysroot at {}.", path.display())
198-
})?)
195+
match Sysroot::with_sysroot_dir(path.clone()) {
196+
Ok(it) => Some(it),
197+
Err(e) => {
198+
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
199+
None
200+
}
201+
}
202+
}
203+
Some(RustcSource::Discover) => {
204+
match Sysroot::discover(cargo_toml.parent(), &config.extra_env) {
205+
Ok(it) => Some(it),
206+
Err(e) => {
207+
tracing::error!(
208+
%e,
209+
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
210+
cargo_toml.display()
211+
);
212+
None
213+
}
214+
}
199215
}
200-
Some(RustcSource::Discover) => Some(
201-
Sysroot::discover(cargo_toml.parent(), &config.extra_env).with_context(
202-
|| {
203-
format!(
204-
"Failed to find sysroot for Cargo.toml file {}. Is rust-src installed?",
205-
cargo_toml.display()
206-
)
207-
},
208-
)?,
209-
),
210216
None => None,
211217
};
212218
if let Some(sysroot) = &sysroot {
@@ -225,18 +231,22 @@ impl ProjectWorkspace {
225231
}
226232

227233
let rustc = match rustc_dir {
228-
Some(rustc_dir) => Some({
229-
let meta = CargoWorkspace::fetch_metadata(
230-
&rustc_dir,
231-
cargo_toml.parent(),
232-
config,
233-
progress,
234-
)
235-
.with_context(|| {
236-
"Failed to read Cargo metadata for Rust sources".to_string()
237-
})?;
238-
CargoWorkspace::new(meta)
239-
}),
234+
Some(rustc_dir) => match CargoWorkspace::fetch_metadata(
235+
&rustc_dir,
236+
cargo_toml.parent(),
237+
config,
238+
progress,
239+
) {
240+
Ok(meta) => Some(CargoWorkspace::new(meta)),
241+
Err(e) => {
242+
tracing::error!(
243+
%e,
244+
"Failed to read Cargo metadata from rustc source at {}",
245+
rustc_dir.display()
246+
);
247+
None
248+
}
249+
},
240250
None => None,
241251
};
242252

@@ -272,23 +282,22 @@ impl ProjectWorkspace {
272282
project_json: ProjectJson,
273283
target: Option<&str>,
274284
extra_env: &FxHashMap<String, String>,
275-
) -> Result<ProjectWorkspace> {
285+
) -> ProjectWorkspace {
276286
let sysroot = match (project_json.sysroot.clone(), project_json.sysroot_src.clone()) {
277-
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)?),
287+
(Some(sysroot), Some(sysroot_src)) => Some(Sysroot::load(sysroot, sysroot_src)),
278288
(Some(sysroot), None) => {
279289
// assume sysroot is structured like rustup's and guess `sysroot_src`
280290
let sysroot_src =
281291
sysroot.join("lib").join("rustlib").join("src").join("rust").join("library");
282-
283-
Some(Sysroot::load(sysroot, sysroot_src)?)
292+
Some(Sysroot::load(sysroot, sysroot_src))
284293
}
285294
(None, Some(sysroot_src)) => {
286295
// assume sysroot is structured like rustup's and guess `sysroot`
287296
let mut sysroot = sysroot_src.clone();
288297
for _ in 0..5 {
289298
sysroot.pop();
290299
}
291-
Some(Sysroot::load(sysroot, sysroot_src)?)
300+
Some(Sysroot::load(sysroot, sysroot_src))
292301
}
293302
(None, None) => None,
294303
};
@@ -297,26 +306,37 @@ impl ProjectWorkspace {
297306
}
298307

299308
let rustc_cfg = rustc_cfg::get(None, target, extra_env);
300-
Ok(ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg })
309+
ProjectWorkspace::Json { project: project_json, sysroot, rustc_cfg }
301310
}
302311

303312
pub fn load_detached_files(
304313
detached_files: Vec<AbsPathBuf>,
305314
config: &CargoConfig,
306315
) -> Result<ProjectWorkspace> {
307316
let sysroot = match &config.sysroot {
308-
Some(RustcSource::Path(path)) => Some(
309-
Sysroot::with_sysroot_dir(path.clone())
310-
.with_context(|| format!("Failed to find sysroot at {}.", path.display()))?,
311-
),
317+
Some(RustcSource::Path(path)) => match Sysroot::with_sysroot_dir(path.clone()) {
318+
Ok(it) => Some(it),
319+
Err(e) => {
320+
tracing::error!(%e, "Failed to find sysroot at {}.", path.display());
321+
None
322+
}
323+
},
312324
Some(RustcSource::Discover) => {
313325
let dir = &detached_files
314326
.first()
315327
.and_then(|it| it.parent())
316328
.ok_or_else(|| format_err!("No detached files to load"))?;
317-
Some(Sysroot::discover(dir, &config.extra_env).with_context(|| {
318-
format!("Failed to find sysroot in {}. Is rust-src installed?", dir.display())
319-
})?)
329+
match Sysroot::discover(dir, &config.extra_env) {
330+
Ok(it) => Some(it),
331+
Err(e) => {
332+
tracing::error!(
333+
%e,
334+
"Failed to find sysroot for {}. Is rust-src installed?",
335+
dir.display()
336+
);
337+
None
338+
}
339+
}
320340
}
321341
None => None,
322342
};
@@ -541,7 +561,7 @@ impl ProjectWorkspace {
541561
load_proc_macro,
542562
load,
543563
project,
544-
sysroot,
564+
sysroot.as_ref(),
545565
extra_env,
546566
Err("rust-project.json projects have no target layout set".into()),
547567
),
@@ -585,14 +605,57 @@ impl ProjectWorkspace {
585605
}
586606
crate_graph
587607
}
608+
609+
pub fn eq_ignore_build_data(&self, other: &Self) -> bool {
610+
match (self, other) {
611+
(
612+
Self::Cargo {
613+
cargo,
614+
sysroot,
615+
rustc,
616+
rustc_cfg,
617+
cfg_overrides,
618+
toolchain,
619+
build_scripts: _,
620+
target_layout: _,
621+
},
622+
Self::Cargo {
623+
cargo: o_cargo,
624+
sysroot: o_sysroot,
625+
rustc: o_rustc,
626+
rustc_cfg: o_rustc_cfg,
627+
cfg_overrides: o_cfg_overrides,
628+
toolchain: o_toolchain,
629+
build_scripts: _,
630+
target_layout: _,
631+
},
632+
) => {
633+
cargo == o_cargo
634+
&& rustc == o_rustc
635+
&& rustc_cfg == o_rustc_cfg
636+
&& cfg_overrides == o_cfg_overrides
637+
&& toolchain == o_toolchain
638+
&& sysroot == o_sysroot
639+
}
640+
(
641+
Self::Json { project, sysroot, rustc_cfg },
642+
Self::Json { project: o_project, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
643+
) => project == o_project && rustc_cfg == o_rustc_cfg && sysroot == o_sysroot,
644+
(
645+
Self::DetachedFiles { files, sysroot, rustc_cfg },
646+
Self::DetachedFiles { files: o_files, sysroot: o_sysroot, rustc_cfg: o_rustc_cfg },
647+
) => files == o_files && sysroot == o_sysroot && rustc_cfg == o_rustc_cfg,
648+
_ => false,
649+
}
650+
}
588651
}
589652

590653
fn project_json_to_crate_graph(
591654
rustc_cfg: Vec<CfgFlag>,
592655
load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
593656
load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
594657
project: &ProjectJson,
595-
sysroot: &Option<Sysroot>,
658+
sysroot: Option<&Sysroot>,
596659
extra_env: &FxHashMap<String, String>,
597660
target_layout: TargetLayoutLoadResult,
598661
) -> CrateGraph {

crates/rust-analyzer/src/reload.rs

+5-28
Original file line numberDiff line numberDiff line change
@@ -148,11 +148,11 @@ impl GlobalState {
148148
)
149149
}
150150
LinkedProject::InlineJsonProject(it) => {
151-
project_model::ProjectWorkspace::load_inline(
151+
Ok(project_model::ProjectWorkspace::load_inline(
152152
it.clone(),
153153
cargo_config.target.as_deref(),
154154
&cargo_config.extra_env,
155-
)
155+
))
156156
}
157157
})
158158
.collect::<Vec<_>>();
@@ -212,35 +212,11 @@ impl GlobalState {
212212
let workspaces =
213213
workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>();
214214

215-
fn eq_ignore_build_data<'a>(
216-
left: &'a ProjectWorkspace,
217-
right: &'a ProjectWorkspace,
218-
) -> bool {
219-
let key = |p: &'a ProjectWorkspace| match p {
220-
ProjectWorkspace::Cargo {
221-
cargo,
222-
sysroot,
223-
rustc,
224-
rustc_cfg,
225-
cfg_overrides,
226-
227-
build_scripts: _,
228-
toolchain: _,
229-
target_layout: _,
230-
} => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
231-
_ => None,
232-
};
233-
match (key(left), key(right)) {
234-
(Some(lk), Some(rk)) => lk == rk,
235-
_ => left == right,
236-
}
237-
}
238-
239215
let same_workspaces = workspaces.len() == self.workspaces.len()
240216
&& workspaces
241217
.iter()
242218
.zip(self.workspaces.iter())
243-
.all(|(l, r)| eq_ignore_build_data(l, r));
219+
.all(|(l, r)| l.eq_ignore_build_data(r));
244220

245221
if same_workspaces {
246222
let (workspaces, build_scripts) = self.fetch_build_data_queue.last_op_result();
@@ -270,7 +246,8 @@ impl GlobalState {
270246

271247
// Here, we completely changed the workspace (Cargo.toml edit), so
272248
// we don't care about build-script results, they are stale.
273-
self.workspaces = Arc::new(workspaces)
249+
// FIXME: can we abort the build scripts here?
250+
self.workspaces = Arc::new(workspaces);
274251
}
275252

276253
if let FilesWatcher::Client = self.config.files().watcher {

0 commit comments

Comments
 (0)