Repository: rust-lang/rust-analyzer
Pull request #17439 (2024-06-17 11:11:09)

Properly prime all crate def maps in parallel_prime_caches


Patch:
diff --git a/crates/hir-def/src/hir.rs b/crates/hir-def/src/hir.rs
index fd6f4a3d08..2f7ebbfec1 100644
--- a/crates/hir-def/src/hir.rs
+++ b/crates/hir-def/src/hir.rs
@@ -503,11 +503,11 @@ impl BindingAnnotation {
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum BindingProblems {
-    /// <https://doc.rust-lang.org/stable/error_codes/E0416.html>
+    /// https://doc.rust-lang.org/stable/error_codes/E0416.html
     BoundMoreThanOnce,
-    /// <https://doc.rust-lang.org/stable/error_codes/E0409.html>
+    /// https://doc.rust-lang.org/stable/error_codes/E0409.html
     BoundInconsistently,
-    /// <https://doc.rust-lang.org/stable/error_codes/E0408.html>
+    /// https://doc.rust-lang.org/stable/error_codes/E0408.html
     NotBoundAcrossAll,
 }
 
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 0dcd9129d6..b1f97f2bb9 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -73,7 +73,7 @@ use std::{
 
 use base_db::{
     impl_intern_key,
-    salsa::{self, InternValueTrivial},
+    salsa::{self, impl_intern_value_trivial},
     CrateId,
 };
 use hir_expand::{
@@ -187,7 +187,7 @@ pub trait ItemTreeLoc {
 macro_rules! impl_intern {
     ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
         impl_intern_key!($id);
-        impl InternValueTrivial for $loc {}
+        impl_intern_value_trivial!($loc);
         impl_intern_lookup!(DefDatabase, $id, $loc, $intern, $lookup);
     };
 }
@@ -535,7 +535,7 @@ pub struct TypeOrConstParamId {
     pub parent: GenericDefId,
     pub local_id: LocalTypeOrConstParamId,
 }
-impl InternValueTrivial for TypeOrConstParamId {}
+impl_intern_value_trivial!(TypeOrConstParamId);
 
 /// A TypeOrConstParamId with an invariant that it actually belongs to a type
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -597,7 +597,7 @@ pub struct LifetimeParamId {
     pub local_id: LocalLifetimeParamId,
 }
 pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
-impl InternValueTrivial for LifetimeParamId {}
+impl_intern_value_trivial!(LifetimeParamId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ItemContainerId {
diff --git a/crates/hir-def/src/nameres.rs b/crates/hir-def/src/nameres.rs
index 162b6429c3..256a37f6ec 100644
--- a/crates/hir-def/src/nameres.rs
+++ b/crates/hir-def/src/nameres.rs
@@ -16,8 +16,8 @@
 //!
 //! This happens in the `raw` module, which parses a single source file into a
 //! set of top-level items. Nested imports are desugared to flat imports in this
-//! phase. Macro calls are represented as a triple of `(Path, Option<Name>,
-//! TokenTree)`.
+//! phase. Macro calls are represented as a triple of (Path, Option<Name>,
+//! TokenTree).
 //!
 //! ## Collecting Modules
 //!
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index f83e266744..eadb2e19d1 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -91,7 +91,6 @@ pub(crate) fn fixup_syntax(
             preorder.skip_subtree();
             continue;
         }
-
         // In some other situations, we can fix things by just appending some tokens.
         match_ast! {
             match node {
@@ -276,6 +275,62 @@ pub(crate) fn fixup_syntax(
                         ]);
                     }
                 },
+                ast::RecordExprField(it) => {
+                    if let Some(colon) = it.colon_token() {
+                        if it.name_ref().is_some() {
+                            append.insert(colon.into(), vec![
+                                Leaf::Ident(Ident {
+                                    text: "__ra_fixup".into(),
+                                    span: fake_span(node_range)
+                                })
+                            ]);
+                        }
+                    }
+                },
+                ast::Path(it) => {
+                    if let Some(colon) = it.coloncolon_token() {
+                        if it.segment().is_none() {
+                            append.insert(colon.into(), vec![
+                                Leaf::Ident(Ident {
+                                    text: "__ra_fixup".into(),
+                                    span: fake_span(node_range)
+                                })
+                            ]);
+                        }
+                    }
+                },
+                ast::ArgList(it) => {
+                    if it.r_paren_token().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Punct(Punct {
+                                span: fake_span(node_range),
+                                char: ')',
+                                spacing: Spacing::Alone
+                            })
+                        ]);
+                    }
+                },
+                ast::ArgList(it) => {
+                    if it.r_paren_token().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Punct(Punct {
+                                span: fake_span(node_range),
+                                char: ')',
+                                spacing: Spacing::Alone
+                            })
+                        ]);
+                    }
+                },
+                ast::ClosureExpr(it) => {
+                    if it.body().is_none() {
+                        append.insert(node.into(), vec![
+                            Leaf::Ident(Ident {
+                                text: "__ra_fixup".into(),
+                                span: fake_span(node_range)
+                            })
+                        ]);
+                    }
+                },
                 _ => (),
             }
         }
