From 8f3335f5fbe06505fa85538c7cd04eb87eae7ecf Mon Sep 17 00:00:00 2001
From: Aleksey Kladov <aleksey.kladov@gmail.com>
Date: Sat, 17 Jul 2021 23:43:54 +0300
Subject: [PATCH] internal: make it clearer where IO happens

---
 crates/base_db/src/fixture.rs               |  7 ++--
 crates/base_db/src/input.rs                 |  4 +++
 crates/ide/src/lib.rs                       |  2 +-
 crates/project_model/src/cargo_workspace.rs | 38 ++++++++++++++++-----
 crates/project_model/src/workspace.rs       | 21 ++++++------
 5 files changed, 47 insertions(+), 25 deletions(-)

diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 7d5d12e6300..5bdc427f739 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -156,7 +156,7 @@ impl ChangeFixture {
             let crate_root = default_crate_root.unwrap();
             crate_graph.add_crate_root(
                 crate_root,
-                Edition::Edition2018,
+                Edition::CURRENT,
                 Some(CrateName::new("test").unwrap().into()),
                 default_cfg.clone(),
                 default_cfg,
@@ -227,10 +227,7 @@ impl From<Fixture> for FileMeta {
             krate: f.krate,
             deps: f.deps,
             cfg,
-            edition: f
-                .edition
-                .as_ref()
-                .map_or(Edition::Edition2018, |v| Edition::from_str(v).unwrap()),
+            edition: f.edition.as_ref().map_or(Edition::CURRENT, |v| Edition::from_str(v).unwrap()),
             env: f.env.into_iter().collect(),
             introduce_new_source_root: f.introduce_new_source_root,
         }
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 0b80e9e47d7..5f746ec5a5e 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -195,6 +195,10 @@ pub enum Edition {
     Edition2021,
 }
 
+impl Edition {
+    pub const CURRENT: Edition = Edition::Edition2018;
+}
+
 #[derive(Default, Debug, Clone, PartialEq, Eq)]
 pub struct Env {
     entries: FxHashMap<String, String>,
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index f8c811c8ed6..525f052ede6 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -217,7 +217,7 @@ impl Analysis {
         cfg_options.insert_atom("test".into());
         crate_graph.add_crate_root(
             file_id,
-            Edition::Edition2018,
+            Edition::CURRENT,
             None,
             cfg_options.clone(),
             cfg_options,
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index 5f65b7bbe6e..4ee720a53ab 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -228,11 +228,11 @@ struct PackageMetadata {
 }
 
 impl CargoWorkspace {
-    pub fn from_cargo_metadata(
+    pub fn fetch_metadata(
         cargo_toml: &AbsPath,
         config: &CargoConfig,
         progress: &dyn Fn(String),
-    ) -> Result<CargoWorkspace> {
+    ) -> Result<cargo_metadata::Metadata> {
         let mut meta = MetadataCommand::new();
         meta.cargo_path(toolchain::cargo());
         meta.manifest_path(cargo_toml.to_path_buf());
@@ -262,10 +262,12 @@ impl CargoWorkspace {
             meta.other_options(vec![String::from("--filter-platform"), target]);
         }
 
-        // FIXME: Currently MetadataCommand is not based on parse_stream,
-        // So we just report it as a whole
+        // FIXME: Fetching metadata is a slow process, as it might require
+        // calling crates.io. We should be reporting progress here, but it's
+        // unclear whether cargo itself supports it.
         progress("metadata".to_string());
-        let mut meta = meta.exec().with_context(|| {
+
+        let meta = meta.exec().with_context(|| {
             let cwd: Option<AbsPathBuf> =
                 std::env::current_dir().ok().and_then(|p| p.try_into().ok());
 
@@ -283,6 +285,14 @@ impl CargoWorkspace {
             )
         })?;
 
+        Ok(meta)
+    }
+
+    pub fn new(
+        cargo_toml: &AbsPath,
+        config: &CargoConfig,
+        mut meta: cargo_metadata::Metadata,
+    ) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
         let mut packages = Arena::default();
         let mut targets = Arena::default();
@@ -296,9 +306,10 @@ impl CargoWorkspace {
             } = meta_pkg;
             let meta = from_value::<PackageMetadata>(metadata.clone()).unwrap_or_default();
             let is_member = ws_members.contains(id);
-            let edition = edition
-                .parse::<Edition>()
-                .with_context(|| format!("Failed to parse edition {}", edition))?;
+            let edition = edition.parse::<Edition>().unwrap_or_else(|err| {
+                log::error!("Failed to parse edition {}", err);
+                Edition::CURRENT
+            });
 
             let pkg = packages.alloc(PackageData {
                 id: id.repr.clone(),
@@ -366,7 +377,16 @@ impl CargoWorkspace {
         let build_data_config =
             BuildDataConfig::new(cargo_toml.to_path_buf(), config.clone(), Arc::new(meta.packages));
 
-        Ok(CargoWorkspace { packages, targets, workspace_root, build_data_config })
+        CargoWorkspace { packages, targets, workspace_root, build_data_config }
+    }
+
+    pub fn from_cargo_metadata3(
+        cargo_toml: &AbsPath,
+        config: &CargoConfig,
+        progress: &dyn Fn(String),
+    ) -> Result<CargoWorkspace> {
+        let meta = CargoWorkspace::fetch_metadata(cargo_toml, config, progress)?;
+        Ok(CargoWorkspace::new(cargo_toml, config, meta))
     }
 
     pub fn packages<'a>(&'a self) -> impl Iterator<Item = Package> + ExactSizeIterator + 'a {
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index c1750d43a5f..76c4388f193 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -126,7 +126,7 @@ impl ProjectWorkspace {
                     cmd
                 })?;
 
-                let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, config, progress)
+                let meta = CargoWorkspace::fetch_metadata(&cargo_toml, config, progress)
                     .with_context(|| {
                         format!(
                             "Failed to read Cargo metadata from Cargo.toml file {}, {}",
@@ -134,6 +134,7 @@ impl ProjectWorkspace {
                             cargo_version
                         )
                     })?;
+                let cargo = CargoWorkspace::new(&cargo_toml, config, meta);
 
                 let sysroot = if config.no_sysroot {
                     Sysroot::default()
@@ -156,15 +157,15 @@ impl ProjectWorkspace {
                     None
                 };
 
-                let rustc = if let Some(rustc_dir) = rustc_dir {
-                    Some(
-                        CargoWorkspace::from_cargo_metadata(&rustc_dir, config, progress)
+                let rustc = match rustc_dir {
+                    Some(rustc_dir) => Some({
+                        let meta = CargoWorkspace::fetch_metadata(&rustc_dir, config, progress)
                             .with_context(|| {
                                 format!("Failed to read Cargo metadata for Rust sources")
-                            })?,
-                    )
-                } else {
-                    None
+                            })?;
+                        CargoWorkspace::new(&rustc_dir, config, meta)
+                    }),
+                    None => None,
                 };
 
                 let rustc_cfg = rustc_cfg::get(Some(&cargo_toml), config.target.as_deref());
@@ -595,7 +596,7 @@ fn detached_files_to_crate_graph(
             .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
         let detached_file_crate = crate_graph.add_crate_root(
             file_id,
-            Edition::Edition2018,
+            Edition::CURRENT,
             display_name,
             cfg_options.clone(),
             cfg_options.clone(),
@@ -777,7 +778,7 @@ fn sysroot_to_crate_graph(
             let display_name = CrateDisplayName::from_canonical_name(sysroot[krate].name.clone());
             let crate_id = crate_graph.add_crate_root(
                 file_id,
-                Edition::Edition2018,
+                Edition::CURRENT,
                 Some(display_name),
                 cfg_options.clone(),
                 cfg_options.clone(),