Repository: rust-lang/rust-analyzer
Pull request #12984 (2022-08-09 12:32:02)

Use `--keep-going` cargo flag when building build scripts
See https://github.com/rust-lang/rust-analyzer/issues/12973#issuecomment-1209159426


Patch:
diff --git a/crates/project-model/src/build_scripts.rs b/crates/project-model/src/build_scripts.rs
index ee7f8339a7..84e772d168 100644
--- a/crates/project-model/src/build_scripts.rs
+++ b/crates/project-model/src/build_scripts.rs
@@ -12,6 +12,7 @@ use cargo_metadata::{camino::Utf8Path, Message};
 use la_arena::ArenaMap;
 use paths::AbsPathBuf;
 use rustc_hash::FxHashMap;
+use semver::Version;
 use serde::Deserialize;
 
 use crate::{cfg_flag::CfgFlag, CargoConfig, CargoWorkspace, Package};
@@ -77,9 +78,32 @@ impl WorkspaceBuildScripts {
         config: &CargoConfig,
         workspace: &CargoWorkspace,
         progress: &dyn Fn(String),
+        toolchain: &Option<Version>,
     ) -> io::Result<WorkspaceBuildScripts> {
-        let mut cmd = Self::build_command(config);
+        const RUST_1_62: Version = Version::new(1, 62, 0);
 
+        match Self::run_(Self::build_command(config), config, workspace, progress) {
+            Ok(WorkspaceBuildScripts { error: Some(error), .. })
+                if toolchain.as_ref().map_or(false, |it| *it >= RUST_1_62) =>
+            {
+                // building build scripts failed, attempt to build with --keep-going so
+                // that we potentially get more build data
+                let mut cmd = Self::build_command(config);
+                cmd.args(&["-Z", "unstable-options", "--keep-going"]).env("RUSTC_BOOTSTRAP", "1");
+                let mut res = Self::run_(cmd, config, workspace, progress)?;
+                res.error = Some(error);
+                Ok(res)
+            }
+            res => res,
+        }
+    }
+
+    fn run_(
+        mut cmd: Command,
+        config: &CargoConfig,
+        workspace: &CargoWorkspace,
+        progress: &dyn Fn(String),
+    ) -> io::Result<WorkspaceBuildScripts> {
         if config.wrap_rustc_in_build_scripts {
             // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
             // that to compile only proc macros and build scripts during the initial
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index b144006b44..daabb299f7 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -12,6 +12,7 @@ use base_db::{
 use cfg::{CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::{FxHashMap, FxHashSet};
+use semver::Version;
 use stdx::always;
 
 use crate::{
@@ -77,6 +78,7 @@ pub enum ProjectWorkspace {
         /// different target.
         rustc_cfg: Vec<CfgFlag>,
         cfg_overrides: CfgOverrides,
+        toolchain: Option<Version>,
     },
     /// Project workspace was manually specified using a `rust-project.json` file.
     Json { project: ProjectJson, sysroot: Option<Sysroot>, rustc_cfg: Vec<CfgFlag> },
@@ -105,6 +107,7 @@ impl fmt::Debug for ProjectWorkspace {
                 rustc,
                 rustc_cfg,
                 cfg_overrides,
+                toolchain,
             } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
@@ -116,6 +119,7 @@ impl fmt::Debug for ProjectWorkspace {
                 )
                 .field("n_rustc_cfg", &rustc_cfg.len())
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("toolchain", &toolchain)
                 .finish(),
             ProjectWorkspace::Json { project, sysroot, rustc_cfg } => {
                 let mut debug_struct = f.debug_struct("Json");
@@ -160,6 +164,9 @@ impl ProjectWorkspace {
                     cmd.arg("--version");
                     cmd
                 })?;
+                let toolchain = cargo_version
+                    .get("cargo ".len()..)
+                    .and_then(|it| Version::parse(it.split_whitespace().next()?).ok());
 
                 let meta = CargoWorkspace::fetch_metadata(
                     &cargo_toml,
@@ -169,9 +176,9 @@ impl ProjectWorkspace {
                 )
                 .with_context(|| {
                     format!(
-                        "Failed to read Cargo metadata from Cargo.toml file {}, {}",
+                        "Failed to read Cargo metadata from Cargo.toml file {}, {:?}",
                         cargo_toml.display(),
-                        cargo_version
+                        toolchain
                     )
                 })?;
                 let cargo = CargoWorkspace::new(meta);
@@ -219,6 +226,7 @@ impl ProjectWorkspace {
                     rustc,
                     rustc_cfg,
                     cfg_overrides,
+                    toolchain,
                 }
             }
         };
@@ -271,8 +279,8 @@ impl ProjectWorkspace {
         progress: &dyn Fn(String),
     ) -> Result<WorkspaceBuildScripts> {
         match self {
-            ProjectWorkspace::Cargo { cargo, .. } => {
-                WorkspaceBuildScripts::run(config, cargo, progress).with_context(|| {
+            ProjectWorkspace::Cargo { cargo, toolchain, .. } => {
+                WorkspaceBuildScripts::run(config, cargo, progress, toolchain).with_context(|| {
                     format!("Failed to run build scripts for {}", &cargo.workspace_root().display())
                 })
             }
@@ -320,6 +328,7 @@ impl ProjectWorkspace {
                 rustc_cfg: _,
                 cfg_overrides: _,
                 build_scripts,
+                toolchain: _,
             } => {
                 cargo
                     .packages()
@@ -425,6 +434,7 @@ impl ProjectWorkspace {
                 rustc_cfg,
                 cfg_overrides,
                 build_scripts,
+                toolchain: _,
             } => cargo_to_crate_graph(
                 rustc_cfg.clone(),
                 cfg_overrides,
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 49ccad71a1..ceb2a6d703 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -219,6 +219,7 @@ impl GlobalState {
                     cfg_overrides,
 
                     build_scripts: _,
+                    toolchain: _,
                 } => Some((cargo, sysroot, rustc, rustc_cfg, cfg_overrides)),
                 _ => None,
             };


Test patch:
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index e304a59c01..8d0fa757c2 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -28,6 +28,7 @@ fn load_cargo_with_overrides(file: &str, cfg_overrides: CfgOverrides) -> CrateGr
         rustc: None,
         rustc_cfg: Vec::new(),
         cfg_overrides,
+        toolchain: None,
     };
     to_crate_graph(project_workspace)
 }