@@ -759,4 +814,70 @@ fn foo () {loop { }}
 "#]],
         )
     }
+
+    #[test]
+    fn fixup_path() {
+        check(
+            r#"
+fn foo() {
+    path::
+}
+"#,
+            expect![[r#"
+fn foo () {path :: __ra_fixup}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_record_ctor_field() {
+        check(
+            r#"
+fn foo() {
+    R { f: }
+}
+"#,
+            expect![[r#"
+fn foo () {R {f : __ra_fixup}}
+"#]],
+        )
+    }
+
+    #[test]
+    fn fixup_arg_list() {
+        check(
+            r#"
+fn foo() {
+    foo(a
+}
+"#,
+            expect![[r#"
+fn foo () { foo ( a ) }
+"#]],
+        );
+        check(
+            r#"
+fn foo() {
+    bar.foo(a
+}
+"#,
+            expect![[r#"
+fn foo () { bar . foo ( a ) }
+"#]],
+        );
+    }
+
+    #[test]
+    fn fixup_closure() {
+        check(
+            r#"
+fn foo() {
+    ||
+}
+"#,
+            expect![[r#"
+fn foo () {|| __ra_fixup}
+"#]],
+        );
+    }
 }
diff --git a/crates/hir-expand/src/hygiene.rs b/crates/hir-expand/src/hygiene.rs
index cc02332207..097e760c70 100644
--- a/crates/hir-expand/src/hygiene.rs
+++ b/crates/hir-expand/src/hygiene.rs
@@ -4,7 +4,7 @@
 //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
 //! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
 //!
-//! Also see <https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies>
+//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
 //!
 //! # The Expansion Order Hierarchy
 //!
diff --git a/crates/hir-expand/src/lib.rs b/crates/hir-expand/src/lib.rs
index ec0716c5fa..8859b47e4c 100644
--- a/crates/hir-expand/src/lib.rs
+++ b/crates/hir-expand/src/lib.rs
@@ -31,7 +31,7 @@ use triomphe::Arc;
 
 use std::{fmt, hash::Hash};
 
-use base_db::{salsa::InternValueTrivial, CrateId, FileId};
+use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId};
 use either::Either;
 use span::{
     Edition, ErasedFileAstId, FileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor,
@@ -173,7 +173,7 @@ pub struct MacroCallLoc {
     pub kind: MacroCallKind,
     pub ctxt: SyntaxContextId,
 }
-impl InternValueTrivial for MacroCallLoc {}
+impl_intern_value_trivial!(MacroCallLoc);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroDefId {
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 000871ed52..90bf46b505 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -5,7 +5,7 @@ use std::sync;
 
 use base_db::{
     impl_intern_key,
-    salsa::{self, InternValueTrivial},
+    salsa::{self, impl_intern_value_trivial},
     CrateId, Upcast,
 };
 use hir_def::{
@@ -298,8 +298,7 @@ impl_intern_key!(InternedClosureId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedClosure(pub DefWithBodyId, pub ExprId);
-
-impl InternValueTrivial for InternedClosure {}
+impl_intern_value_trivial!(InternedClosure);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedCoroutineId(salsa::InternId);
@@ -307,7 +306,7 @@ impl_intern_key!(InternedCoroutineId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
-impl InternValueTrivial for InternedCoroutine {}
+impl_intern_value_trivial!(InternedCoroutine);
 
 /// This exists just for Chalk, because Chalk just has a single `FnDefId` where
 /// we have different IDs for struct and enum variant constructors.
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index 9d596e957b..26a839f0e9 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -52,7 +52,7 @@ use std::{
     hash::{BuildHasherDefault, Hash},
 };
 
-use base_db::salsa::InternValueTrivial;
+use base_db::salsa::impl_intern_value_trivial;
 use chalk_ir::{
     fold::{Shift, TypeFoldable},
     interner::HasInterner,
@@ -606,7 +606,7 @@ pub enum ImplTraitId {
     AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx),
     AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 }
-impl InternValueTrivial for ImplTraitId {}
+impl_intern_value_trivial!(ImplTraitId);
 
 #[derive(PartialEq, Eq, Debug, Hash)]
 pub struct ImplTraits {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 2e100d5c55..d3e79541ab 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -11,7 +11,7 @@ use std::{
 };
 
 use base_db::{
-    salsa::{Cycle, InternValueTrivial},
+    salsa::{impl_intern_value_trivial, Cycle},
     CrateId,
 };
 use chalk_ir::{
@@ -1965,9 +1965,7 @@ pub enum CallableDefId {
     StructId(StructId),
     EnumVariantId(EnumVariantId),
 }
-
-impl InternValueTrivial for CallableDefId {}
-
+impl_intern_value_trivial!(CallableDefId);
 impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
 impl From<CallableDefId> for ModuleDefId {
     fn from(def: CallableDefId) -> ModuleDefId {
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 929c8b3c09..4b3b7ff4c4 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -26,7 +26,7 @@ pub trait HasSource {
     ///
     /// The current some implementations can return `InFile` instead of `Option<InFile>`.
     /// But we made this method `Option` to support rlib in the future
-    /// by <https://github.com/rust-lang/rust-analyzer/issues/6913>
+    /// by https://github.com/rust-lang/rust-analyzer/issues/6913
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
 }
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index df17a35734..13dba8805a 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -26,19 +26,19 @@
 //!
 //! The actual algorithm to resolve syntax to def is curious in two aspects:
 //!
-//! * It is recursive
-//! * It uses the inverse algorithm (what is the syntax for this def?)
+//!     * It is recursive
+//!     * It uses the inverse algorithm (what is the syntax for this def?)
 //!
 //! Specifically, the algorithm goes like this:
 //!
-//! 1. Find the syntactic container for the syntax. For example, field's
-//!    container is the struct, and structs container is a module.
-//! 2. Recursively get the def corresponding to container.
-//! 3. Ask the container def for all child defs. These child defs contain
-//!    the answer and answer's siblings.
-//! 4. For each child def, ask for it's source.
-//! 5. The child def whose source is the syntax node we've started with
-//!    is the answer.
+//!     1. Find the syntactic container for the syntax. For example, field's
+//!        container is the struct, and structs container is a module.
+//!     2. Recursively get the def corresponding to container.
+//!     3. Ask the container def for all child defs. These child defs contain
+//!        the answer and answer's siblings.
+//!     4. For each child def, ask for it's source.
+//!     5. The child def whose source is the syntax node we've started with
+//!        is the answer.
 //!
 //! It's interesting that both Roslyn and Kotlin contain very similar code
 //! shape.
diff --git a/crates/ide-completion/src/completions/env_vars.rs b/crates/ide-completion/src/completions/env_vars.rs
index 23d93d3b74..4005753773 100644
--- a/crates/ide-completion/src/completions/env_vars.rs
+++ b/crates/ide-completion/src/completions/env_vars.rs
@@ -1,5 +1,4 @@
-//! Completes environment variables defined by Cargo
-//! (<https://doc.rust-lang.org/cargo/reference/environment-variables.html>)
+//! Completes environment variables defined by Cargo (https://doc.rust-lang.org/cargo/reference/environment-variables.html)
 use hir::MacroFileIdExt;
 use ide_db::syntax_helpers::node_ext::macro_call_for_string_token;
 use syntax::{
diff --git a/crates/ide-db/src/famous_defs.rs b/crates/ide-db/src/famous_defs.rs
index 51ac0b7191..e445e9fb68 100644
--- a/crates/ide-db/src/famous_defs.rs
+++ b/crates/ide-db/src/famous_defs.rs
@@ -15,7 +15,7 @@ use crate::RootDatabase;
 /// you'd want to include minicore (see `test_utils::MiniCore`) declaration at
 /// the start of your tests:
 ///
-/// ```text
+/// ```
 /// //- minicore: iterator, ord, derive
 /// ```
 pub struct FamousDefs<'a, 'b>(pub &'a Semantics<'b, RootDatabase>, pub Crate);
diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs
index b4486d1502..62104fb7dc 100644
--- a/crates/ide-db/src/prime_caches.rs
+++ b/crates/ide-db/src/prime_caches.rs
@@ -11,9 +11,9 @@ use hir::db::DefDatabase;
 use crate::{
     base_db::{
         salsa::{Database, ParallelDatabase, Snapshot},
-        Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt,
+        Cancelled, CrateId, SourceDatabase, SourceDatabaseExt,
     },
-    FxHashSet, FxIndexMap, RootDatabase,
+    FxIndexMap, RootDatabase,
 };
 
 /// We're indexing many crates.
@@ -36,19 +36,10 @@ pub fn parallel_prime_caches(
 
     let graph = db.crate_graph();
     let mut crates_to_prime = {
-        let crate_ids = compute_crates_to_prime(db, &graph);
-
         let mut builder = topologic_sort::TopologicalSortIter::builder();
 
-        for &crate_id in &crate_ids {
-            let crate_data = &graph[crate_id];
-            let dependencies = crate_data
-                .dependencies
-                .iter()
-                .map(|d| d.crate_id)
-                .filter(|i| crate_ids.contains(i));
-
-            builder.add(crate_id, dependencies);
+        for crate_id in graph.iter() {
+            builder.add(crate_id, graph[crate_id].dependencies.iter().map(|d| d.crate_id));
         }
 
         builder.build()
@@ -62,13 +53,20 @@ pub fn parallel_prime_caches(
     let (work_sender, progress_receiver) = {
         let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
         let (work_sender, work_receiver) = crossbeam_channel::unbounded();
+        let graph = graph.clone();
         let prime_caches_worker = move |db: Snapshot<RootDatabase>| {
             while let Ok((crate_id, crate_name)) = work_receiver.recv() {
                 progress_sender
                     .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
 
-                // This also computes the DefMap
-                db.import_map(crate_id);
+                let file_id = graph[crate_id].root_file_id;
+                let root_id = db.file_source_root(file_id);
+                if db.source_root(root_id).is_library {
+                    db.crate_def_map(crate_id);
+                } else {
+                    // This also computes the DefMap
+                    db.import_map(crate_id);
+                }
 
                 progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?;
             }
@@ -76,13 +74,13 @@ pub fn parallel_prime_caches(
             Ok::<_, crossbeam_channel::SendError<_>>(())
         };
 
-        for _ in 0..num_worker_threads {
+        for id in 0..num_worker_threads {
             let worker = prime_caches_worker.clone();
             let db = db.snapshot();
 
             stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
                 .allow_leak(true)
-                .name("PrimeCaches".to_owned())
+                .name(format!("PrimeCaches#{id}"))
                 .spawn(move || Cancelled::catch(|| worker(db)))
                 .expect("failed to spawn thread");
         }
@@ -96,7 +94,7 @@ pub fn parallel_prime_caches(
     // an index map is used to preserve ordering so we can sort the progress report in order of
     // "longest crate to index" first
     let mut crates_currently_indexing =
-        FxIndexMap::with_capacity_and_hasher(num_worker_threads as _, Default::default());
+        FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
 
     while crates_done < crates_total {
         db.unwind_if_cancelled();
@@ -144,19 +142,3 @@ pub fn parallel_prime_caches(
         cb(progress);
     }
 }
-
-fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet<CrateId> {
-    // We're only interested in the workspace crates and the `ImportMap`s of their direct
-    // dependencies, though in practice the latter also compute the `DefMap`s.
-    // We don't prime transitive dependencies because they're generally not visible in
-    // the current workspace.
-    graph
-        .iter()
-        .filter(|&id| {
-            let file_id = graph[id].root_file_id;
-            let root_id = db.file_source_root(file_id);
-            !db.source_root(root_id).is_library
-        })
-        .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id))
-        .collect()
-}
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index 2930190cb3..b342e35488 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -13,7 +13,7 @@
 //! Code in this module also contains inline tests, which start with
 //! `// test name-of-the-test` comment and look like this:
 //!
-//! ```text
+//! ```
 //! // test function_with_zero_parameters
 //! // fn foo() {}
 //! ```
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index ef890fa3e6..e8504979be 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -2531,7 +2531,6 @@ macro_rules! _impl_for_config_data {
                 #[allow(non_snake_case)]
                 $vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty {
                     let mut par: Option<SourceRootId> = source_root;
-                    let mut traversals = 0;
                     while let Some(source_root_id) = par {
                         par = self.source_root_parent_map.get(&source_root_id).copied();
                         if let Some((config, _)) = self.ratoml_files.get(&source_root_id) {
@@ -2539,14 +2538,6 @@ macro_rules! _impl_for_config_data {
                                 return value;
                             }
                         }
-                        // Prevent infinite loops caused by cycles by giving up when it's
-                        // clear that we must have either visited all source roots or
-                        // encountered a cycle.
-                        traversals += 1;
-                        if traversals >= self.source_root_parent_map.len() {
-                            // i.e. no source root contains the config we're looking for
-                            break;
-                        }
                     }
 
                     if let Some((root_path_ratoml, _)) = self.root_ratoml.as_ref() {
diff --git a/crates/rust-analyzer/src/tracing/hprof.rs b/crates/rust-analyzer/src/tracing/hprof.rs
index 2d1604e70b..978dcd67fa 100644
--- a/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/crates/rust-analyzer/src/tracing/hprof.rs
@@ -1,8 +1,8 @@
 //! Consumer of `tracing` data, which prints a hierarchical profile.
 //!
-//! Based on <https://github.com/davidbarsky/tracing-tree>, but does less, while
+//! Based on https://github.com/davidbarsky/tracing-tree, but does less, while
 //! actually printing timings for spans by default. The code here is vendored from
-//! <https://github.com/matklad/tracing-span-tree>.
+//! https://github.com/matklad/tracing-span-tree.
 //!
 //! Usage:
 //!
diff --git a/crates/salsa/src/interned.rs b/crates/salsa/src/interned.rs
index eef8bcc814..bfa9cc0591 100644
--- a/crates/salsa/src/interned.rs
+++ b/crates/salsa/src/interned.rs
@@ -98,27 +98,26 @@ impl<A: InternValue + Eq + Hash + Debug + Clone, B: InternValue + Eq + Hash + De
     }
 }
 
-pub trait InternValueTrivial
-where
-    Self: Eq + Hash + Debug + Clone,
-{
-}
-
 /// Implement [`InternValue`] trivially, that is without actually mapping at all.
-impl<V: InternValueTrivial> InternValue for V {
-    type Key = Self;
-    #[inline]
-    fn into_key(&self) -> Self::Key {
-        self.clone()
-    }
-    #[inline]
-    fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
-        f(self)
-    }
+#[macro_export]
+macro_rules! impl_intern_value_trivial {
+    ($($ty:ty),*) => {
+        $(
+            impl $crate::InternValue for $ty {
+                type Key = $ty;
+                #[inline]
+                fn into_key(&self) -> Self::Key {
+                    self.clone()
+                }
+                #[inline]
+                fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
+                    f(self)
+                }
+            }
+        )*
+    };
 }
-
-impl InternValueTrivial for String {}
-
+impl_intern_value_trivial!(String);
 #[derive(Debug)]
 struct Slot<V> {
     /// DatabaseKeyIndex for this slot.
diff --git a/crates/salsa/src/lib.rs b/crates/salsa/src/lib.rs
index e11e6e2e19..9219a55634 100644
--- a/crates/salsa/src/lib.rs
+++ b/crates/salsa/src/lib.rs
@@ -40,7 +40,7 @@ use std::panic::{self, UnwindSafe};
 
 pub use crate::durability::Durability;
 pub use crate::intern_id::InternId;
-pub use crate::interned::{InternKey, InternValue, InternValueTrivial};
+pub use crate::interned::{InternKey, InternValue};
 pub use crate::runtime::Runtime;
 pub use crate::runtime::RuntimeId;
 pub use crate::storage::Storage;
@@ -284,7 +284,7 @@ pub trait ParallelDatabase: Database + Send {
     /// series of queries in parallel and arranging the results. Using
     /// this method for that purpose ensures that those queries will
     /// see a consistent view of the database (it is also advisable
-    /// for those queries to use the [`Database::unwind_if_cancelled`]
+    /// for those queries to use the [`Runtime::unwind_if_cancelled`]
     /// method to check for cancellation).
     ///
     /// # Panics
diff --git a/crates/span/src/hygiene.rs b/crates/span/src/hygiene.rs
index e8c558355c..e4b0a26a6f 100644
--- a/crates/span/src/hygiene.rs
+++ b/crates/span/src/hygiene.rs
@@ -4,7 +4,7 @@
 //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2
 //! (March 1, 2012): 181–216, <https://doi.org/10.1017/S0956796812000093>.
 //!
-//! Also see <https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies>
+//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies
 //!
 //! # The Expansion Order Hierarchy
 //!
diff --git a/crates/stdx/src/anymap.rs b/crates/stdx/src/anymap.rs
index d189b56a46..d47b3d1647 100644
--- a/crates/stdx/src/anymap.rs
+++ b/crates/stdx/src/anymap.rs
@@ -1,6 +1,6 @@
-//! This file is a port of only the necessary features from <https://github.com/chris-morgan/anymap> version 1.0.0-beta.2 for use within rust-analyzer.
+//! This file is a port of only the necessary features from https://github.com/chris-morgan/anymap version 1.0.0-beta.2 for use within rust-analyzer.
 //! Copyright © 2014–2022 Chris Morgan.
-//! COPYING: <https://github.com/chris-morgan/anymap/blob/master/COPYING>
+//! COPYING: https://github.com/chris-morgan/anymap/blob/master/COPYING
 //! Note that the license is changed from Blue Oak Model 1.0.0 or MIT or Apache-2.0 to MIT OR Apache-2.0
 //!
 //! This implementation provides a safe and convenient store for one value of each type.
diff --git a/crates/toolchain/src/lib.rs b/crates/toolchain/src/lib.rs
index 2591ed1691..b577723612 100644
--- a/crates/toolchain/src/lib.rs
+++ b/crates/toolchain/src/lib.rs
@@ -23,7 +23,7 @@ impl Tool {
     ///
     /// The current implementation checks three places for an executable to use:
     /// 1) `$CARGO_HOME/bin/<executable_name>`
-    ///      where $CARGO_HOME defaults to ~/.cargo (see <https://doc.rust-lang.org/cargo/guide/cargo-home.html>)
+    ///      where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html)
     ///      example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset.
     ///      It seems that this is a reasonable place to try for cargo, rustc, and rustup
     /// 2) Appropriate environment variable (erroring if this is set but not a usable executable)
@@ -45,7 +45,7 @@ impl Tool {
     ///      example: for cargo, this tries all paths in $PATH with appended `cargo`, returning the
     ///      first that exists
     /// 3) `$CARGO_HOME/bin/<executable_name>`
-    ///      where $CARGO_HOME defaults to ~/.cargo (see <https://doc.rust-lang.org/cargo/guide/cargo-home.html>)
+    ///      where $CARGO_HOME defaults to ~/.cargo (see https://doc.rust-lang.org/cargo/guide/cargo-home.html)
     ///      example: for cargo, this tries $CARGO_HOME/bin/cargo, or ~/.cargo/bin/cargo if $CARGO_HOME is unset.
     ///      It seems that this is a reasonable place to try for cargo, rustc, and rustup
     /// 4) If all else fails, we just try to use the executable name directly
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index c14f7a1175..c28a919231 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -1,7 +1,8 @@
 import * as vscode from "vscode";
+import * as toolchain from "./toolchain";
 import type { Config } from "./config";
 import { log } from "./util";
-import { expectNotUndefined, unwrapUndefinable } from "./undefinable";
+import { unwrapUndefinable } from "./undefinable";
 
 // This ends up as the `type` key in tasks.json. RLS also uses `cargo` and
 // our configuration should be compatible with it so use the same key.
@@ -141,16 +142,14 @@ async function cargoToExecution(
     if (definition.type === TASK_TYPE) {
         // Check whether we must use a user-defined substitute for cargo.
         // Split on spaces to allow overrides like "wrapper cargo".
-        const cargoCommand = definition.overrideCargo?.split(" ") ?? [definition.command];
+        const cargoPath = await toolchain.cargoPath();
+        const cargoCommand = definition.overrideCargo?.split(" ") ?? [cargoPath];
 
-        const definitionArgs = expectNotUndefined(
-            definition.args,
-            "args were not provided via runnables; this is a bug.",
-        );
-        const args = [...cargoCommand.slice(1), ...definitionArgs];
-        const processName = unwrapUndefinable(cargoCommand[0]);
+        const args = [definition.command].concat(definition.args ?? []);
+        const fullCommand = [...cargoCommand, ...args];
+        const processName = unwrapUndefinable(fullCommand[0]);
 
-        return new vscode.ProcessExecution(processName, args, {
+        return new vscode.ProcessExecution(processName, fullCommand.slice(1), {
             cwd: definition.cwd,
             env: definition.env,
         });


Test patch:
diff --git a/crates/test-utils/src/fixture.rs b/crates/test-utils/src/fixture.rs
index 54c9db7aac..9871fd2cf0 100644
--- a/crates/test-utils/src/fixture.rs
+++ b/crates/test-utils/src/fixture.rs
@@ -143,14 +143,14 @@ pub struct FixtureWithProjectMeta {
     /// Specifies LLVM data layout to be used.
     ///
     /// You probably don't want to manually specify this. See LLVM manual for the
-    /// syntax, if you must: <https://llvm.org/docs/LangRef.html#data-layout>
+    /// syntax, if you must: https://llvm.org/docs/LangRef.html#data-layout
     pub target_data_layout: String,
 }
 
 impl FixtureWithProjectMeta {
     /// Parses text which looks like this:
     ///
-    ///  ```text
+    ///  ```not_rust
     ///  //- some meta
     ///  line 1
     ///  line 2
@@ -159,7 +159,7 @@ impl FixtureWithProjectMeta {
     ///
     /// Fixture can also start with a proc_macros and minicore declaration (in that order):
     ///
-    /// ```text
+    /// ```
     /// //- toolchain: nightly
     /// //- proc_macros: identity
     /// //- minicore: sized
diff --git a/crates/test-utils/src/lib.rs b/crates/test-utils/src/lib.rs
index 43f62d0d1e..b750107803 100644
--- a/crates/test-utils/src/lib.rs
+++ b/crates/test-utils/src/lib.rs
@@ -224,7 +224,7 @@ pub fn add_cursor(text: &str, offset: TextSize) -> String {
 /// Annotations point to the last line that actually was long enough for the
 /// range, not counting annotations themselves. So overlapping annotations are
 /// possible:
-/// ```text
+/// ```no_run
 /// // stuff        other stuff
 /// // ^^ 'st'
 /// // ^^^^^ 'stuff'