about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLukas Wirth <lukastw97@gmail.com>2023-04-03 18:24:11 +0200
committerLukas Wirth <lukastw97@gmail.com>2023-04-25 10:57:25 +0200
commita4c7a87755d2d4abfb957ef98a1368a359154917 (patch)
tree710a1a8c437de1ddd58ed8861c52b785640dd7c7
parent980c75bc91c1d7648498f28e4ba89be520eb6a52 (diff)
Handle dev-dependency cycles
-rw-r--r--crates/base-db/src/input.rs11
-rw-r--r--crates/project-model/src/workspace.rs155
-rw-r--r--crates/project-model/test_data/cargo_dev_dependencies-crate-graph.txt1121
3 files changed, 752 insertions, 535 deletions
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index dfd0b2abc33..a153e7f36cd 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -417,6 +417,11 @@ impl CrateGraph {
         Ok(())
     }
 
+    pub fn duplicate(&mut self, id: CrateId) -> CrateId {
+        let data = self[id].clone();
+        self.arena.alloc(data)
+    }
+
     pub fn add_dep(
         &mut self,
         from: CrateId,
@@ -612,6 +617,12 @@ impl ops::Index<CrateId> for CrateGraph {
     }
 }
 
+impl ops::IndexMut<CrateId> for CrateGraph {
+    fn index_mut(&mut self, crate_id: CrateId) -> &mut CrateData {
+        &mut self.arena[crate_id]
+    }
+}
+
 impl CrateData {
     fn add_dep(&mut self, dep: Dependency) {
         self.dependencies.push(dep)
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 5518b6bc7f5..a0b185a3a59 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -2,7 +2,12 @@
 //! metadata` or `rust-project.json`) into representation stored in the salsa
 //! database -- `CrateGraph`.
 
-use std::{collections::VecDeque, fmt, fs, process::Command, sync::Arc};
+use std::{
+    collections::{hash_map::Entry, VecDeque},
+    fmt, fs,
+    process::Command,
+    sync::Arc,
+};
 
 use anyhow::{format_err, Context, Result};
 use base_db::{
@@ -844,12 +849,12 @@ fn cargo_to_crate_graph(
         None => (SysrootPublicDeps::default(), None),
     };
 
-    let cfg_options = {
+    let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
         let mut cfg_options = CfgOptions::default();
         cfg_options.extend(rustc_cfg);
         cfg_options.insert_atom("debug_assertions".into());
         cfg_options
-    };
+    });
 
     // Mapping of a package to its library target
     let mut pkg_to_lib_crate = FxHashMap::default();
@@ -861,32 +866,6 @@ fn cargo_to_crate_graph(
     for pkg in cargo.packages() {
         has_private |= cargo[pkg].metadata.rustc_private;
 
-        let cfg_options = forced_cfg.clone().unwrap_or_else(|| {
-            let mut cfg_options = cfg_options.clone();
-
-            // Add test cfg for local crates
-            if cargo[pkg].is_local {
-                cfg_options.insert_atom("test".into());
-            }
-
-            let overrides = match override_cfg {
-                CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
-                CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
-            };
-
-            if let Some(overrides) = overrides {
-                // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
-                // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
-                // working on rust-lang/rust as that's the only time it appears outside sysroot).
-                //
-                // A more ideal solution might be to reanalyze crates based on where the cursor is and
-                // figure out the set of cfgs that would have to apply to make it active.
-
-                cfg_options.apply_diff(overrides.clone());
-            };
-            cfg_options
-        });
-
         let mut lib_tgt = None;
         for &tgt in cargo[pkg].targets.iter() {
             if cargo[tgt].kind != TargetKind::Lib && !cargo[pkg].is_member {
@@ -897,7 +876,7 @@ fn cargo_to_crate_graph(
                 // https://github.com/rust-lang/rust-analyzer/issues/11300
                 continue;
             }
-            let Some(file_id) =  load(&cargo[tgt].root) else { continue };
+            let Some(file_id) = load(&cargo[tgt].root) else { continue };
 
             let crate_id = add_target_crate_root(
                 crate_graph,
@@ -925,15 +904,19 @@ fn cargo_to_crate_graph(
             pkg_crates.entry(pkg).or_insert_with(Vec::new).push((crate_id, cargo[tgt].kind));
         }
 
+        let Some(targets) = pkg_crates.get(&pkg) else { continue };
         // Set deps to the core, std and to the lib target of the current package
-        for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
+        for &(from, kind) in targets {
             // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
             public_deps.add_to_crate_graph(crate_graph, from);
 
             // Add dep edge of all targets to the package's lib target
             if let Some((to, name)) = lib_tgt.clone() {
-                if to != from && kind != TargetKind::BuildScript {
-                    // (build script can not depend on its library target)
+                if to != from {
+                    if kind == TargetKind::BuildScript {
+                        // build script can not depend on its library target
+                        continue;
+                    }
 
                     // For root projects with dashes in their name,
                     // cargo metadata does not do any normalization,
@@ -945,6 +928,43 @@ fn cargo_to_crate_graph(
         }
     }
 
+    // We now need to duplicate workspace members that are used as dev-dependencies to prevent
+    // cycles from forming.
+
+    // Map from crate id to it's dev-dependency clone id
+    let mut test_dupes = FxHashMap::default();
+    let mut work = vec![];
+
+    // Get all dependencies of the workspace members that are used as dev-dependencies
+    for pkg in cargo.packages() {
+        for dep in &cargo[pkg].dependencies {
+            if dep.kind == DepKind::Dev {
+                work.push(dep.pkg);
+            }
+        }
+    }
+    while let Some(pkg) = work.pop() {
+        let Some(&to) = pkg_to_lib_crate.get(&pkg) else { continue };
+        match test_dupes.entry(to) {
+            Entry::Occupied(_) => continue,
+            Entry::Vacant(v) => {
+                for dep in &cargo[pkg].dependencies {
+                    if dep.kind == DepKind::Normal && cargo[dep.pkg].is_member {
+                        work.push(dep.pkg);
+                    }
+                }
+                v.insert({
+                    let duped = crate_graph.duplicate(to);
+                    if let Some(proc_macro) = proc_macros.get(&to).cloned() {
+                        proc_macros.insert(duped, proc_macro);
+                    }
+                    crate_graph[duped].cfg_options.insert_atom("test".into());
+                    duped
+                });
+            }
+        }
+    }
+
     // Now add a dep edge from all targets of upstream to the lib
     // target of downstream.
     for pkg in cargo.packages() {
@@ -958,12 +978,66 @@ fn cargo_to_crate_graph(
                 if (dep.kind == DepKind::Build) != (kind == TargetKind::BuildScript) {
                     continue;
                 }
+                add_dep(
+                    crate_graph,
+                    from,
+                    name.clone(),
+                    if dep.kind == DepKind::Dev {
+                        // point to the test enabled duplicate for dev-dependencies
+                        test_dupes.get(&to).copied().unwrap_or(to)
+                    } else {
+                        to
+                    },
+                );
 
-                add_dep(crate_graph, from, name.clone(), to)
+                if dep.kind == DepKind::Normal && cargo[dep.pkg].is_member {
+                    // Also apply the dependency as a test enabled dependency to the test duplicate
+                    if let Some(&dupe) = test_dupes.get(&from) {
+                        let to = test_dupes.get(&to).copied().unwrap_or_else(|| {
+                            panic!(
+                                "dependency of a dev dependency did not get duplicated! {:?} {:?}",
+                                crate_graph[to].display_name, crate_graph[from].display_name,
+                            )
+                        });
+                        add_dep(crate_graph, dupe, name.clone(), to);
+                    }
+                }
+            }
+        }
+    }
+
+    for (&pkg, targets) in &pkg_crates {
+        for &(krate, _) in targets {
+            if test_dupes.get(&krate).is_some() {
+                // if the crate got duped as a dev-dep the dupe already has test set
+                continue;
+            }
+            let cfg_options = &mut crate_graph[krate].cfg_options;
+
+            // Add test cfg for local crates
+            if cargo[pkg].is_local {
+                cfg_options.insert_atom("test".into());
             }
+
+            let overrides = match override_cfg {
+                CfgOverrides::Wildcard(cfg_diff) => Some(cfg_diff),
+                CfgOverrides::Selective(cfg_overrides) => cfg_overrides.get(&cargo[pkg].name),
+            };
+
+            if let Some(overrides) = overrides {
+                // FIXME: this is sort of a hack to deal with #![cfg(not(test))] vanishing such as seen
+                // in ed25519_dalek (#7243), and libcore (#9203) (although you only hit that one while
+                // working on rust-lang/rust as that's the only time it appears outside sysroot).
+                //
+                // A more ideal solution might be to reanalyze crates based on where the cursor is and
+                // figure out the set of cfgs that would have to apply to make it active.
+
+                cfg_options.apply_diff(overrides.clone());
+            };
         }
     }
 
+    // FIXME: Handle rustc private crates properly when used as dev-dependencies
     if has_private {
         // If the user provided a path to rustc sources, we add all the rustc_private crates
         // and create dependencies on them for the crates which opt-in to that
@@ -1087,7 +1161,9 @@ fn handle_rustc_crates(
                 continue;
             }
             for dep in &rustc_workspace[pkg].dependencies {
-                queue.push_back(dep.pkg);
+                if dep.kind == DepKind::Normal {
+                    queue.push_back(dep.pkg);
+                }
             }
 
             let mut cfg_options = cfg_options.clone();
@@ -1397,10 +1473,12 @@ fn handle_hack_cargo_workspace(
         .collect()
 }
 
+#[track_caller]
 fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
     add_dep_inner(graph, from, Dependency::new(name, to))
 }
 
+#[track_caller]
 fn add_dep_with_prelude(
     graph: &mut CrateGraph,
     from: CrateId,
@@ -1411,13 +1489,18 @@ fn add_dep_with_prelude(
     add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
 }
 
+#[track_caller]
 fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
     add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
 }
 
+#[track_caller]
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
     if let Err(err) = graph.add_dep(from, dep) {
-        tracing::error!("{}", err)
+        if cfg!(test) {
+            panic!("{}", err);
+        }
+        tracing::error!("{}", err);
     }
 }
 
diff --git a/crates/project-model/test_data/cargo_dev_dependencies-crate-graph.txt b/crates/project-model/test_data/cargo_dev_dependencies-crate-graph.txt
index 914c7db038c..2dba4efa923 100644
--- a/crates/project-model/test_data/cargo_dev_dependencies-crate-graph.txt
+++ b/crates/project-model/test_data/cargo_dev_dependencies-crate-graph.txt
@@ -1,402 +1,405 @@
-CrateGraph {
-    arena: {
-        CrateId(
-            0,
-        ): CrateData {
-            root_file_id: FileId(
-                1,
-            ),
-            edition: Edition2018,
-            version: Some(
-                "0.7.20",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "aho_corasick",
-                    ),
-                    canonical_name: "aho_corasick",
-                },
-            ),
-            cfg_options: CfgOptions(
+{
+    0: CrateData {
+        root_file_id: FileId(
+            1,
+        ),
+        edition: Edition2018,
+        version: Some(
+            "0.7.20",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "aho_corasick",
+                ),
+                canonical_name: "aho_corasick",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "feature=default",
+                "feature=std",
+            ],
+        ),
+        potential_cfg_options: Some(
+            CfgOptions(
                 [
                     "debug_assertions",
                     "feature=default",
                     "feature=std",
                 ],
             ),
-            potential_cfg_options: Some(
-                CfgOptions(
-                    [
-                        "debug_assertions",
-                        "feature=default",
-                        "feature=std",
-                    ],
-                ),
-            ),
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "0",
-                    "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/aho-corasick-0.7.20",
-                    "CARGO_PKG_VERSION": "0.7.20",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "aho_corasick",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "aho-corasick",
-                    "CARGO_PKG_VERSION_PATCH": "20",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "7",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+        ),
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/aho-corasick-0.7.20",
+                "CARGO_PKG_VERSION": "0.7.20",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "aho_corasick",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "aho-corasick",
+                "CARGO_PKG_VERSION_PATCH": "20",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "7",
+                "CARGO_PKG_VERSION_PRE": "",
             },
-            dependencies: [
-                Dependency {
-                    crate_id: CrateId(
-                        2,
-                    ),
-                    name: CrateName(
-                        "memchr",
-                    ),
-                    prelude: true,
-                },
-            ],
-            origin: Library {
-                repo: Some(
-                    "https://github.com/BurntSushi/aho-corasick",
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(2),
+                name: CrateName(
+                    "memchr",
                 ),
-                name: "aho-corasick",
+                prelude: true,
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
+        ],
+        origin: Library {
+            repo: Some(
+                "https://github.com/BurntSushi/aho-corasick",
             ),
-            channel: None,
+            name: "aho-corasick",
         },
-        CrateId(
-            1,
-        ): CrateData {
-            root_file_id: FileId(
-                2,
-            ),
-            edition: Edition2021,
-            version: Some(
-                "0.3.0",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "la_arena",
-                    ),
-                    canonical_name: "la-arena",
-                },
-            ),
-            cfg_options: CfgOptions(
-                [
-                    "debug_assertions",
-                ],
-            ),
-            potential_cfg_options: None,
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "0",
-                    "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/la-arena-0.3.0",
-                    "CARGO_PKG_VERSION": "0.3.0",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "la_arena",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "la-arena",
-                    "CARGO_PKG_VERSION_PATCH": "0",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "3",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
-            },
-            dependencies: [],
-            origin: Library {
-                repo: Some(
-                    "https://github.com/rust-lang/rust-analyzer/tree/master/lib/la-arena",
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    1: CrateData {
+        root_file_id: FileId(
+            2,
+        ),
+        edition: Edition2021,
+        version: Some(
+            "0.3.0",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "la_arena",
                 ),
-                name: "la-arena",
+                canonical_name: "la-arena",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/la-arena-0.3.0",
+                "CARGO_PKG_VERSION": "0.3.0",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "la_arena",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "la-arena",
+                "CARGO_PKG_VERSION_PATCH": "0",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "3",
+                "CARGO_PKG_VERSION_PRE": "",
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
-            ),
-            channel: None,
         },
-        CrateId(
-            2,
-        ): CrateData {
-            root_file_id: FileId(
-                3,
+        dependencies: [],
+        origin: Library {
+            repo: Some(
+                "https://github.com/rust-lang/rust-analyzer/tree/master/lib/la-arena",
             ),
-            edition: Edition2018,
-            version: Some(
-                "2.5.0",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "memchr",
-                    ),
-                    canonical_name: "memchr",
-                },
-            ),
-            cfg_options: CfgOptions(
+            name: "la-arena",
+        },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    2: CrateData {
+        root_file_id: FileId(
+            3,
+        ),
+        edition: Edition2018,
+        version: Some(
+            "2.5.0",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "memchr",
+                ),
+                canonical_name: "memchr",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "feature=default",
+                "feature=std",
+            ],
+        ),
+        potential_cfg_options: Some(
+            CfgOptions(
                 [
                     "debug_assertions",
+                    "feature=compiler_builtins",
+                    "feature=core",
                     "feature=default",
+                    "feature=libc",
+                    "feature=rustc-dep-of-std",
                     "feature=std",
+                    "feature=use_std",
                 ],
             ),
-            potential_cfg_options: Some(
-                CfgOptions(
-                    [
-                        "debug_assertions",
-                        "feature=compiler_builtins",
-                        "feature=core",
-                        "feature=default",
-                        "feature=libc",
-                        "feature=rustc-dep-of-std",
-                        "feature=std",
-                        "feature=use_std",
-                    ],
-                ),
-            ),
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "2",
-                    "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0",
-                    "CARGO_PKG_VERSION": "2.5.0",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "memchr",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "memchr",
-                    "CARGO_PKG_VERSION_PATCH": "0",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "5",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+        ),
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "2",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/memchr-2.5.0",
+                "CARGO_PKG_VERSION": "2.5.0",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "memchr",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "memchr",
+                "CARGO_PKG_VERSION_PATCH": "0",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "5",
+                "CARGO_PKG_VERSION_PRE": "",
             },
-            dependencies: [],
-            origin: Library {
-                repo: Some(
-                    "https://github.com/BurntSushi/memchr",
-                ),
-                name: "memchr",
-            },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
-            ),
-            channel: None,
         },
-        CrateId(
-            3,
-        ): CrateData {
-            root_file_id: FileId(
-                4,
-            ),
-            edition: Edition2021,
-            version: Some(
-                "0.1.0",
+        dependencies: [],
+        origin: Library {
+            repo: Some(
+                "https://github.com/BurntSushi/memchr",
             ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "ra_playground",
-                    ),
-                    canonical_name: "ra-playground",
-                },
-            ),
-            cfg_options: CfgOptions(
-                [
-                    "debug_assertions",
-                    "test",
-                ],
-            ),
-            potential_cfg_options: None,
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "0",
-                    "CARGO_MANIFEST_DIR": "$ROOT$ra-playground",
-                    "CARGO_PKG_VERSION": "0.1.0",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "ra_playground",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "ra-playground",
-                    "CARGO_PKG_VERSION_PATCH": "0",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "1",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+            name: "memchr",
+        },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    3: CrateData {
+        root_file_id: FileId(
+            4,
+        ),
+        edition: Edition2021,
+        version: Some(
+            "0.1.0",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "ra_playground",
+                ),
+                canonical_name: "ra-playground",
             },
-            dependencies: [
-                Dependency {
-                    crate_id: CrateId(
-                        1,
-                    ),
-                    name: CrateName(
-                        "la_arena",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        5,
-                    ),
-                    name: CrateName(
-                        "regex",
-                    ),
-                    prelude: true,
-                },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
             ],
-            origin: Local {
-                repo: None,
-                name: Some(
-                    "ra-playground",
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$ra-playground",
+                "CARGO_PKG_VERSION": "0.1.0",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "ra_playground",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "ra-playground",
+                "CARGO_PKG_VERSION_PATCH": "0",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "1",
+                "CARGO_PKG_VERSION_PRE": "",
+            },
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "la_arena",
+                ),
+                prelude: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "ra_playground",
+                ),
+                prelude: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(7),
+                name: CrateName(
+                    "regex",
                 ),
+                prelude: true,
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
+        ],
+        origin: Local {
+            repo: None,
+            name: Some(
+                "ra-playground",
             ),
-            channel: None,
         },
-        CrateId(
-            4,
-        ): CrateData {
-            root_file_id: FileId(
-                5,
-            ),
-            edition: Edition2021,
-            version: Some(
-                "0.1.0",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "ra_playground",
-                    ),
-                    canonical_name: "ra-playground",
-                },
-            ),
-            cfg_options: CfgOptions(
-                [
-                    "debug_assertions",
-                    "test",
-                ],
-            ),
-            potential_cfg_options: None,
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "0",
-                    "CARGO_MANIFEST_DIR": "$ROOT$ra-playground",
-                    "CARGO_PKG_VERSION": "0.1.0",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "ra_playground",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "ra-playground",
-                    "CARGO_PKG_VERSION_PATCH": "0",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "1",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    4: CrateData {
+        root_file_id: FileId(
+            5,
+        ),
+        edition: Edition2021,
+        version: Some(
+            "0.1.0",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "ra_playground",
+                ),
+                canonical_name: "ra-playground",
             },
-            dependencies: [
-                Dependency {
-                    crate_id: CrateId(
-                        3,
-                    ),
-                    name: CrateName(
-                        "ra_playground",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        1,
-                    ),
-                    name: CrateName(
-                        "la_arena",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        3,
-                    ),
-                    name: CrateName(
-                        "ra_playground",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        5,
-                    ),
-                    name: CrateName(
-                        "regex",
-                    ),
-                    prelude: true,
-                },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "test",
             ],
-            origin: Local {
-                repo: None,
-                name: Some(
-                    "ra-playground",
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$ra-playground",
+                "CARGO_PKG_VERSION": "0.1.0",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "ra_playground",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "ra-playground",
+                "CARGO_PKG_VERSION_PATCH": "0",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "1",
+                "CARGO_PKG_VERSION_PRE": "",
+            },
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(3),
+                name: CrateName(
+                    "ra_playground",
                 ),
+                prelude: true,
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
+            Dependency {
+                crate_id: Idx::<CrateData>(1),
+                name: CrateName(
+                    "la_arena",
+                ),
+                prelude: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(8),
+                name: CrateName(
+                    "ra_playground",
+                ),
+                prelude: true,
+            },
+            Dependency {
+                crate_id: Idx::<CrateData>(7),
+                name: CrateName(
+                    "regex",
+                ),
+                prelude: true,
+            },
+        ],
+        origin: Local {
+            repo: None,
+            name: Some(
+                "ra-playground",
             ),
-            channel: None,
         },
-        CrateId(
-            5,
-        ): CrateData {
-            root_file_id: FileId(
-                6,
-            ),
-            edition: Edition2018,
-            version: Some(
-                "1.7.3",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "regex",
-                    ),
-                    canonical_name: "regex",
-                },
-            ),
-            cfg_options: CfgOptions(
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    5: CrateData {
+        root_file_id: FileId(
+            6,
+        ),
+        edition: Edition2018,
+        version: Some(
+            "1.7.3",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "regex",
+                ),
+                canonical_name: "regex",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "feature=aho-corasick",
+                "feature=default",
+                "feature=memchr",
+                "feature=perf",
+                "feature=perf-cache",
+                "feature=perf-dfa",
+                "feature=perf-inline",
+                "feature=perf-literal",
+                "feature=std",
+                "feature=unicode",
+                "feature=unicode-age",
+                "feature=unicode-bool",
+                "feature=unicode-case",
+                "feature=unicode-gencat",
+                "feature=unicode-perl",
+                "feature=unicode-script",
+                "feature=unicode-segment",
+            ],
+        ),
+        potential_cfg_options: Some(
+            CfgOptions(
                 [
                     "debug_assertions",
                     "feature=aho-corasick",
                     "feature=default",
                     "feature=memchr",
+                    "feature=pattern",
                     "feature=perf",
                     "feature=perf-cache",
                     "feature=perf-dfa",
@@ -411,114 +414,97 @@ CrateGraph {
                     "feature=unicode-perl",
                     "feature=unicode-script",
                     "feature=unicode-segment",
+                    "feature=unstable",
+                    "feature=use_std",
                 ],
             ),
-            potential_cfg_options: Some(
-                CfgOptions(
-                    [
-                        "debug_assertions",
-                        "feature=aho-corasick",
-                        "feature=default",
-                        "feature=memchr",
-                        "feature=pattern",
-                        "feature=perf",
-                        "feature=perf-cache",
-                        "feature=perf-dfa",
-                        "feature=perf-inline",
-                        "feature=perf-literal",
-                        "feature=std",
-                        "feature=unicode",
-                        "feature=unicode-age",
-                        "feature=unicode-bool",
-                        "feature=unicode-case",
-                        "feature=unicode-gencat",
-                        "feature=unicode-perl",
-                        "feature=unicode-script",
-                        "feature=unicode-segment",
-                        "feature=unstable",
-                        "feature=use_std",
-                    ],
+        ),
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "1",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.7.3",
+                "CARGO_PKG_VERSION": "1.7.3",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "regex",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "regex",
+                "CARGO_PKG_VERSION_PATCH": "3",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "7",
+                "CARGO_PKG_VERSION_PRE": "",
+            },
+        },
+        dependencies: [
+            Dependency {
+                crate_id: Idx::<CrateData>(0),
+                name: CrateName(
+                    "aho_corasick",
                 ),
-            ),
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "1",
-                    "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.7.3",
-                    "CARGO_PKG_VERSION": "1.7.3",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "regex",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "regex",
-                    "CARGO_PKG_VERSION_PATCH": "3",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "7",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+                prelude: true,
             },
-            dependencies: [
-                Dependency {
-                    crate_id: CrateId(
-                        0,
-                    ),
-                    name: CrateName(
-                        "aho_corasick",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        2,
-                    ),
-                    name: CrateName(
-                        "memchr",
-                    ),
-                    prelude: true,
-                },
-                Dependency {
-                    crate_id: CrateId(
-                        6,
-                    ),
-                    name: CrateName(
-                        "regex_syntax",
-                    ),
-                    prelude: true,
-                },
-            ],
-            origin: Library {
-                repo: Some(
-                    "https://github.com/rust-lang/regex",
+            Dependency {
+                crate_id: Idx::<CrateData>(2),
+                name: CrateName(
+                    "memchr",
                 ),
-                name: "regex",
+                prelude: true,
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
+            Dependency {
+                crate_id: Idx::<CrateData>(6),
+                name: CrateName(
+                    "regex_syntax",
+                ),
+                prelude: true,
+            },
+        ],
+        origin: Library {
+            repo: Some(
+                "https://github.com/rust-lang/regex",
             ),
-            channel: None,
+            name: "regex",
         },
-        CrateId(
-            6,
-        ): CrateData {
-            root_file_id: FileId(
-                7,
-            ),
-            edition: Edition2018,
-            version: Some(
-                "0.6.29",
-            ),
-            display_name: Some(
-                CrateDisplayName {
-                    crate_name: CrateName(
-                        "regex_syntax",
-                    ),
-                    canonical_name: "regex-syntax",
-                },
-            ),
-            cfg_options: CfgOptions(
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    6: CrateData {
+        root_file_id: FileId(
+            7,
+        ),
+        edition: Edition2018,
+        version: Some(
+            "0.6.29",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "regex_syntax",
+                ),
+                canonical_name: "regex-syntax",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "feature=default",
+                "feature=unicode",
+                "feature=unicode-age",
+                "feature=unicode-bool",
+                "feature=unicode-case",
+                "feature=unicode-gencat",
+                "feature=unicode-perl",
+                "feature=unicode-script",
+                "feature=unicode-segment",
+            ],
+        ),
+        potential_cfg_options: Some(
+            CfgOptions(
                 [
                     "debug_assertions",
                     "feature=default",
@@ -532,53 +518,190 @@ CrateGraph {
                     "feature=unicode-segment",
                 ],
             ),
-            potential_cfg_options: Some(
-                CfgOptions(
-                    [
-                        "debug_assertions",
-                        "feature=default",
-                        "feature=unicode",
-                        "feature=unicode-age",
-                        "feature=unicode-bool",
-                        "feature=unicode-case",
-                        "feature=unicode-gencat",
-                        "feature=unicode-perl",
-                        "feature=unicode-script",
-                        "feature=unicode-segment",
-                    ],
+        ),
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.6.29",
+                "CARGO_PKG_VERSION": "0.6.29",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "regex_syntax",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "regex-syntax",
+                "CARGO_PKG_VERSION_PATCH": "29",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "6",
+                "CARGO_PKG_VERSION_PRE": "",
+            },
+        },
+        dependencies: [],
+        origin: Library {
+            repo: Some(
+                "https://github.com/rust-lang/regex",
+            ),
+            name: "regex-syntax",
+        },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    7: CrateData {
+        root_file_id: FileId(
+            6,
+        ),
+        edition: Edition2018,
+        version: Some(
+            "1.7.3",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "regex",
                 ),
+                canonical_name: "regex",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "feature=aho-corasick",
+                "feature=default",
+                "feature=memchr",
+                "feature=perf",
+                "feature=perf-cache",
+                "feature=perf-dfa",
+                "feature=perf-inline",
+                "feature=perf-literal",
+                "feature=std",
+                "feature=unicode",
+                "feature=unicode-age",
+                "feature=unicode-bool",
+                "feature=unicode-case",
+                "feature=unicode-gencat",
+                "feature=unicode-perl",
+                "feature=unicode-script",
+                "feature=unicode-segment",
+                "test",
+            ],
+        ),
+        potential_cfg_options: Some(
+            CfgOptions(
+                [
+                    "debug_assertions",
+                    "feature=aho-corasick",
+                    "feature=default",
+                    "feature=memchr",
+                    "feature=pattern",
+                    "feature=perf",
+                    "feature=perf-cache",
+                    "feature=perf-dfa",
+                    "feature=perf-inline",
+                    "feature=perf-literal",
+                    "feature=std",
+                    "feature=unicode",
+                    "feature=unicode-age",
+                    "feature=unicode-bool",
+                    "feature=unicode-case",
+                    "feature=unicode-gencat",
+                    "feature=unicode-perl",
+                    "feature=unicode-script",
+                    "feature=unicode-segment",
+                    "feature=unstable",
+                    "feature=use_std",
+                ],
             ),
-            env: Env {
-                entries: {
-                    "CARGO_PKG_LICENSE": "",
-                    "CARGO_PKG_VERSION_MAJOR": "0",
-                    "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/regex-syntax-0.6.29",
-                    "CARGO_PKG_VERSION": "0.6.29",
-                    "CARGO_PKG_AUTHORS": "",
-                    "CARGO_CRATE_NAME": "regex_syntax",
-                    "CARGO_PKG_LICENSE_FILE": "",
-                    "CARGO_PKG_HOMEPAGE": "",
-                    "CARGO_PKG_DESCRIPTION": "",
-                    "CARGO_PKG_NAME": "regex-syntax",
-                    "CARGO_PKG_VERSION_PATCH": "29",
-                    "CARGO": "cargo",
-                    "CARGO_PKG_REPOSITORY": "",
-                    "CARGO_PKG_VERSION_MINOR": "6",
-                    "CARGO_PKG_VERSION_PRE": "",
-                },
+        ),
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "1",
+                "CARGO_MANIFEST_DIR": "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/regex-1.7.3",
+                "CARGO_PKG_VERSION": "1.7.3",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "regex",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "regex",
+                "CARGO_PKG_VERSION_PATCH": "3",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "7",
+                "CARGO_PKG_VERSION_PRE": "",
             },
-            dependencies: [],
-            origin: Library {
-                repo: Some(
-                    "https://github.com/rust-lang/regex",
+        },
+        dependencies: [],
+        origin: Library {
+            repo: Some(
+                "https://github.com/rust-lang/regex",
+            ),
+            name: "regex",
+        },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
+    },
+    8: CrateData {
+        root_file_id: FileId(
+            4,
+        ),
+        edition: Edition2021,
+        version: Some(
+            "0.1.0",
+        ),
+        display_name: Some(
+            CrateDisplayName {
+                crate_name: CrateName(
+                    "ra_playground",
                 ),
-                name: "regex-syntax",
+                canonical_name: "ra-playground",
+            },
+        ),
+        cfg_options: CfgOptions(
+            [
+                "debug_assertions",
+                "test",
+            ],
+        ),
+        potential_cfg_options: None,
+        env: Env {
+            entries: {
+                "CARGO_PKG_LICENSE": "",
+                "CARGO_PKG_VERSION_MAJOR": "0",
+                "CARGO_MANIFEST_DIR": "$ROOT$ra-playground",
+                "CARGO_PKG_VERSION": "0.1.0",
+                "CARGO_PKG_AUTHORS": "",
+                "CARGO_CRATE_NAME": "ra_playground",
+                "CARGO_PKG_LICENSE_FILE": "",
+                "CARGO_PKG_HOMEPAGE": "",
+                "CARGO_PKG_DESCRIPTION": "",
+                "CARGO_PKG_NAME": "ra-playground",
+                "CARGO_PKG_VERSION_PATCH": "0",
+                "CARGO": "cargo",
+                "CARGO_PKG_REPOSITORY": "",
+                "CARGO_PKG_VERSION_MINOR": "1",
+                "CARGO_PKG_VERSION_PRE": "",
             },
-            is_proc_macro: false,
-            target_layout: Err(
-                "target_data_layout not loaded",
+        },
+        dependencies: [],
+        origin: Local {
+            repo: None,
+            name: Some(
+                "ra-playground",
             ),
-            channel: None,
         },
+        is_proc_macro: false,
+        target_layout: Err(
+            "target_data_layout not loaded",
+        ),
+        channel: None,
     },
 }
\ No newline at end of file