Repository: rust-lang/rust-analyzer
Pull request #17406 (2024-06-12 09:48:21)

internal: Don't unnecessarily clone ModPaths out of interning wrappers


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 57d43dad3f..efb313cd3c 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -512,7 +512,6 @@ dependencies = [
  "hir-def",
  "hir-expand",
  "hir-ty",
- "intern",
  "itertools",
  "once_cell",
  "rustc-hash",
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index c48d16d053..cbb5ca887f 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -48,30 +48,21 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
     let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false };
     if let DefWithBodyId::FunctionId(it) = owner {
         p.buf.push('(');
-        let function_data = &db.function_data(it);
-        let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type);
+        let params = &db.function_data(it).params;
+        let mut params = params.iter();
         if let Some(self_param) = body.self_param {
             p.print_binding(self_param);
-            p.buf.push_str(": ");
+            p.buf.push(':');
             if let Some(ty) = params.next() {
                 p.print_type_ref(ty);
-                p.buf.push_str(", ");
             }
         }
         body.params.iter().zip(params).for_each(|(&param, ty)| {
             p.print_pat(param);
-            p.buf.push_str(": ");
+            p.buf.push(':');
             p.print_type_ref(ty);
-            p.buf.push_str(", ");
         });
-        // remove the last ", " in param list
-        if body.params.len() > 0 {
-            p.buf.truncate(p.buf.len() - 2);
-        }
         p.buf.push(')');
-        // return type
-        p.buf.push_str(" -> ");
-        p.print_type_ref(ret_type);
         p.buf.push(' ');
     }
     p.print_expr(body.body_expr);
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index ded2fd243b..4338163672 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -628,7 +628,7 @@ impl<'a> AssocItemCollector<'a> {
             'attrs: for attr in &*attrs {
                 let ast_id =
                     AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast());
-                let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id };
+                let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
 
                 match self.def_map.resolve_attr_macro(
                     self.db,
diff --git a/crates/hir-def/src/lib.rs b/crates/hir-def/src/lib.rs
index 447c67f125..2a8fbe3d2c 100644
--- a/crates/hir-def/src/lib.rs
+++ b/crates/hir-def/src/lib.rs
@@ -56,6 +56,7 @@ pub mod find_path;
 pub mod import_map;
 pub mod visibility;
 
+use intern::Interned;
 pub use rustc_abi as layout;
 use triomphe::Arc;
 
@@ -90,7 +91,7 @@ use hir_expand::{
 use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
-use span::{AstIdNode, Edition, FileAstId, SyntaxContextId};
+use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId};
 use stdx::impl_from;
 use syntax::{ast, AstNode};
 
@@ -958,14 +959,15 @@ impl GenericDefId {
         match self {
             GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None),
             GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
             GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
-            GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
-            GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None),
+            // We won't be using this ID anyway
+            GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None),
         }
     }
 
@@ -1407,7 +1409,8 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 
         macro_call_as_call_id_with_eager(
             db,
-            &AstIdWithPath::new(ast_id.file_id, ast_id.value, path),
+            ast_id,
+            &path,
             call_site.ctx,
             expands_to,
             krate,
@@ -1421,11 +1424,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> {
 #[derive(Clone, Debug, Eq, PartialEq)]
 struct AstIdWithPath<T: AstIdNode> {
     ast_id: AstId<T>,
-    path: path::ModPath,
+    path: Interned<path::ModPath>,
 }
 
 impl<T: AstIdNode> AstIdWithPath<T> {
-    fn new(file_id: HirFileId, ast_id: FileAstId<T>, path: path::ModPath) -> AstIdWithPath<T> {
+    fn new(
+        file_id: HirFileId,
+        ast_id: FileAstId<T>,
+        path: Interned<path::ModPath>,
+    ) -> AstIdWithPath<T> {
         AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path }
     }
 }
@@ -1438,27 +1445,37 @@ fn macro_call_as_call_id(
     krate: CrateId,
     resolver: impl Fn(&path::ModPath) -> Option<MacroDefId> + Copy,
 ) -> Result<Option<MacroCallId>, UnresolvedMacro> {
-    macro_call_as_call_id_with_eager(db, call, call_site, expand_to, krate, resolver, resolver)
-        .map(|res| res.value)
+    macro_call_as_call_id_with_eager(
+        db,
+        call.ast_id,
+        &call.path,
+        call_site,
+        expand_to,
+        krate,
+        resolver,
+        resolver,
+    )
+    .map(|res| res.value)
 }
 
 fn macro_call_as_call_id_with_eager(
     db: &dyn ExpandDatabase,
-    call: &AstIdWithPath<ast::MacroCall>,
+    ast_id: AstId<ast::MacroCall>,
+    path: &path::ModPath,
     call_site: SyntaxContextId,
     expand_to: ExpandTo,
     krate: CrateId,
     resolver: impl FnOnce(&path::ModPath) -> Option<MacroDefId>,
     eager_resolver: impl Fn(&path::ModPath) -> Option<MacroDefId>,
 ) -> Result<ExpandResult<Option<MacroCallId>>, UnresolvedMacro> {
-    let def = resolver(&call.path).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
+    let def = resolver(path).ok_or_else(|| UnresolvedMacro { path: path.clone() })?;
 
     let res = match def.kind {
         MacroDefKind::BuiltInEager(..) => expand_eager_macro_input(
             db,
             krate,
-            &call.ast_id.to_node(db),
-            call.ast_id,
+            &ast_id.to_node(db),
+            ast_id,
             def,
             call_site,
             &|path| eager_resolver(path).filter(MacroDefId::is_fn_like),
@@ -1467,12 +1484,12 @@ fn macro_call_as_call_id_with_eager(
             value: Some(def.make_call(
                 db,
                 krate,
-                MacroCallKind::FnLike { ast_id: call.ast_id, expand_to, eager: None },
+                MacroCallKind::FnLike { ast_id, expand_to, eager: None },
                 call_site,
             )),
             err: None,
         },
-        _ => return Err(UnresolvedMacro { path: call.path.clone() }),
+        _ => return Err(UnresolvedMacro { path: path.clone() }),
     };
     Ok(res)
 }
diff --git a/crates/hir-def/src/nameres/attr_resolution.rs b/crates/hir-def/src/nameres/attr_resolution.rs
index 460f1f1407..f842027d64 100644
--- a/crates/hir-def/src/nameres/attr_resolution.rs
+++ b/crates/hir-def/src/nameres/attr_resolution.rs
@@ -59,7 +59,7 @@ impl DefMap {
                     return Ok(ResolvedAttr::Other);
                 }
             }
-            None => return Err(UnresolvedMacro { path: ast_id.path }),
+            None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }),
         };
 
         Ok(ResolvedAttr::Macro(attr_macro_as_call_id(
@@ -142,7 +142,7 @@ pub(super) fn derive_macro_as_call_id(
 ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> {
     let (macro_id, def_id) = resolver(&item_attr.path)
         .filter(|(_, def_id)| def_id.is_derive())
-        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
+        .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?;
     let call_id = def_id.make_call(
         db.upcast(),
         krate,
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index b6e87d3d38..216fbeaa40 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -17,11 +17,12 @@ use hir_expand::{
     proc_macro::CustomProcMacroExpander,
     ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
 };
+use intern::Interned;
 use itertools::{izip, Itertools};
 use la_arena::Idx;
 use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
-use span::{Edition, ErasedFileAstId, FileAstId, SyntaxContextId};
+use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId};
 use syntax::ast;
 use triomphe::Arc;
 
@@ -75,23 +76,36 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI
 
     let proc_macros = if krate.is_proc_macro {
         match db.proc_macros().get(&def_map.krate) {
-            Some(Ok(proc_macros)) => Ok(proc_macros
-                .iter()
-                .enumerate()
-                .map(|(idx, it)| {
-                    let name = Name::new_text_dont_use(it.name.clone());
-                    (
-                        name,
-                        if it.disabled {
-                            CustomProcMacroExpander::disabled()
-                        } else {
-                            CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new(
-                                idx as u32,
-                            ))
-                        },
-                    )
-                })
-                .collect()),
+            Some(Ok(proc_macros)) => {
+                Ok(proc_macros
+                    .iter()
+                    .enumerate()
+                    .map(|(idx, it)| {
+                        // FIXME: a hacky way to create a Name from string.
+                        let name = tt::Ident {
+                            text: it.name.clone(),
+                            span: Span {
+                                range: syntax::TextRange::empty(syntax::TextSize::new(0)),
+                                anchor: span::SpanAnchor {
+                                    file_id: FileId::BOGUS,
+                                    ast_id: span::ROOT_ERASED_FILE_AST_ID,
+                                },
+                                ctx: SyntaxContextId::ROOT,
+                            },
+                        };
+                        (
+                            name.as_name(),
+                            if it.disabled {
+                                CustomProcMacroExpander::disabled()
+                            } else {
+                                CustomProcMacroExpander::new(
+                                    hir_expand::proc_macro::ProcMacroId::new(idx as u32),
+                                )
+                            },
+                        )
+                    })
+                    .collect())
+            }
             Some(Err(e)) => Err(e.clone().into_boxed_str()),
             None => Err("No proc-macros present for crate".to_owned().into_boxed_str()),
         }
@@ -1287,7 +1301,11 @@ impl DefCollector<'_> {
                                 let call_id = call_id();
                                 let mut len = 0;
                                 for (idx, (path, call_site)) in derive_macros.enumerate() {
-                                    let ast_id = AstIdWithPath::new(file_id, ast_id.value, path);
+                                    let ast_id = AstIdWithPath::new(
+                                        file_id,
+                                        ast_id.value,
+                                        Interned::new(path),
+                                    );
                                     self.unresolved_macros.push(MacroDirective {
                                         module_id: directive.module_id,
                                         depth: directive.depth + 1,
@@ -1460,7 +1478,7 @@ impl DefCollector<'_> {
                             derive_index: *derive_pos as u32,
                             derive_macro_id: *derive_macro_id,
                         },
-                        ast_id.path.clone(),
+                        ast_id.path.as_ref().clone(),
                     ));
                 }
                 // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them
@@ -2095,7 +2113,7 @@ impl ModCollector<'_, '_> {
             let ast_id = AstIdWithPath::new(
                 self.file_id(),
                 mod_item.ast_id(self.item_tree),
-                attr.path.as_ref().clone(),
+                attr.path.clone(),
             );
             self.def_collector.unresolved_macros.push(MacroDirective {
                 module_id: self.module_id,
@@ -2141,7 +2159,19 @@ impl ModCollector<'_, '_> {
             let name;
             let name = match attrs.by_key("rustc_builtin_macro").string_value() {
                 Some(it) => {
-                    name = Name::new_text_dont_use(it.into());
+                    // FIXME: a hacky way to create a Name from string.
+                    name = tt::Ident {
+                        text: it.into(),
+                        span: Span {
+                            range: syntax::TextRange::empty(syntax::TextSize::new(0)),
+                            anchor: span::SpanAnchor {
+                                file_id: FileId::BOGUS,
+                                ast_id: span::ROOT_ERASED_FILE_AST_ID,
+                            },
+                            ctx: SyntaxContextId::ROOT,
+                        },
+                    }
+                    .as_name();
                     &name
                 }
                 None => {
@@ -2277,7 +2307,7 @@ impl ModCollector<'_, '_> {
         &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall,
         container: ItemContainerId,
     ) {
-        let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path));
+        let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone());
         let db = self.def_collector.db;
 
         // FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define
@@ -2287,7 +2317,8 @@ impl ModCollector<'_, '_> {
         // Case 1: try to resolve macro calls with single-segment name and expand macro_rules
         if let Ok(res) = macro_call_as_call_id_with_eager(
             db.upcast(),
-            &ast_id,
+            ast_id.ast_id,
+            &ast_id.path,
             ctxt,
             expand_to,
             self.def_collector.def_map.krate,
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index ad25a1168c..30042ca78a 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -146,11 +146,13 @@ pub fn expand_speculative(
     token_to_map: SyntaxToken,
 ) -> Option<(SyntaxNode, SyntaxToken)> {
     let loc = db.lookup_intern_macro_call(actual_macro_call);
-    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
 
-    let span_map = RealSpanMap::absolute(span.anchor.file_id);
+    // FIXME: This BOGUS here is dangerous once the proc-macro server can call back into the database!
+    let span_map = RealSpanMap::absolute(FileId::BOGUS);
     let span_map = SpanMapRef::RealSpanMap(&span_map);
 
+    let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind);
+
     // Build the subtree and token mapping for the speculative args
     let (mut tt, undo_info) = match loc.kind {
         MacroCallKind::FnLike { .. } => (
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index f83e266744..9ec2a83162 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -4,10 +4,7 @@
 use mbe::DocCommentDesugarMode;
 use rustc_hash::{FxHashMap, FxHashSet};
 use smallvec::SmallVec;
-use span::{
-    ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, FIXUP_ERASED_FILE_AST_ID_MARKER,
-    ROOT_ERASED_FILE_AST_ID,
-};
+use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER};
 use stdx::never;
 use syntax::{
     ast::{self, AstNode, HasLoopBody},
@@ -310,13 +307,8 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo)
         tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID
             || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID
     ) {
-        let span = |file_id| Span {
-            range: TextRange::empty(TextSize::new(0)),
-            anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
-            ctx: SyntaxContextId::ROOT,
-        };
-        tt.delimiter.open = span(tt.delimiter.open.anchor.file_id);
-        tt.delimiter.close = span(tt.delimiter.close.anchor.file_id);
+        tt.delimiter.close = Span::DUMMY;
+        tt.delimiter.open = Span::DUMMY;
     }
     reverse_fixups_(tt, undo_info);
 }
diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs
index 8f1e32321e..a31a111c91 100644
--- a/crates/hir-expand/src/quote.rs
+++ b/crates/hir-expand/src/quote.rs
@@ -231,7 +231,7 @@ mod tests {
 
     const DUMMY: tt::Span = tt::Span {
         range: TextRange::empty(TextSize::new(0)),
-        anchor: SpanAnchor { file_id: FileId::from_raw(0xe4e4e), ast_id: ROOT_ERASED_FILE_AST_ID },
+        anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID },
         ctx: SyntaxContextId::ROOT,
     };
 
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index ff78fe0d54..f035dd11e1 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -4,7 +4,7 @@
 
 use std::{
     fmt::{self, Debug},
-    mem::{self, size_of},
+    mem::size_of,
 };
 
 use base_db::CrateId;
@@ -74,8 +74,6 @@ pub struct HirFormatter<'a> {
     /// When rendering something that has a concept of "children" (like fields in a struct), this limits
     /// how many should be rendered.
     pub entity_limit: Option<usize>,
-    /// When rendering functions, whether to show the constraint from the container
-    show_container_bounds: bool,
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
@@ -103,7 +101,6 @@ pub trait HirDisplay {
         omit_verbose_types: bool,
         display_target: DisplayTarget,
         closure_style: ClosureStyle,
-        show_container_bounds: bool,
     ) -> HirDisplayWrapper<'a, Self>
     where
         Self: Sized,
@@ -120,7 +117,6 @@ pub trait HirDisplay {
             omit_verbose_types,
             display_target,
             closure_style,
-            show_container_bounds,
         }
     }
 
@@ -138,7 +134,6 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
-            show_container_bounds: false,
         }
     }
 
@@ -160,7 +155,6 @@ pub trait HirDisplay {
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
-            show_container_bounds: false,
         }
     }
 
@@ -182,7 +176,6 @@ pub trait HirDisplay {
             omit_verbose_types: true,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Diagnostics,
-            show_container_bounds: false,
         }
     }
 
@@ -205,7 +198,6 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
-            show_container_bounds: false,
         }) {
             Ok(()) => {}
             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -227,29 +219,6 @@ pub trait HirDisplay {
             omit_verbose_types: false,
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::Test,
-            show_container_bounds: false,
-        }
-    }
-
-    /// Returns a String representation of `self` that shows the constraint from
-    /// the container for functions
-    fn display_with_container_bounds<'a>(
-        &'a self,
-        db: &'a dyn HirDatabase,
-        show_container_bounds: bool,
-    ) -> HirDisplayWrapper<'a, Self>
-    where
-        Self: Sized,
-    {
-        HirDisplayWrapper {
-            db,
-            t: self,
-            max_size: None,
-            limited_size: None,
-            omit_verbose_types: false,
-            closure_style: ClosureStyle::ImplFn,
-            display_target: DisplayTarget::Diagnostics,
-            show_container_bounds,
         }
     }
 }
@@ -308,10 +277,6 @@ impl HirFormatter<'_> {
     pub fn omit_verbose_types(&self) -> bool {
         self.omit_verbose_types
     }
-
-    pub fn show_container_bounds(&self) -> bool {
-        self.show_container_bounds
-    }
 }
 
 #[derive(Clone, Copy)]
@@ -371,7 +336,6 @@ pub struct HirDisplayWrapper<'a, T> {
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
-    show_container_bounds: bool,
 }
 
 #[derive(Debug, PartialEq, Eq, Clone, Copy)]
@@ -401,7 +365,6 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
             omit_verbose_types: self.omit_verbose_types,
             display_target: self.display_target,
             closure_style: self.closure_style,
-            show_container_bounds: self.show_container_bounds,
         })
     }
 
@@ -460,7 +423,7 @@ impl HirDisplay for ProjectionTy {
         let proj_params_count =
             self.substitution.len(Interner) - trait_ref.substitution.len(Interner);
         let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count];
-        hir_fmt_generics(f, proj_params, None, None)
+        hir_fmt_generics(f, proj_params, None)
     }
 }
 
@@ -505,7 +468,6 @@ impl HirDisplay for Const {
                         f,
                         parameters.as_slice(Interner),
                         c.generic_def(f.db.upcast()),
-                        None,
                     )?;
                     Ok(())
                 }
@@ -1005,11 +967,11 @@ impl HirDisplay for Ty {
                         let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params);
 
                         write!(f, "<")?;
-                        hir_fmt_generic_arguments(f, parent_params, None)?;
+                        hir_fmt_generic_arguments(f, parent_params)?;
                         if !parent_params.is_empty() && !fn_params.is_empty() {
                             write!(f, ", ")?;
                         }
-                        hir_fmt_generic_arguments(f, fn_params, None)?;
+                        hir_fmt_generic_arguments(f, fn_params)?;
                         write!(f, ">")?;
                     }
                 }
@@ -1054,7 +1016,7 @@ impl HirDisplay for Ty {
 
                 let generic_def = self.as_generic_def(db);
 
-                hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?;
+                hir_fmt_generics(f, parameters.as_slice(Interner), generic_def)?;
             }
             TyKind::AssociatedType(assoc_type_id, parameters) => {
                 let type_alias = from_assoc_type_id(*assoc_type_id);
@@ -1077,7 +1039,7 @@ impl HirDisplay for Ty {
                     f.end_location_link();
                     // Note that the generic args for the associated type come before those for the
                     // trait (including the self type).
-                    hir_fmt_generics(f, parameters.as_slice(Interner), None, None)
+                    hir_fmt_generics(f, parameters.as_slice(Interner), None)
                 } else {
                     let projection_ty = ProjectionTy {
                         associated_ty_id: to_assoc_type_id(type_alias),
@@ -1179,7 +1141,7 @@ impl HirDisplay for Ty {
                     }
                     ClosureStyle::ClosureWithSubst => {
                         write!(f, "{{closure#{:?}}}", id.0.as_u32())?;
-                        return hir_fmt_generics(f, substs.as_slice(Interner), None, None);
+                        return hir_fmt_generics(f, substs.as_slice(Interner), None);
                     }
                     _ => (),
                 }
@@ -1367,7 +1329,6 @@ fn hir_fmt_generics(
     f: &mut HirFormatter<'_>,
     parameters: &[GenericArg],
     generic_def: Option<hir_def::GenericDefId>,
-    self_: Option<&Ty>,
 ) -> Result<(), HirDisplayError> {
     if parameters.is_empty() {
         return Ok(());
@@ -1387,7 +1348,7 @@ fn hir_fmt_generics(
         });
     if !parameters_to_write.is_empty() && !only_err_lifetimes {
         write!(f, "<")?;
-        hir_fmt_generic_arguments(f, parameters_to_write, self_)?;
+        hir_fmt_generic_arguments(f, parameters_to_write)?;
         write!(f, ">")?;
     }
 
@@ -1449,7 +1410,6 @@ fn generic_args_sans_defaults<'ga>(
 fn hir_fmt_generic_arguments(
     f: &mut HirFormatter<'_>,
     parameters: &[GenericArg],
-    self_: Option<&Ty>,
 ) -> Result<(), HirDisplayError> {
     let mut first = true;
     let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some());
@@ -1471,13 +1431,11 @@ fn hir_fmt_generic_arguments(
             continue;
         }
 
-        if !mem::take(&mut first) {
+        if !first {
             write!(f, ", ")?;
         }
-        match self_ {
-            self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?,
-            _ => generic_arg.hir_fmt(f)?,
-        }
+        first = false;
+        generic_arg.hir_fmt(f)?;
     }
     Ok(())
 }
@@ -1600,16 +1558,12 @@ fn write_bounds_like_dyn_trait(
                 write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
                 f.end_location_link();
                 if is_fn_trait {
-                    if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) {
+                    if let [_self, params @ ..] = trait_ref.substitution.as_slice(Interner) {
                         if let Some(args) =
                             params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple())
                         {
                             write!(f, "(")?;
-                            hir_fmt_generic_arguments(
-                                f,
-                                args.as_slice(Interner),
-                                self_.ty(Interner),
-                            )?;
+                            hir_fmt_generic_arguments(f, args.as_slice(Interner))?;
                             write!(f, ")")?;
                         }
                     }
@@ -1619,10 +1573,10 @@ fn write_bounds_like_dyn_trait(
                         Some(trait_.into()),
                         trait_ref.substitution.as_slice(Interner),
                     );
-                    if let [self_, params @ ..] = params {
+                    if let [_self, params @ ..] = params {
                         if !params.is_empty() {
                             write!(f, "<")?;
-                            hir_fmt_generic_arguments(f, params, self_.ty(Interner))?;
+                            hir_fmt_generic_arguments(f, params)?;
                             // there might be assoc type bindings, so we leave the angle brackets open
                             angle_open = true;
                         }
@@ -1680,7 +1634,6 @@ fn write_bounds_like_dyn_trait(
                         hir_fmt_generic_arguments(
                             f,
                             &proj.substitution.as_slice(Interner)[..proj_arg_count],
-                            None,
                         )?;
                         write!(f, ">")?;
                     }
@@ -1737,8 +1690,7 @@ fn fmt_trait_ref(
     f.start_location_link(trait_.into());
     write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?;
     f.end_location_link();
-    let substs = tr.substitution.as_slice(Interner);
-    hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
+    hir_fmt_generics(f, &tr.substitution.as_slice(Interner)[1..], None)
 }
 
 impl HirDisplay for TraitRef {
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index edf26a07a7..6d7ecd1e50 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -27,7 +27,6 @@ cfg.workspace = true
 hir-def.workspace = true
 hir-expand.workspace = true
 hir-ty.workspace = true
-intern.workspace = true
 stdx.workspace = true
 syntax.workspace = true
 tt.workspace = true
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 79069ed66b..c276e87786 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -3,8 +3,7 @@ use either::Either;
 use hir_def::{
     data::adt::{StructKind, VariantData},
     generics::{
-        GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
-        WherePredicateTypeTarget,
+        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
     },
     lang_item::LangItem,
     type_ref::{TypeBound, TypeRef},
@@ -17,12 +16,10 @@ use hir_ty::{
     },
     AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause,
 };
-use intern::Interned;
-use itertools::Itertools;
 
 use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl,
-    Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module,
+    Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module,
     SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias,
     TypeOrConstParam, TypeParam, Union, Variant,
 };
@@ -33,42 +30,12 @@ impl HirDisplay for Function {
         let data = db.function_data(self.id);
         let container = self.as_assoc_item(db).map(|it| it.container(db));
         let mut module = self.module(db);
-
-        // Write container (trait or impl)
-        let container_params = match container {
-            Some(AssocItemContainer::Trait(trait_)) => {
-                let params = f.db.generic_params(trait_.id.into());
-                if f.show_container_bounds() && !params.is_empty() {
-                    write_trait_header(&trait_, f)?;
-                    f.write_char('\n')?;
-                    has_disaplayable_predicates(&params).then_some(params)
-                } else {
-                    None
-                }
-            }
-            Some(AssocItemContainer::Impl(impl_)) => {
-                let params = f.db.generic_params(impl_.id.into());
-                if f.show_container_bounds() && !params.is_empty() {
-                    write_impl_header(&impl_, f)?;
-                    f.write_char('\n')?;
-                    has_disaplayable_predicates(&params).then_some(params)
-                } else {
-                    None
-                }
-            }
-            None => None,
-        };
-
-        // Write signature of the function
-
-        // Block-local impls are "hoisted" to the nearest (non-block) module.
         if let Some(AssocItemContainer::Impl(_)) = container {
+            // Block-local impls are "hoisted" to the nearest (non-block) module.
             module = module.nearest_non_block_module(db);
         }
         let module_id = module.id;
-
         write_visibility(module_id, self.visibility(db), f)?;
-
         if data.has_default_kw() {
             f.write_str("default ")?;
         }
@@ -149,39 +116,10 @@ impl HirDisplay for Function {
             }
         }
 
-        // Write where clauses
-        let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?;
-        if let Some(container_params) = container_params {
-            if !has_written_where {
-                f.write_str("\nwhere")?;
-            }
-            let container_name = match container.unwrap() {
-                AssocItemContainer::Trait(_) => "trait",
-                AssocItemContainer::Impl(_) => "impl",
-            };
-            write!(f, "\n    // Bounds from {container_name}:",)?;
-            write_where_predicates(&container_params, f)?;
-        }
-        Ok(())
-    }
-}
-
-fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-    let db = f.db;
+        write_where_clause(GenericDefId::FunctionId(self.id), f)?;
 
-    f.write_str("impl")?;
-    let def_id = GenericDefId::ImplId(impl_.id);
-    write_generic_params(def_id, f)?;
-
-    if let Some(trait_) = impl_.trait_(db) {
-        let trait_data = db.trait_data(trait_.id);
-        write!(f, " {} for", trait_data.name.display(db.upcast()))?;
+        Ok(())
     }
-
-    f.write_char(' ')?;
-    impl_.self_ty(db).hir_fmt(f)?;
-
-    Ok(())
 }
 
 impl HirDisplay for SelfParam {
@@ -250,7 +188,7 @@ impl HirDisplay for Struct {
             StructKind::Record => {
                 let has_where_clause = write_where_clause(def_id, f)?;
                 if let Some(limit) = f.entity_limit {
-                    write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
+                    display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
                 }
             }
             StructKind::Unit => _ = write_where_clause(def_id, f)?,
@@ -270,7 +208,7 @@ impl HirDisplay for Enum {
 
         let has_where_clause = write_where_clause(def_id, f)?;
         if let Some(limit) = f.entity_limit {
-            write_variants(&self.variants(f.db), has_where_clause, limit, f)?;
+            display_variants(&self.variants(f.db), has_where_clause, limit, f)?;
         }
 
         Ok(())
@@ -287,13 +225,13 @@ impl HirDisplay for Union {
 
         let has_where_clause = write_where_clause(def_id, f)?;
         if let Some(limit) = f.entity_limit {
-            write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
+            display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?;
         }
         Ok(())
     }
 }
 
-fn write_fields(
+fn display_fields(
     fields: &[Field],
     has_where_clause: bool,
     limit: usize,
@@ -304,7 +242,11 @@ fn write_fields(
     let (indent, separator) = if in_line { ("", ' ') } else { ("    ", '\n') };
     f.write_char(if !has_where_clause { ' ' } else { separator })?;
     if count == 0 {
-        f.write_str(if fields.is_empty() { "{}" } else { "{ /* … */ }" })?;
+        if fields.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
     } else {
         f.write_char('{')?;
 
@@ -313,11 +255,14 @@ fn write_fields(
             for field in &fields[..count] {
                 f.write_str(indent)?;
                 field.hir_fmt(f)?;
-                write!(f, ",{separator}")?;
+                f.write_char(',')?;
+                f.write_char(separator)?;
             }
 
             if fields.len() > count {
-                write!(f, "{indent}/* … */{separator}")?;
+                f.write_str(indent)?;
+                f.write_str("/* … */")?;
+                f.write_char(separator)?;
             }
         }
 
@@ -327,7 +272,7 @@ fn write_fields(
     Ok(())
 }
 
-fn write_variants(
+fn display_variants(
     variants: &[Variant],
     has_where_clause: bool,
     limit: usize,
@@ -336,22 +281,30 @@ fn write_variants(
     let count = variants.len().min(limit);
     f.write_char(if !has_where_clause { ' ' } else { '\n' })?;
     if count == 0 {
-        let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" };
-        f.write_str(variants)?;
+        if variants.is_empty() {
+            f.write_str("{}")?;
+        } else {
+            f.write_str("{ /* … */ }")?;
+        }
     } else {
         f.write_str("{\n")?;
         for variant in &variants[..count] {
-            write!(f, "    {}", variant.name(f.db).display(f.db.upcast()))?;
+            f.write_str("    ")?;
+            write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?;
             match variant.kind(f.db) {
                 StructKind::Tuple => {
-                    let fields_str =
-                        if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" };
-                    f.write_str(fields_str)?;
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str("()")?;
+                    } else {
+                        f.write_str("( /* … */ )")?;
+                    }
                 }
                 StructKind::Record => {
-                    let fields_str =
-                        if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" };
-                    f.write_str(fields_str)?;
+                    if variant.fields(f.db).is_empty() {
+                        f.write_str(" {}")?;
+                    } else {
+                        f.write_str(" { /* … */ }")?;
+                    }
                 }
                 StructKind::Unit => {}
             }
@@ -404,7 +357,7 @@ impl HirDisplay for Variant {
             }
             VariantData::Record(_) => {
                 if let Some(limit) = f.entity_limit {
-                    write_fields(&self.fields(f.db), false, limit, true, f)?;
+                    display_fields(&self.fields(f.db), false, limit, true, f)?;
                 }
             }
         }
@@ -601,96 +554,102 @@ fn write_where_clause(
     f: &mut HirFormatter<'_>,
 ) -> Result<bool, HirDisplayError> {
     let params = f.db.generic_params(def);
-    if !has_disaplayable_predicates(&params) {
-        return Ok(false);
-    }
-
-    f.write_str("\nwhere")?;
-    write_where_predicates(&params, f)?;
 
-    Ok(true)
-}
-
-fn has_disaplayable_predicates(params: &Interned<GenericParams>) -> bool {
-    params.where_predicates.iter().any(|pred| {
-        !matches!(
-            pred,
-            WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. }
-            if params.type_or_consts[*id].name().is_none()
-        )
-    })
-}
+    // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
+    let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
+        WherePredicateTypeTarget::TypeRef(_) => false,
+        WherePredicateTypeTarget::TypeOrConstParam(id) => {
+            params.type_or_consts[*id].name().is_none()
+        }
+    };
 
-fn write_where_predicates(
-    params: &Interned<GenericParams>,
-    f: &mut HirFormatter<'_>,
-) -> Result<(), HirDisplayError> {
-    use WherePredicate::*;
+    let has_displayable_predicate = params
+        .where_predicates
+        .iter()
+        .any(|pred| {
+            !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target))
+        });
 
-    // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
-    let is_unnamed_type_target =
-        |params: &Interned<GenericParams>, target: &WherePredicateTypeTarget| {
-            matches!(target,
-                WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none()
-            )
-        };
+    if !has_displayable_predicate {
+        return Ok(false);
+    }
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target {
         WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
-        WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() {
-            Some(name) => write!(f, "{}", name.display(f.db.upcast())),
-            None => f.write_str("{unnamed}"),
-        },
+        WherePredicateTypeTarget::TypeOrConstParam(id) => {
+            match &params.type_or_consts[*id].name() {
+                Some(name) => write!(f, "{}", name.display(f.db.upcast())),
+                None => f.write_str("{unnamed}"),
+            }
+        }
     };
 
-    let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) {
-        (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2,
-        (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2,
-        (
-            ForLifetime { lifetimes: l1, target: t1, .. },
-            ForLifetime { lifetimes: l2, target: t2, .. },
-        ) => l1 == l2 && t1 == t2,
-        _ => false,
-    };
+    f.write_str("\nwhere")?;
 
-    let mut iter = params.where_predicates.iter().peekable();
-    while let Some(pred) = iter.next() {
-        if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) {
-            continue;
-        }
+    for (pred_idx, pred) in params.where_predicates.iter().enumerate() {
+        let prev_pred =
+            if pred_idx == 0 { None } else { Some(&params.where_predicates[pred_idx - 1]) };
+
+        let new_predicate = |f: &mut HirFormatter<'_>| {
+            f.write_str(if pred_idx == 0 { "\n    " } else { ",\n    " })
+        };
 
-        f.write_str("\n    ")?;
         match pred {
-            TypeBound { target, bound } => {
-                write_target(target, f)?;
-                f.write_str(": ")?;
+            WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {}
+            WherePredicate::TypeBound { target, bound } => {
+                if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target)
+                {
+                    f.write_str(" + ")?;
+                } else {
+                    new_predicate(f)?;
+                    write_target(target, f)?;
+                    f.write_str(": ")?;
+                }
                 bound.hir_fmt(f)?;
             }
-            Lifetime { target, bound } => {
-                let target = target.name.display(f.db.upcast());
-                let bound = bound.name.display(f.db.upcast());
-                write!(f, "{target}: {bound}")?;
+            WherePredicate::Lifetime { target, bound } => {
+                if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target)
+                {
+                    write!(f, " + {}", bound.name.display(f.db.upcast()))?;
+                } else {
+                    new_predicate(f)?;
+                    write!(
+                        f,
+                        "{}: {}",
+                        target.name.display(f.db.upcast()),
+                        bound.name.display(f.db.upcast())
+                    )?;
+                }
             }
-            ForLifetime { lifetimes, target, bound } => {
-                let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", ");
-                write!(f, "for<{lifetimes}> ")?;
-                write_target(target, f)?;
-                f.write_str(": ")?;
+            WherePredicate::ForLifetime { lifetimes, target, bound } => {
+                if matches!(
+                    prev_pred,
+                    Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. })
+                    if lifetimes_ == lifetimes && target_ == target,
+                ) {
+                    f.write_str(" + ")?;
+                } else {
+                    new_predicate(f)?;
+                    f.write_str("for<")?;
+                    for (idx, lifetime) in lifetimes.iter().enumerate() {
+                        if idx != 0 {
+                            f.write_str(", ")?;
+                        }
+                        write!(f, "{}", lifetime.display(f.db.upcast()))?;
+                    }
+                    f.write_str("> ")?;
+                    write_target(target, f)?;
+                    f.write_str(": ")?;
+                }
                 bound.hir_fmt(f)?;
             }
         }
-
-        while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) {
-            f.write_str(" + ")?;
-            match nxt {
-                TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?,
-                Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?,
-            }
-        }
-        f.write_str(",")?;
     }
 
-    Ok(())
+    // End of final predicate. There must be at least one predicate here.
+    f.write_char(',')?;
+
+    Ok(true)
 }
 
 impl HirDisplay for Const {
@@ -730,8 +689,17 @@ impl HirDisplay for Static {
 
 impl HirDisplay for Trait {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write_trait_header(self, f)?;
+        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
+        let data = f.db.trait_data(self.id);
+        if data.is_unsafe {
+            f.write_str("unsafe ")?;
+        }
+        if data.is_auto {
+            f.write_str("auto ")?;
+        }
+        write!(f, "trait {}", data.name.display(f.db.upcast()))?;
         let def_id = GenericDefId::TraitId(self.id);
+        write_generic_params(def_id, f)?;
         let has_where_clause = write_where_clause(def_id, f)?;
 
         if let Some(limit) = f.entity_limit {
@@ -767,20 +735,6 @@ impl HirDisplay for Trait {
     }
 }
 
-fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-    write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
-    let data = f.db.trait_data(trait_.id);
-    if data.is_unsafe {
-        f.write_str("unsafe ")?;
-    }
-    if data.is_auto {
-        f.write_str("auto ")?;
-    }
-    write!(f, "trait {}", data.name.display(f.db.upcast()))?;
-    write_generic_params(GenericDefId::TraitId(trait_.id), f)?;
-    Ok(())
-}
-
 impl HirDisplay for TraitAlias {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 4b3b7ff4c4..308e8a31ca 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -8,14 +8,13 @@ use hir_def::{
     Lookup, MacroId, VariantId,
 };
 use hir_expand::{HirFileId, InFile};
-use hir_ty::{db::InternedClosure, CallableDefId};
 use syntax::ast;
 use tt::TextRange;
 
 use crate::{
-    db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
-    Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait,
-    TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant,
+    db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
+    LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias,
+    TypeOrConstParam, Union, Variant,
 };
 
 pub trait HasSource {
@@ -223,68 +222,6 @@ impl HasSource for LocalSource {
     }
 }
 
-impl HasSource for Param {
-    type Ast = Either<ast::SelfParam, ast::Param>;
-
-    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        match self.func {
-            Callee::Def(CallableDefId::FunctionId(func)) => {
-                let InFile { file_id, value } = Function { id: func }.source(db)?;
-                let params = value.param_list()?;
-                if let Some(self_param) = params.self_param() {
-                    if let Some(idx) = self.idx.checked_sub(1) {
-                        params.params().nth(idx).map(Either::Right)
-                    } else {
-                        Some(Either::Left(self_param))
-                    }
-                } else {
-                    params.params().nth(self.idx).map(Either::Right)
-                }
-                .map(|value| InFile { file_id, value })
-            }
-            Callee::Closure(closure, _) => {
-                let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
-                let (_, source_map) = db.body_with_source_map(owner);
-                let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
-                let root = db.parse_or_expand(file_id);
-                match value.to_node(&root) {
-                    ast::Expr::ClosureExpr(it) => it
-                        .param_list()?
-                        .params()
-                        .nth(self.idx)
-                        .map(Either::Right)
-                        .map(|value| InFile { file_id: ast.file_id, value }),
-                    _ => None,
-                }
-            }
-            _ => None,
-        }
-    }
-}
-
-impl HasSource for SelfParam {
-    type Ast = ast::SelfParam;
-
-    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        let InFile { file_id, value } = Function::from(self.func).source(db)?;
-        value
-            .param_list()
-            .and_then(|params| params.self_param())
-            .map(|value| InFile { file_id, value })
-    }
-}
-
-impl HasSource for Label {
-    type Ast = ast::Label;
-
-    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        let (_body, source_map) = db.body_with_source_map(self.parent);
-        let src = source_map.label_syntax(self.label_id);
-        let root = src.file_syntax(db.upcast());
-        Some(src.map(|ast| ast.to_node(&root)))
-    }
-}
-
 impl HasSource for ExternCrateDecl {
     type Ast = ast::ExternCrate;
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 05fa7c4964..c69336407e 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -64,6 +64,7 @@ use hir_expand::{
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
+    db::InternedClosure,
     diagnostics::BodyValidationDiagnostic,
     error_lifetime, known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
@@ -1098,35 +1099,6 @@ pub enum FieldSource {
     Pos(ast::TupleField),
 }
 
-impl AstNode for FieldSource {
-    fn can_cast(kind: syntax::SyntaxKind) -> bool
-    where
-        Self: Sized,
-    {
-        ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind)
-    }
-
-    fn cast(syntax: SyntaxNode) -> Option<Self>
-    where
-        Self: Sized,
-    {
-        if ast::RecordField::can_cast(syntax.kind()) {
-            <ast::RecordField as AstNode>::cast(syntax).map(FieldSource::Named)
-        } else if ast::TupleField::can_cast(syntax.kind()) {
-            <ast::TupleField as AstNode>::cast(syntax).map(FieldSource::Pos)
-        } else {
-            None
-        }
-    }
-
-    fn syntax(&self) -> &SyntaxNode {
-        match self {
-            FieldSource::Named(it) => it.syntax(),
-            FieldSource::Pos(it) => it.syntax(),
-        }
-    }
-}
-
 impl Field {
     pub fn name(&self, db: &dyn HirDatabase) -> Name {
         self.parent.variant_data(db).fields()[self.id].name.clone()
@@ -2244,9 +2216,47 @@ impl Param {
         }
     }
 
-    pub fn pattern_source(self, db: &dyn HirDatabase) -> Option<ast::Pat> {
+    pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option<ast::Pat> {
         self.source(db).and_then(|p| p.value.right()?.pat())
     }
+
+    pub fn source(
+        &self,
+        db: &dyn HirDatabase,
+    ) -> Option<InFile<Either<ast::SelfParam, ast::Param>>> {
+        match self.func {
+            Callee::Def(CallableDefId::FunctionId(func)) => {
+                let InFile { file_id, value } = Function { id: func }.source(db)?;
+                let params = value.param_list()?;
+                if let Some(self_param) = params.self_param() {
+                    if let Some(idx) = self.idx.checked_sub(1) {
+                        params.params().nth(idx).map(Either::Right)
+                    } else {
+                        Some(Either::Left(self_param))
+                    }
+                } else {
+                    params.params().nth(self.idx).map(Either::Right)
+                }
+                .map(|value| InFile { file_id, value })
+            }
+            Callee::Closure(closure, _) => {
+                let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
+                let (_, source_map) = db.body_with_source_map(owner);
+                let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?;
+                let root = db.parse_or_expand(file_id);
+                match value.to_node(&root) {
+                    ast::Expr::ClosureExpr(it) => it
+                        .param_list()?
+                        .params()
+                        .nth(self.idx)
+                        .map(Either::Right)
+                        .map(|value| InFile { file_id: ast.file_id, value }),
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -2270,6 +2280,14 @@ impl SelfParam {
             .unwrap_or(Access::Owned)
     }
 
+    pub fn source(&self, db: &dyn HirDatabase) -> Option<InFile<ast::SelfParam>> {
+        let InFile { file_id, value } = Function::from(self.func).source(db)?;
+        value
+            .param_list()
+            .and_then(|params| params.self_param())
+            .map(|value| InFile { file_id, value })
+    }
+
     pub fn parent_fn(&self) -> Function {
         Function::from(self.func)
     }
@@ -3440,6 +3458,13 @@ impl Label {
         let body = db.body(self.parent);
         body[self.label_id].name.clone()
     }
+
+    pub fn source(self, db: &dyn HirDatabase) -> InFile<ast::Label> {
+        let (_body, source_map) = db.body_with_source_map(self.parent);
+        let src = source_map.label_syntax(self.label_id);
+        let root = src.file_syntax(db.upcast());
+        src.map(|ast| ast.to_node(&root))
+    }
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 2a5112abd8..5ed75cdd47 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -132,6 +132,9 @@ pub struct SemanticsImpl<'db> {
     s2d_cache: RefCell<SourceToDefCache>,
     /// Rootnode to HirFileId cache
     root_to_file_cache: RefCell<FxHashMap<SyntaxNode, HirFileId>>,
+    /// HirFileId to Rootnode cache (this adds a layer over the database LRU cache to prevent
+    /// possibly frequent invalidation)
+    parse_cache: RefCell<FxHashMap<HirFileId, SyntaxNode>>,
     /// MacroCall to its expansion's MacroFileId cache
     macro_call_cache: RefCell<FxHashMap<InFile<ast::MacroCall>, MacroFileId>>,
 }
@@ -292,6 +295,7 @@ impl<'db> SemanticsImpl<'db> {
             db,
             s2d_cache: Default::default(),
             root_to_file_cache: Default::default(),
+            parse_cache: Default::default(),
             macro_call_cache: Default::default(),
         }
     }
@@ -303,6 +307,9 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub fn parse_or_expand(&self, file_id: HirFileId) -> SyntaxNode {
+        if let Some(root) = self.parse_cache.borrow().get(&file_id) {
+            return root.clone();
+        }
         let node = self.db.parse_or_expand(file_id);
         self.cache(node.clone(), file_id);
         node
@@ -1483,8 +1490,9 @@ impl<'db> SemanticsImpl<'db> {
     fn cache(&self, root_node: SyntaxNode, file_id: HirFileId) {
         assert!(root_node.parent().is_none());
         let mut cache = self.root_to_file_cache.borrow_mut();
-        let prev = cache.insert(root_node, file_id);
+        let prev = cache.insert(root_node.clone(), file_id);
         assert!(prev.is_none() || prev == Some(file_id));
+        self.parse_cache.borrow_mut().insert(file_id, root_node);
     }
 
     pub fn assert_contains_node(&self, node: &SyntaxNode) {
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index f2a097afc8..23a06404f3 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -254,7 +254,7 @@ fn from_param(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>) -> Option<St
 
     let (idx, _) = arg_list.args().find_position(|it| it == expr).unwrap();
     let param = func.params().into_iter().nth(idx)?;
-    let pat = sema.source(param)?.value.right()?.pat()?;
+    let pat = param.source(sema.db)?.value.right()?.pat()?;
     let name = var_name_from_pat(&pat)?;
     normalize(&name.to_string())
 }
diff --git a/crates/ide-db/src/active_parameter.rs b/crates/ide-db/src/active_parameter.rs
index 088d2ec5e3..98d2e81754 100644
--- a/crates/ide-db/src/active_parameter.rs
+++ b/crates/ide-db/src/active_parameter.rs
@@ -28,7 +28,7 @@ impl ActiveParameter {
             return None;
         }
         let param = params.swap_remove(idx);
-        Some(ActiveParameter { ty: param.ty().clone(), src: sema.source(param) })
+        Some(ActiveParameter { ty: param.ty().clone(), src: param.source(sema.db) })
     }
 
     pub fn ident(&self) -> Option<ast::Name> {
diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs
index b4486d1502..1ca5206011 100644
--- a/crates/ide-db/src/prime_caches.rs
+++ b/crates/ide-db/src/prime_caches.rs
@@ -29,7 +29,7 @@ pub struct ParallelPrimeCachesProgress {
 
 pub fn parallel_prime_caches(
     db: &RootDatabase,
-    num_worker_threads: usize,
+    num_worker_threads: u8,
     cb: &(dyn Fn(ParallelPrimeCachesProgress) + Sync),
 ) {
     let _p = tracing::info_span!("parallel_prime_caches").entered();
diff --git a/crates/ide-db/src/rename.rs b/crates/ide-db/src/rename.rs
index 484c65c2b0..288d56b534 100644
--- a/crates/ide-db/src/rename.rs
+++ b/crates/ide-db/src/rename.rs
@@ -24,7 +24,7 @@ use std::fmt;
 
 use base_db::{AnchoredPathBuf, FileId, FileRange};
 use either::Either;
-use hir::{FieldSource, HirFileIdExt, InFile, ModuleSource, Semantics};
+use hir::{FieldSource, HasSource, HirFileIdExt, InFile, ModuleSource, Semantics};
 use span::SyntaxContextId;
 use stdx::{never, TupleExt};
 use syntax::{
@@ -109,7 +109,7 @@ impl Definition {
         let syn_ctx_is_root = |(range, ctx): (_, SyntaxContextId)| ctx.is_root().then_some(range);
         let res = match self {
             Definition::Macro(mac) => {
-                let src = sema.source(mac)?;
+                let src = mac.source(sema.db)?;
                 let name = match &src.value {
                     Either::Left(it) => it.name()?,
                     Either::Right(it) => it.name()?,
@@ -119,7 +119,7 @@ impl Definition {
                     .and_then(syn_ctx_is_root)
             }
             Definition::Field(field) => {
-                let src = sema.source(field)?;
+                let src = field.source(sema.db)?;
                 match &src.value {
                     FieldSource::Named(record_field) => {
                         let name = record_field.name()?;
@@ -154,18 +154,18 @@ impl Definition {
             }
             Definition::GenericParam(generic_param) => match generic_param {
                 hir::GenericParam::LifetimeParam(lifetime_param) => {
-                    let src = sema.source(lifetime_param)?;
+                    let src = lifetime_param.source(sema.db)?;
                     src.with_value(src.value.lifetime()?.syntax())
                         .original_file_range_opt(sema.db)
                         .and_then(syn_ctx_is_root)
                 }
                 _ => {
-                    let param = match generic_param {
+                    let x = match generic_param {
                         hir::GenericParam::TypeParam(it) => it.merge(),
                         hir::GenericParam::ConstParam(it) => it.merge(),
                         hir::GenericParam::LifetimeParam(_) => return None,
                     };
-                    let src = sema.source(param)?;
+                    let src = x.source(sema.db)?;
                     let name = match &src.value {
                         Either::Left(x) => x.name()?,
                         Either::Right(_) => return None,
@@ -176,14 +176,14 @@ impl Definition {
                 }
             },
             Definition::Label(label) => {
-                let src = sema.source(label)?;
+                let src = label.source(sema.db);
                 let lifetime = src.value.lifetime()?;
                 src.with_value(lifetime.syntax())
                     .original_file_range_opt(sema.db)
                     .and_then(syn_ctx_is_root)
             }
             Definition::ExternCrateDecl(it) => {
-                let src = sema.source(it)?;
+                let src = it.source(sema.db)?;
                 if let Some(rename) = src.value.rename() {
                     let name = rename.name()?;
                     src.with_value(name.syntax())
@@ -212,10 +212,10 @@ impl Definition {
             sema: &Semantics<'_, RootDatabase>,
         ) -> Option<(FileRange, SyntaxContextId)>
         where
-            D: hir::HasSource,
+            D: HasSource,
             D::Ast: ast::HasName,
         {
-            let src = sema.source(def)?;
+            let src = def.source(sema.db)?;
             let name = src.value.name()?;
             src.with_value(name.syntax()).original_file_range_opt(sema.db)
         }
diff --git a/crates/ide-ssr/src/matching.rs b/crates/ide-ssr/src/matching.rs
index b29053c0c2..cf7e7e08bc 100644
--- a/crates/ide-ssr/src/matching.rs
+++ b/crates/ide-ssr/src/matching.rs
@@ -575,7 +575,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                             .resolve_method_call_as_callable(code)
                             .and_then(|callable| {
                                 let (self_param, _) = callable.receiver_param(self.sema.db)?;
-                                Some(self.sema.source(self_param)?.value.kind())
+                                Some(self_param.source(self.sema.db)?.value.kind())
                             })
                             .unwrap_or(ast::SelfParamKind::Owned);
                     }
diff --git a/crates/ide/src/call_hierarchy.rs b/crates/ide/src/call_hierarchy.rs
index f7e5b40dde..654a1cd316 100644
--- a/crates/ide/src/call_hierarchy.rs
+++ b/crates/ide/src/call_hierarchy.rs
@@ -19,6 +19,13 @@ pub struct CallItem {
     pub ranges: Vec<TextRange>,
 }
 
+impl CallItem {
+    #[cfg(test)]
+    pub(crate) fn debug_render(&self) -> String {
+        format!("{} : {:?}", self.target.debug_render(), self.ranges)
+    }
+}
+
 pub(crate) fn call_hierarchy(
     db: &RootDatabase,
     position: FilePosition,
@@ -152,10 +159,6 @@ mod tests {
         expected_incoming: Expect,
         expected_outgoing: Expect,
     ) {
-        fn debug_render(item: crate::CallItem) -> String {
-            format!("{} : {:?}", item.target.debug_render(), item.ranges)
-        }
-
         let (analysis, pos) = fixture::position(ra_fixture);
 
         let mut navs = analysis.call_hierarchy(pos).unwrap().unwrap().info;
@@ -166,10 +169,12 @@ mod tests {
         let item_pos =
             FilePosition { file_id: nav.file_id, offset: nav.focus_or_full_range().start() };
         let incoming_calls = analysis.incoming_calls(item_pos).unwrap().unwrap();
-        expected_incoming.assert_eq(&incoming_calls.into_iter().map(debug_render).join("\n"));
+        expected_incoming
+            .assert_eq(&incoming_calls.into_iter().map(|call| call.debug_render()).join("\n"));
 
         let outgoing_calls = analysis.outgoing_calls(item_pos).unwrap().unwrap();
-        expected_outgoing.assert_eq(&outgoing_calls.into_iter().map(debug_render).join("\n"));
+        expected_outgoing
+            .assert_eq(&outgoing_calls.into_iter().map(|call| call.debug_render()).join("\n"));
     }
 
     #[test]
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 99568c9922..3bc17f95e7 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -430,7 +430,6 @@ pub(super) fn definition(
             }
             label
         }
-        Definition::Function(fn_) => fn_.display_with_container_bounds(db, true).to_string(),
         _ => def.label(db),
     };
     let docs = def.docs(db, famous_defs);
diff --git a/crates/ide/src/inlay_hints/adjustment.rs b/crates/ide/src/inlay_hints/adjustment.rs
index 7932d8efbc..20128a286f 100644
--- a/crates/ide/src/inlay_hints/adjustment.rs
+++ b/crates/ide/src/inlay_hints/adjustment.rs
@@ -709,25 +709,4 @@ fn main() {
             "#,
         )
     }
-
-    // regression test for a stackoverflow in hir display code
-    #[test]
-    fn adjustment_hints_method_call_on_impl_trait_self() {
-        check_with_config(
-            InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
-            r#"
-//- minicore: slice, coerce_unsized
-trait T<RHS = Self> {}
-
-fn hello(it: &&[impl T]) {
-    it.len();
-  //^^(
-  //^^&
-  //^^*
-  //^^*
-  //^^)
-}
-"#,
-        );
-    }
 }
diff --git a/crates/ide/src/inlay_hints/param_name.rs b/crates/ide/src/inlay_hints/param_name.rs
index 9819d0e3fb..fb50c49a3a 100644
--- a/crates/ide/src/inlay_hints/param_name.rs
+++ b/crates/ide/src/inlay_hints/param_name.rs
@@ -30,7 +30,7 @@ pub(super) fn hints(
         .filter_map(|(p, arg)| {
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
-            let source = sema.source(p)?;
+            let source = p.source(sema.db)?;
             let (param_name, name_syntax) = match source.value.as_ref() {
                 Either::Left(pat) => (pat.name()?, pat.name()),
                 Either::Right(param) => match param.pat()? {
@@ -38,6 +38,8 @@ pub(super) fn hints(
                     _ => return None,
                 },
             };
+            // make sure the file is cached so we can map out of macros
+            sema.parse_or_expand(source.file_id);
             Some((name_syntax, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index a2ac62341d..e9408bf897 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -284,7 +284,7 @@ impl Analysis {
         })
     }
 
-    pub fn parallel_prime_caches<F>(&self, num_worker_threads: usize, cb: F) -> Cancellable<()>
+    pub fn parallel_prime_caches<F>(&self, num_worker_threads: u8, cb: F) -> Cancellable<()>
     where
         F: Fn(ParallelPrimeCachesProgress) + Sync + std::panic::UnwindSafe,
     {
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index bfd62e7624..a93a8da57e 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -220,7 +220,7 @@ impl TryToNav for Definition {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
         match self {
             Definition::Local(it) => Some(it.to_nav(db)),
-            Definition::Label(it) => it.try_to_nav(db),
+            Definition::Label(it) => Some(it.to_nav(db)),
             Definition::Module(it) => Some(it.to_nav(db)),
             Definition::Macro(it) => it.try_to_nav(db),
             Definition::Field(it) => it.try_to_nav(db),
@@ -562,12 +562,12 @@ impl ToNav for hir::Local {
     }
 }
 
-impl TryToNav for hir::Label {
-    fn try_to_nav(&self, db: &RootDatabase) -> Option<UpmappingResult<NavigationTarget>> {
-        let InFile { file_id, value } = self.source(db)?;
+impl ToNav for hir::Label {
+    fn to_nav(&self, db: &RootDatabase) -> UpmappingResult<NavigationTarget> {
+        let InFile { file_id, value } = self.source(db);
         let name = self.name(db).to_smol_str();
 
-        Some(orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
+        orig_range_with_focus(db, file_id, value.syntax(), value.lifetime()).map(
             |(FileRange { file_id, range: full_range }, focus_range)| NavigationTarget {
                 file_id,
                 name: name.clone(),
@@ -579,7 +579,7 @@ impl TryToNav for hir::Label {
                 description: None,
                 docs: None,
             },
-        ))
+        )
     }
 }
 
diff --git a/crates/ide/src/rename.rs b/crates/ide/src/rename.rs
index 3d08e2f371..a13758a9f4 100644
--- a/crates/ide/src/rename.rs
+++ b/crates/ide/src/rename.rs
@@ -361,9 +361,8 @@ fn rename_to_self(
         bail!("Parameter type differs from impl block type");
     }
 
-    let InFile { file_id, value: param_source } = sema
-        .source(first_param.clone())
-        .ok_or_else(|| format_err!("No source for parameter found"))?;
+    let InFile { file_id, value: param_source } =
+        first_param.source(sema.db).ok_or_else(|| format_err!("No source for parameter found"))?;
 
     let def = Definition::Local(local);
     let usages = def.usages(sema).all();
@@ -393,7 +392,7 @@ fn rename_self_to_param(
     let identifier_kind = IdentifierKind::classify(new_name)?;
 
     let InFile { file_id, value: self_param } =
-        sema.source(self_param).ok_or_else(|| format_err!("cannot find function source"))?;
+        self_param.source(sema.db).ok_or_else(|| format_err!("cannot find function source"))?;
 
     let def = Definition::Local(local);
     let usages = def.usages(sema).all();
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/signature_help.rs
index 89c725a6c4..378a38892c 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/signature_help.rs
@@ -226,7 +226,7 @@ fn signature_help_for_call(
         let mut buf = String::new();
         for (idx, p) in callable.params().into_iter().enumerate() {
             buf.clear();
-            if let Some(param) = sema.source(p.clone()) {
+            if let Some(param) = p.source(sema.db) {
                 match param.value {
                     Either::Right(param) => match param.pat() {
                         Some(pat) => format_to!(buf, "{}: ", pat),
diff --git a/crates/ide/src/syntax_highlighting/escape.rs b/crates/ide/src/syntax_highlighting/escape.rs
index 552ce9cd8c..2f387968c9 100644
--- a/crates/ide/src/syntax_highlighting/escape.rs
+++ b/crates/ide/src/syntax_highlighting/escape.rs
@@ -28,7 +28,7 @@ pub(super) fn highlight_escape_string<T: IsString>(
 pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
     if char.value().is_err() {
         // We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
-        // state and this token contains junk, since `'` is not a reliable delimiter (consider
+        // state and this token contains junks, since `'` is not a reliable delimiter (consider
         // lifetimes). Nonetheless, parser errors should already be emitted.
         return;
     }
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index cb785195a0..10c41fda75 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -285,6 +285,7 @@ impl SourceRootConfig {
     /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot`.
     pub fn source_root_parent_map(&self) -> FxHashMap<SourceRootId, SourceRootId> {
         let roots = self.fsc.roots();
+        let mut i = 0;
         roots
             .iter()
             .enumerate()
@@ -292,14 +293,9 @@ impl SourceRootConfig {
             .filter_map(|(idx, (root, root_id))| {
                 // We are interested in parents if they are also local source roots.
                 // So instead of a non-local parent we may take a local ancestor as a parent to a node.
-                //
-                // Here paths in roots are sorted lexicographically, so if a root
-                // is a parent of another root, it will be before it in the list.
                 roots[..idx].iter().find_map(|(root2, root2_id)| {
-                    if self.local_filesets.contains(root2_id)
-                        && root.starts_with(root2)
-                        && root_id != root2_id
-                    {
+                    i += 1;
+                    if self.local_filesets.contains(root2_id) && root.starts_with(root2) {
                         return Some((root_id, root2_id));
                     }
                     None
@@ -576,20 +572,4 @@ mod tests {
 
         assert_eq!(vc, vec![(SourceRootId(3), SourceRootId(1)),])
     }
-
-    #[test]
-    fn parents_with_identical_root_id() {
-        let mut builder = FileSetConfigBuilder::default();
-        builder.add_file_set(vec![
-            VfsPath::new_virtual_path("/ROOT/def".to_owned()),
-            VfsPath::new_virtual_path("/ROOT/def/abc/def".to_owned()),
-        ]);
-        builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc/def/ghi".to_owned())]);
-        let fsc = builder.build();
-        let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
-        let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
-        vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
-
-        assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0)),])
-    }
 }
diff --git a/crates/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index 19ba5c7a15..f73e188c79 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -215,7 +215,7 @@ fn invocation_fixtures(
 
                 token_trees.push(subtree.into());
             }
-            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => {}
+            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
         };
 
         // Simple linear congruential generator for deterministic result
diff --git a/crates/mbe/src/expander/matcher.rs b/crates/mbe/src/expander/matcher.rs
index 0cec4e70da..78d4bfee2a 100644
--- a/crates/mbe/src/expander/matcher.rs
+++ b/crates/mbe/src/expander/matcher.rs
@@ -566,7 +566,7 @@ fn match_loop_inner<'t>(
                 error_items.push(item);
             }
             OpDelimited::Op(
-                Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. },
+                Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. },
             ) => {
                 stdx::never!("metavariable expression in lhs found");
             }
@@ -832,7 +832,7 @@ fn collect_vars(collector_fun: &mut impl FnMut(SmolStr), pattern: &MetaTemplate)
             Op::Subtree { tokens, .. } => collect_vars(collector_fun, tokens),
             Op::Repeat { tokens, .. } => collect_vars(collector_fun, tokens),
             Op::Literal(_) | Op::Ident(_) | Op::Punct(_) => {}
-            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Len { .. } => {
+            Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {
                 stdx::never!("metavariable expression in lhs found");
             }
         }
diff --git a/crates/mbe/src/expander/transcriber.rs b/crates/mbe/src/expander/transcriber.rs
index 0f689a2692..5e6e45f152 100644
--- a/crates/mbe/src/expander/transcriber.rs
+++ b/crates/mbe/src/expander/transcriber.rs
@@ -242,7 +242,7 @@ fn expand_subtree(
                     .into(),
                 );
             }
-            Op::Len { depth } => {
+            Op::Length { depth } => {
                 let length = ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |_nest| {
                     // FIXME: to be implemented
                     0
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index bbe00f0afc..eaf2fd8c27 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -75,7 +75,7 @@ pub(crate) enum Op {
     Index {
         depth: usize,
     },
-    Len {
+    Length {
         depth: usize,
     },
     Count {
@@ -345,7 +345,7 @@ fn parse_metavar_expr(new_meta_vars: bool, src: &mut TtIter<'_, Span>) -> Result
             Op::Ignore { name: ident.text.clone(), id: ident.span }
         }
         "index" => Op::Index { depth: parse_depth(&mut args)? },
-        "len" => Op::Len { depth: parse_depth(&mut args)? },
+        "length" => Op::Length { depth: parse_depth(&mut args)? },
         "count" => {
             if new_meta_vars {
                 args.expect_dollar()?;
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index c8ff8c35e9..412e492176 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -47,7 +47,7 @@ pub(crate) mod dummy_test_span_utils {
     pub const DUMMY: Span = Span {
         range: TextRange::empty(TextSize::new(0)),
         anchor: span::SpanAnchor {
-            file_id: span::FileId::from_raw(0xe4e4e),
+            file_id: span::FileId::BOGUS,
             ast_id: span::ROOT_ERASED_FILE_AST_ID,
         },
         ctx: SyntaxContextId::ROOT,
@@ -60,7 +60,7 @@ pub(crate) mod dummy_test_span_utils {
             Span {
                 range,
                 anchor: span::SpanAnchor {
-                    file_id: span::FileId::from_raw(0xe4e4e),
+                    file_id: span::FileId::BOGUS,
                     ast_id: span::ROOT_ERASED_FILE_AST_ID,
                 },
                 ctx: SyntaxContextId::ROOT,
diff --git a/crates/project-model/src/lib.rs b/crates/project-model/src/lib.rs
index 35643dcc02..181c07f46b 100644
--- a/crates/project-model/src/lib.rs
+++ b/crates/project-model/src/lib.rs
@@ -22,7 +22,7 @@ mod cargo_workspace;
 mod cfg;
 mod env;
 mod manifest_path;
-pub mod project_json;
+mod project_json;
 mod rustc_cfg;
 mod sysroot;
 pub mod target_data_layout;
diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs
index 4a916e570b..408593ea8a 100644
--- a/crates/project-model/src/project_json.rs
+++ b/crates/project-model/src/project_json.rs
@@ -33,7 +33,7 @@
 //!
 //! * file on disk
 //! * a field in the config (ie, you can send a JSON request with the contents
-//!   of `rust-project.json` to rust-analyzer, no need to write anything to disk)
+//!   of rust-project.json to rust-analyzer, no need to write anything to disk)
 //!
 //! Another possible thing we don't do today, but which would be totally valid,
 //! is to add an extension point to VS Code extension to register custom
@@ -55,7 +55,8 @@ use rustc_hash::FxHashMap;
 use serde::{de, Deserialize, Serialize};
 use span::Edition;
 
-use crate::{cfg::CfgFlag, ManifestPath, TargetKind};
+use crate::cfg::CfgFlag;
+use crate::ManifestPath;
 
 /// Roots and crates that compose this Rust project.
 #[derive(Clone, Debug, Eq, PartialEq)]
@@ -67,10 +68,6 @@ pub struct ProjectJson {
     project_root: AbsPathBuf,
     manifest: Option<ManifestPath>,
     crates: Vec<Crate>,
-    /// Configuration for CLI commands.
-    ///
-    /// Examples include a check build or a test run.
-    runnables: Vec<Runnable>,
 }
 
 /// A crate points to the root module of a crate and lists the dependencies of the crate. This is
@@ -91,86 +88,6 @@ pub struct Crate {
     pub(crate) exclude: Vec<AbsPathBuf>,
     pub(crate) is_proc_macro: bool,
     pub(crate) repository: Option<String>,
-    pub build: Option<Build>,
-}
-
-/// Additional, build-specific data about a crate.
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct Build {
-    /// The name associated with this crate.
-    ///
-    /// This is determined by the build system that produced
-    /// the `rust-project.json` in question. For instance, if buck were used,
-    /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
-    ///
-    /// Do not attempt to parse the contents of this string; it is a build system-specific
-    /// identifier similar to [`Crate::display_name`].
-    pub label: String,
-    /// Path corresponding to the build system-specific file defining the crate.
-    ///
-    /// It is roughly analogous to [`ManifestPath`], but it should *not* be used with
-    /// [`crate::ProjectManifest::from_manifest_file`], as the build file may not be
-    /// be in the `rust-project.json`.
-    pub build_file: Utf8PathBuf,
-    /// The kind of target.
-    ///
-    /// Examples (non-exhaustively) include [`TargetKind::Bin`], [`TargetKind::Lib`],
-    /// and [`TargetKind::Test`]. This information is used to determine what sort
-    /// of runnable codelens to provide, if any.
-    pub target_kind: TargetKind,
-}
-
-/// A template-like structure for describing runnables.
-///
-/// These are used for running and debugging binaries and tests without encoding
-/// build system-specific knowledge into rust-analyzer.
-///
-/// # Example
-///
-/// Below is an example of a test runnable. `{label}` and `{test_id}`
-/// are explained in [`Runnable::args`]'s documentation.
-///
-/// ```json
-/// {
-///     "program": "buck",
-///     "args": [
-///         "test",
-///          "{label}",
-///          "--",
-///          "{test_id}",
-///          "--print-passing-details"
-///     ],
-///     "cwd": "/home/user/repo-root/",
-///     "kind": "testOne"
-/// }
-/// ```
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Runnable {
-    /// The program invoked by the runnable.
-    ///
-    /// For example, this might be `cargo`, `buck`, or `bazel`.
-    pub program: String,
-    /// The arguments passed to [`Runnable::program`].
-    ///
-    /// The args can contain two template strings: `{label}` and `{test_id}`.
-    /// rust-analyzer will find and replace `{label}` with [`Build::label`] and
-    /// `{test_id}` with the test name.
-    pub args: Vec<String>,
-    /// The current working directory of the runnable.
-    pub cwd: Utf8PathBuf,
-    pub kind: RunnableKind,
-}
-
-/// The kind of runnable.
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum RunnableKind {
-    Check,
-
-    /// Can run a binary.
-    Run,
-
-    /// Run a single test.
-    TestOne,
 }
 
 impl ProjectJson {
@@ -178,7 +95,6 @@ impl ProjectJson {
     ///
     /// # Arguments
     ///
-    /// * `manifest` - The path to the `rust-project.json`.
     /// * `base` - The path to the workspace root (i.e. the folder containing `rust-project.json`)
     /// * `data` - The parsed contents of `rust-project.json`, or project json that's passed via
     ///            configuration.
@@ -193,7 +109,6 @@ impl ProjectJson {
             sysroot_src: data.sysroot_src.map(absolutize_on_base),
             project_root: base.to_path_buf(),
             manifest,
-            runnables: data.runnables.into_iter().map(Runnable::from).collect(),
             crates: data
                 .crates
                 .into_iter()
@@ -212,15 +127,6 @@ impl ProjectJson {
                         None => (vec![root_module.parent().unwrap().to_path_buf()], Vec::new()),
                     };
 
-                    let build = match crate_data.build {
-                        Some(build) => Some(Build {
-                            label: build.label,
-                            build_file: build.build_file,
-                            target_kind: build.target_kind.into(),
-                        }),
-                        None => None,
-                    };
-
                     Crate {
                         display_name: crate_data
                             .display_name
@@ -240,7 +146,6 @@ impl ProjectJson {
                         exclude,
                         is_proc_macro: crate_data.is_proc_macro,
                         repository: crate_data.repository,
-                        build,
                     }
                 })
                 .collect(),
@@ -262,15 +167,7 @@ impl ProjectJson {
         &self.project_root
     }
 
-    pub fn crate_by_root(&self, root: &AbsPath) -> Option<Crate> {
-        self.crates
-            .iter()
-            .filter(|krate| krate.is_workspace_member)
-            .find(|krate| krate.root_module == root)
-            .cloned()
-    }
-
-    /// Returns the path to the project's manifest, if it exists.
+    /// Returns the path to the project's manifest file, if it exists.
     pub fn manifest(&self) -> Option<&ManifestPath> {
         self.manifest.as_ref()
     }
@@ -279,10 +176,6 @@ impl ProjectJson {
     pub fn manifest_or_root(&self) -> &AbsPath {
         self.manifest.as_ref().map_or(&self.project_root, |manifest| manifest.as_ref())
     }
-
-    pub fn runnables(&self) -> &[Runnable] {
-        &self.runnables
-    }
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -290,8 +183,6 @@ pub struct ProjectJsonData {
     sysroot: Option<Utf8PathBuf>,
     sysroot_src: Option<Utf8PathBuf>,
     crates: Vec<CrateData>,
-    #[serde(default)]
-    runnables: Vec<RunnableData>,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -314,8 +205,6 @@ struct CrateData {
     is_proc_macro: bool,
     #[serde(default)]
     repository: Option<String>,
-    #[serde(default)]
-    build: Option<BuildData>,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -331,48 +220,6 @@ enum EditionData {
     Edition2024,
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize)]
-pub struct BuildData {
-    label: String,
-    build_file: Utf8PathBuf,
-    target_kind: TargetKindData,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
-pub struct RunnableData {
-    pub program: String,
-    pub args: Vec<String>,
-    pub cwd: Utf8PathBuf,
-    pub kind: RunnableKindData,
-}
-
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub enum RunnableKindData {
-    Check,
-    Run,
-    TestOne,
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
-#[serde(rename_all = "camelCase")]
-pub enum TargetKindData {
-    Bin,
-    /// Any kind of Cargo lib crate-type (dylib, rlib, proc-macro, ...).
-    Lib,
-    Test,
-}
-
-impl From<TargetKindData> for TargetKind {
-    fn from(data: TargetKindData) -> Self {
-        match data {
-            TargetKindData::Bin => TargetKind::Bin,
-            TargetKindData::Lib => TargetKind::Lib { is_proc_macro: false },
-            TargetKindData::Test => TargetKind::Test,
-        }
-    }
-}
-
 impl From<EditionData> for Edition {
     fn from(data: EditionData) -> Self {
         match data {
@@ -384,22 +231,6 @@ impl From<EditionData> for Edition {
     }
 }
 
-impl From<RunnableData> for Runnable {
-    fn from(data: RunnableData) -> Self {
-        Runnable { program: data.program, args: data.args, cwd: data.cwd, kind: data.kind.into() }
-    }
-}
-
-impl From<RunnableKindData> for RunnableKind {
-    fn from(data: RunnableKindData) -> Self {
-        match data {
-            RunnableKindData::Check => RunnableKind::Check,
-            RunnableKindData::Run => RunnableKind::Run,
-            RunnableKindData::TestOne => RunnableKind::TestOne,
-        }
-    }
-}
-
 /// Identifies a crate by position in the crates array.
 ///
 /// This will differ from `CrateId` when multiple `ProjectJson`
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 17e40e74de..4dba11eac3 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -76,7 +76,7 @@ pub enum ProjectWorkspaceKind {
         /// Environment variables set in the `.cargo/config` file.
         cargo_config_extra_env: FxHashMap<String, String>,
     },
-    /// Project workspace was specified using a `rust-project.json` file.
+    /// Project workspace was manually specified using a `rust-project.json` file.
     Json(ProjectJson),
     // FIXME: The primary limitation of this approach is that the set of detached files needs to be fixed at the beginning.
     // That's not the end user experience we should strive for.
diff --git a/crates/rust-analyzer/src/target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
similarity index 77%
rename from crates/rust-analyzer/src/target_spec.rs
rename to crates/rust-analyzer/src/cargo_target_spec.rs
index 6145f7e05f..693a35b91e 100644
--- a/crates/rust-analyzer/src/target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -1,52 +1,20 @@
-//! See `TargetSpec`
+//! See `CargoTargetSpec`
 
 use std::mem;
 
 use cfg::{CfgAtom, CfgExpr};
 use ide::{Cancellable, CrateId, FileId, RunnableKind, TestId};
-use project_model::project_json::Runnable;
 use project_model::{CargoFeatures, ManifestPath, TargetKind};
 use rustc_hash::FxHashSet;
 use vfs::AbsPathBuf;
 
 use crate::global_state::GlobalStateSnapshot;
 
-/// A target represents a thing we can build or test.
-///
-/// We use it to calculate the CLI arguments required to build, run or
-/// test the target.
-#[derive(Clone, Debug)]
-pub(crate) enum TargetSpec {
-    Cargo(CargoTargetSpec),
-    ProjectJson(ProjectJsonTargetSpec),
-}
-
-impl TargetSpec {
-    pub(crate) fn for_file(
-        global_state_snapshot: &GlobalStateSnapshot,
-        file_id: FileId,
-    ) -> Cancellable<Option<Self>> {
-        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
-            &[crate_id, ..] => crate_id,
-            _ => return Ok(None),
-        };
-
-        Ok(global_state_snapshot.target_spec_for_crate(crate_id))
-    }
-
-    pub(crate) fn target_kind(&self) -> TargetKind {
-        match self {
-            TargetSpec::Cargo(cargo) => cargo.target_kind,
-            TargetSpec::ProjectJson(project_json) => project_json.target_kind,
-        }
-    }
-}
-
 /// Abstract representation of Cargo target.
 ///
 /// We use it to cook up the set of cli args we need to pass to Cargo to
 /// build/test/run the target.
-#[derive(Clone, Debug)]
+#[derive(Clone)]
 pub(crate) struct CargoTargetSpec {
     pub(crate) workspace_root: AbsPathBuf,
     pub(crate) cargo_toml: ManifestPath,
@@ -58,51 +26,6 @@ pub(crate) struct CargoTargetSpec {
     pub(crate) features: FxHashSet<String>,
 }
 
-#[derive(Clone, Debug)]
-pub(crate) struct ProjectJsonTargetSpec {
-    pub(crate) label: String,
-    pub(crate) target_kind: TargetKind,
-    pub(crate) shell_runnables: Vec<Runnable>,
-}
-
-impl ProjectJsonTargetSpec {
-    pub(crate) fn runnable_args(&self, kind: &RunnableKind) -> Option<Runnable> {
-        match kind {
-            RunnableKind::Bin => {
-                for runnable in &self.shell_runnables {
-                    if matches!(runnable.kind, project_model::project_json::RunnableKind::Run) {
-                        return Some(runnable.clone());
-                    }
-                }
-
-                None
-            }
-            RunnableKind::Test { test_id, .. } => {
-                for runnable in &self.shell_runnables {
-                    if matches!(runnable.kind, project_model::project_json::RunnableKind::TestOne) {
-                        let mut runnable = runnable.clone();
-
-                        let replaced_args: Vec<_> = runnable
-                            .args
-                            .iter()
-                            .map(|arg| arg.replace("{test_id}", &test_id.to_string()))
-                            .map(|arg| arg.replace("{label}", &self.label))
-                            .collect();
-                        runnable.args = replaced_args;
-
-                        return Some(runnable);
-                    }
-                }
-
-                None
-            }
-            RunnableKind::TestMod { .. } => None,
-            RunnableKind::Bench { .. } => None,
-            RunnableKind::DocTest { .. } => None,
-        }
-    }
-}
-
 impl CargoTargetSpec {
     pub(crate) fn runnable_args(
         snap: &GlobalStateSnapshot,
@@ -199,6 +122,35 @@ impl CargoTargetSpec {
         (cargo_args, executable_args)
     }
 
+    pub(crate) fn for_file(
+        global_state_snapshot: &GlobalStateSnapshot,
+        file_id: FileId,
+    ) -> Cancellable<Option<CargoTargetSpec>> {
+        let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
+            &[crate_id, ..] => crate_id,
+            _ => return Ok(None),
+        };
+        let (cargo_ws, target) = match global_state_snapshot.cargo_target_for_crate_root(crate_id) {
+            Some(it) => it,
+            None => return Ok(None),
+        };
+
+        let target_data = &cargo_ws[target];
+        let package_data = &cargo_ws[target_data.package];
+        let res = CargoTargetSpec {
+            workspace_root: cargo_ws.workspace_root().to_path_buf(),
+            cargo_toml: package_data.manifest.clone(),
+            package: cargo_ws.package_flag(package_data),
+            target: target_data.name.clone(),
+            target_kind: target_data.kind,
+            required_features: target_data.required_features.clone(),
+            features: package_data.features.keys().cloned().collect(),
+            crate_id,
+        };
+
+        Ok(Some(res))
+    }
+
     pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
         buf.push("--package".to_owned());
         buf.push(self.package);
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index e8504979be..497fd67e92 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -73,7 +73,7 @@ config_data! {
         /// Warm up caches on project load.
         cachePriming_enable: bool = true,
         /// How many worker threads to handle priming caches. The default `0` means to pick automatically.
-        cachePriming_numThreads: NumThreads = NumThreads::Physical,
+        cachePriming_numThreads: ParallelCachePrimingNumThreads = 0u8,
 
         /// Pass `--all-targets` to cargo invocation.
         cargo_allTargets: bool           = true,
@@ -583,7 +583,7 @@ config_data! {
         notifications_unindexedProject: bool      = false,
 
         /// How many worker threads in the main loop. The default `null` means to pick automatically.
-        numThreads: Option<NumThreads> = None,
+        numThreads: Option<usize> = None,
 
         /// Expand attribute macros. Requires `#rust-analyzer.procMacro.enable#` to be set.
         procMacro_attributes_enable: bool = true,
@@ -968,6 +968,8 @@ macro_rules! try_or_def {
     };
 }
 
+type ParallelCachePrimingNumThreads = u8;
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum LinkedProject {
     ProjectManifest(ProjectManifest),
@@ -2093,22 +2095,15 @@ impl Config {
         }
     }
 
-    pub fn prime_caches_num_threads(&self) -> usize {
-        match self.cachePriming_numThreads() {
-            NumThreads::Concrete(0) | NumThreads::Physical => num_cpus::get_physical(),
-            &NumThreads::Concrete(n) => n,
-            NumThreads::Logical => num_cpus::get(),
+    pub fn prime_caches_num_threads(&self) -> u8 {
+        match *self.cachePriming_numThreads() {
+            0 => num_cpus::get_physical().try_into().unwrap_or(u8::MAX),
+            n => n,
         }
     }
 
     pub fn main_loop_num_threads(&self) -> usize {
-        match self.numThreads() {
-            Some(NumThreads::Concrete(0)) | None | Some(NumThreads::Physical) => {
-                num_cpus::get_physical()
-            }
-            &Some(NumThreads::Concrete(n)) => n,
-            Some(NumThreads::Logical) => num_cpus::get(),
-        }
+        self.numThreads().unwrap_or(num_cpus::get_physical())
     }
 
     pub fn typing_autoclose_angle(&self) -> bool {
@@ -2203,6 +2198,51 @@ macro_rules! create_bool_or_string_serde {
 create_bool_or_string_serde!(true_or_always<true, "always">);
 create_bool_or_string_serde!(false_or_never<false, "never">);
 
+macro_rules! named_unit_variant {
+    ($variant:ident) => {
+        pub(super) mod $variant {
+            pub(in super::super) fn deserialize<'de, D>(deserializer: D) -> Result<(), D::Error>
+            where
+                D: serde::Deserializer<'de>,
+            {
+                struct V;
+                impl<'de> serde::de::Visitor<'de> for V {
+                    type Value = ();
+                    fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                        f.write_str(concat!("\"", stringify!($variant), "\""))
+                    }
+                    fn visit_str<E: serde::de::Error>(self, value: &str) -> Result<Self::Value, E> {
+                        if value == stringify!($variant) {
+                            Ok(())
+                        } else {
+                            Err(E::invalid_value(serde::de::Unexpected::Str(value), &self))
+                        }
+                    }
+                }
+                deserializer.deserialize_str(V)
+            }
+            pub(in super::super) fn serialize<S>(serializer: S) -> Result<S::Ok, S::Error>
+            where
+                S: serde::Serializer,
+            {
+                serializer.serialize_str(stringify!($variant))
+            }
+        }
+    };
+}
+
+mod unit_v {
+    named_unit_variant!(all);
+    named_unit_variant!(skip_trivial);
+    named_unit_variant!(mutable);
+    named_unit_variant!(reborrow);
+    named_unit_variant!(fieldless);
+    named_unit_variant!(with_block);
+    named_unit_variant!(decimal);
+    named_unit_variant!(hexadecimal);
+    named_unit_variant!(both);
+}
+
 #[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
 #[serde(rename_all = "snake_case")]
 #[derive(Default)]
@@ -2317,10 +2357,10 @@ pub(crate) enum CallableCompletionDef {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum CargoFeaturesDef {
+    #[serde(with = "unit_v::all")]
     All,
-    #[serde(untagged)]
     Selected(Vec<String>),
 }
 
@@ -2342,27 +2382,25 @@ enum InvocationLocation {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum LifetimeElisionDef {
-    SkipTrivial,
     #[serde(with = "true_or_always")]
-    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
-    #[serde(untagged)]
     Never,
+    #[serde(with = "unit_v::skip_trivial")]
+    SkipTrivial,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum ClosureReturnTypeHintsDef {
-    WithBlock,
     #[serde(with = "true_or_always")]
-    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
-    #[serde(untagged)]
     Never,
+    #[serde(with = "unit_v::with_block")]
+    WithBlock,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -2375,39 +2413,36 @@ enum ClosureStyle {
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum ReborrowHintsDef {
-    Mutable,
     #[serde(with = "true_or_always")]
-    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
-    #[serde(untagged)]
     Never,
+    #[serde(with = "unit_v::mutable")]
+    Mutable,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum AdjustmentHintsDef {
-    Reborrow,
     #[serde(with = "true_or_always")]
-    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
-    #[serde(untagged)]
     Never,
+    #[serde(with = "unit_v::reborrow")]
+    Reborrow,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum DiscriminantHintsDef {
-    Fieldless,
     #[serde(with = "true_or_always")]
-    #[serde(untagged)]
     Always,
     #[serde(with = "false_or_never")]
-    #[serde(untagged)]
     Never,
+    #[serde(with = "unit_v::fieldless")]
+    Fieldless,
 }
 
 #[derive(Serialize, Deserialize, Debug, Clone)]
@@ -2431,11 +2466,9 @@ enum FilesWatcherDef {
 #[serde(rename_all = "snake_case")]
 enum ImportPrefixDef {
     Plain,
-    #[serde(rename = "self")]
-    #[serde(alias = "by_self")]
+    #[serde(alias = "self")]
     BySelf,
-    #[serde(rename = "crate")]
-    #[serde(alias = "by_crate")]
+    #[serde(alias = "crate")]
     ByCrate,
 }
 
@@ -2462,9 +2495,13 @@ enum WorkspaceSymbolSearchKindDef {
 
 #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
 #[serde(rename_all = "snake_case")]
+#[serde(untagged)]
 enum MemoryLayoutHoverRenderKindDef {
+    #[serde(with = "unit_v::decimal")]
     Decimal,
+    #[serde(with = "unit_v::hexadecimal")]
     Hexadecimal,
+    #[serde(with = "unit_v::both")]
     Both,
 }
 
@@ -2487,15 +2524,6 @@ pub enum TargetDirectory {
     Directory(Utf8PathBuf),
 }
 
-#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
-#[serde(rename_all = "snake_case")]
-pub enum NumThreads {
-    Physical,
-    Logical,
-    #[serde(untagged)]
-    Concrete(usize),
-}
-
 macro_rules! _default_val {
     (@verbatim: $s:literal, $ty:ty) => {{
         let default_: $ty = serde_json::from_str(&$s).unwrap();
@@ -2748,10 +2776,6 @@ impl FullConfigInput {
         ClientConfigInput::schema_fields(&mut fields);
         fields.sort_by_key(|&(x, ..)| x);
         fields
-            .iter()
-            .tuple_windows()
-            .for_each(|(a, b)| assert!(a.0 != b.0, "{a:?} duplicate field"));
-        fields
     }
 
     fn json_schema() -> serde_json::Value {
@@ -3010,6 +3034,11 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Search for all symbols kinds."
             ],
         },
+        "ParallelCachePrimingNumThreads" => set! {
+            "type": "number",
+            "minimum": 0,
+            "maximum": 255
+        },
         "LifetimeElisionDef" => set! {
             "type": "string",
             "enum": [
@@ -3231,44 +3260,7 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 },
             ],
         },
-        "NumThreads" => set! {
-            "anyOf": [
-                {
-                    "type": "number",
-                    "minimum": 0,
-                    "maximum": 255
-                },
-                {
-                    "type": "string",
-                    "enum": ["physical", "logical", ],
-                    "enumDescriptions": [
-                        "Use the number of physical cores",
-                        "Use the number of logical cores",
-                    ],
-                },
-            ],
-        },
-        "Option<NumThreads>" => set! {
-            "anyOf": [
-                {
-                    "type": "null"
-                },
-                {
-                    "type": "number",
-                    "minimum": 0,
-                    "maximum": 255
-                },
-                {
-                    "type": "string",
-                    "enum": ["physical", "logical", ],
-                    "enumDescriptions": [
-                        "Use the number of physical cores",
-                        "Use the number of logical cores",
-                    ],
-                },
-            ],
-        },
-        _ => panic!("missing entry for {ty}: {default} (field {field})"),
+        _ => panic!("missing entry for {ty}: {default}"),
     }
 
     map.into()
@@ -3349,7 +3341,7 @@ mod tests {
             .trim_start_matches('[')
             .trim_end_matches(']')
             .replace("  ", "    ")
-            .replace('\n', "\n        ")
+            .replace('\n', "\n            ")
             .trim_start_matches('\n')
             .trim_end()
             .to_owned();
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 717d8a632c..3d5f525aaf 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -18,7 +18,10 @@ use parking_lot::{
     RwLockWriteGuard,
 };
 use proc_macro_api::ProcMacroServer;
-use project_model::{ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, WorkspaceBuildScripts};
+use project_model::{
+    CargoWorkspace, ManifestPath, ProjectWorkspace, ProjectWorkspaceKind, Target,
+    WorkspaceBuildScripts,
+};
 use rustc_hash::{FxHashMap, FxHashSet};
 use tracing::{span, Level};
 use triomphe::Arc;
@@ -37,7 +40,6 @@ use crate::{
     mem_docs::MemDocs,
     op_queue::OpQueue,
     reload,
-    target_spec::{CargoTargetSpec, ProjectJsonTargetSpec, TargetSpec},
     task_pool::{TaskPool, TaskQueue},
 };
 
@@ -554,52 +556,21 @@ impl GlobalStateSnapshot {
         self.vfs_read().file_path(file_id).clone()
     }
 
-    pub(crate) fn target_spec_for_crate(&self, crate_id: CrateId) -> Option<TargetSpec> {
+    pub(crate) fn cargo_target_for_crate_root(
+        &self,
+        crate_id: CrateId,
+    ) -> Option<(&CargoWorkspace, Target)> {
         let file_id = self.analysis.crate_root(crate_id).ok()?;
         let path = self.vfs_read().file_path(file_id).clone();
         let path = path.as_path()?;
-
-        for workspace in self.workspaces.iter() {
-            match &workspace.kind {
-                ProjectWorkspaceKind::Cargo { cargo, .. }
-                | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
-                    let Some(target_idx) = cargo.target_by_root(path) else {
-                        continue;
-                    };
-
-                    let target_data = &cargo[target_idx];
-                    let package_data = &cargo[target_data.package];
-
-                    return Some(TargetSpec::Cargo(CargoTargetSpec {
-                        workspace_root: cargo.workspace_root().to_path_buf(),
-                        cargo_toml: package_data.manifest.clone(),
-                        crate_id,
-                        package: cargo.package_flag(package_data),
-                        target: target_data.name.clone(),
-                        target_kind: target_data.kind,
-                        required_features: target_data.required_features.clone(),
-                        features: package_data.features.keys().cloned().collect(),
-                    }));
-                }
-                ProjectWorkspaceKind::Json(project) => {
-                    let Some(krate) = project.crate_by_root(path) else {
-                        continue;
-                    };
-                    let Some(build) = krate.build else {
-                        continue;
-                    };
-
-                    return Some(TargetSpec::ProjectJson(ProjectJsonTargetSpec {
-                        label: build.label,
-                        target_kind: build.target_kind,
-                        shell_runnables: project.runnables().to_owned(),
-                    }));
-                }
-                ProjectWorkspaceKind::DetachedFile { .. } => {}
-            };
-        }
-
-        None
+        self.workspaces.iter().find_map(|ws| match &ws.kind {
+            ProjectWorkspaceKind::Cargo { cargo, .. }
+            | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, _)), .. } => {
+                cargo.target_by_root(path).map(|it| (cargo, it))
+            }
+            ProjectWorkspaceKind::Json { .. } => None,
+            ProjectWorkspaceKind::DetachedFile { .. } => None,
+        })
     }
 
     pub(crate) fn file_exists(&self, file_id: FileId) -> bool {
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 8e39b15da3..0789dd6462 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -35,6 +35,7 @@ use triomphe::Arc;
 use vfs::{AbsPath, AbsPathBuf, FileId, VfsPath};
 
 use crate::{
+    cargo_target_spec::CargoTargetSpec,
     config::{Config, RustfmtConfig, WorkspaceSymbolConfig},
     diff::diff,
     global_state::{GlobalState, GlobalStateSnapshot},
@@ -50,7 +51,6 @@ use crate::{
         self, CrateInfoResult, ExternalDocsPair, ExternalDocsResponse, FetchDependencyListParams,
         FetchDependencyListResult, PositionOrRange, ViewCrateGraphParams, WorkspaceSymbolParams,
     },
-    target_spec::TargetSpec,
 };
 
 pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow::Result<()> {
@@ -790,9 +790,9 @@ pub(crate) fn handle_parent_module(
             Some(&crate_id) => crate_id,
             None => return Ok(None),
         };
-        let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
-            Some(TargetSpec::Cargo(it)) => it,
-            Some(TargetSpec::ProjectJson(_)) | None => return Ok(None),
+        let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
+            Some(it) => it,
+            None => return Ok(None),
         };
 
         if snap.analysis.crate_root(crate_id)? == file_id {
@@ -823,7 +823,7 @@ pub(crate) fn handle_runnables(
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
     let line_index = snap.file_line_index(file_id)?;
     let offset = params.position.and_then(|it| from_proto::offset(&line_index, it).ok());
-    let target_spec = TargetSpec::for_file(&snap, file_id)?;
+    let cargo_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 
     let expect_test = match offset {
         Some(offset) => {
@@ -840,24 +840,21 @@ pub(crate) fn handle_runnables(
         if should_skip_for_offset(&runnable, offset) {
             continue;
         }
-        if should_skip_target(&runnable, target_spec.as_ref()) {
+        if should_skip_target(&runnable, cargo_spec.as_ref()) {
             continue;
         }
-        if let Some(mut runnable) = to_proto::runnable(&snap, runnable)? {
-            if expect_test {
-                if let lsp_ext::RunnableArgs::Cargo(r) = &mut runnable.args {
-                    runnable.label = format!("{} + expect", runnable.label);
-                    r.expect_test = Some(true);
-                }
-            }
-            res.push(runnable);
+        let mut runnable = to_proto::runnable(&snap, runnable)?;
+        if expect_test {
+            runnable.label = format!("{} + expect", runnable.label);
+            runnable.args.expect_test = Some(true);
         }
+        res.push(runnable);
     }
 
     // Add `cargo check` and `cargo test` for all targets of the whole package
     let config = snap.config.runnables();
-    match target_spec {
-        Some(TargetSpec::Cargo(spec)) => {
+    match cargo_spec {
+        Some(spec) => {
             let is_crate_no_std = snap.analysis.is_crate_no_std(spec.crate_id)?;
             for cmd in ["check", "run", "test"] {
                 if cmd == "run" && spec.target_kind != TargetKind::Bin {
@@ -882,7 +879,7 @@ pub(crate) fn handle_runnables(
                     ),
                     location: None,
                     kind: lsp_ext::RunnableKind::Cargo,
-                    args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
+                    args: lsp_ext::CargoRunnable {
                         workspace_root: Some(spec.workspace_root.clone().into()),
                         cwd: Some(cwd.into()),
                         override_cargo: config.override_cargo.clone(),
@@ -890,18 +887,17 @@ pub(crate) fn handle_runnables(
                         cargo_extra_args: config.cargo_extra_args.clone(),
                         executable_args: Vec::new(),
                         expect_test: None,
-                    }),
+                    },
                 })
             }
         }
-        Some(TargetSpec::ProjectJson(_)) => {}
         None => {
             if !snap.config.linked_or_discovered_projects().is_empty() {
                 res.push(lsp_ext::Runnable {
                     label: "cargo check --workspace".to_owned(),
                     location: None,
                     kind: lsp_ext::RunnableKind::Cargo,
-                    args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
+                    args: lsp_ext::CargoRunnable {
                         workspace_root: None,
                         cwd: None,
                         override_cargo: config.override_cargo,
@@ -909,7 +905,7 @@ pub(crate) fn handle_runnables(
                         cargo_extra_args: config.cargo_extra_args,
                         executable_args: Vec::new(),
                         expect_test: None,
-                    }),
+                    },
                 });
             }
         }
@@ -935,7 +931,7 @@ pub(crate) fn handle_related_tests(
     let tests = snap.analysis.related_tests(position, None)?;
     let mut res = Vec::new();
     for it in tests {
-        if let Ok(Some(runnable)) = to_proto::runnable(&snap, it) {
+        if let Ok(runnable) = to_proto::runnable(&snap, it) {
             res.push(lsp_ext::TestInfo { runnable })
         }
     }
@@ -1401,14 +1397,14 @@ pub(crate) fn handle_code_lens(
     }
 
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
-    let target_spec = TargetSpec::for_file(&snap, file_id)?;
+    let cargo_target_spec = CargoTargetSpec::for_file(&snap, file_id)?;
 
     let annotations = snap.analysis.annotations(
         &AnnotationConfig {
-            binary_target: target_spec
+            binary_target: cargo_target_spec
                 .map(|spec| {
                     matches!(
-                        spec.target_kind(),
+                        spec.target_kind,
                         TargetKind::Bin | TargetKind::Example | TargetKind::Test
                     )
                 })
@@ -1828,9 +1824,9 @@ pub(crate) fn handle_open_cargo_toml(
     let _p = tracing::info_span!("handle_open_cargo_toml").entered();
     let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
 
-    let cargo_spec = match TargetSpec::for_file(&snap, file_id)? {
-        Some(TargetSpec::Cargo(it)) => it,
-        Some(TargetSpec::ProjectJson(_)) | None => return Ok(None),
+    let cargo_spec = match CargoTargetSpec::for_file(&snap, file_id)? {
+        Some(it) => it,
+        None => return Ok(None),
     };
 
     let cargo_toml_url = to_proto::url_from_abs_path(&cargo_spec.cargo_toml);
@@ -1958,8 +1954,8 @@ fn runnable_action_links(
         return None;
     }
 
-    let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
-    if should_skip_target(&runnable, target_spec.as_ref()) {
+    let cargo_spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id).ok()?;
+    if should_skip_target(&runnable, cargo_spec.as_ref()) {
         return None;
     }
 
@@ -1969,7 +1965,7 @@ fn runnable_action_links(
     }
 
     let title = runnable.title();
-    let r = to_proto::runnable(snap, runnable).ok()??;
+    let r = to_proto::runnable(snap, runnable).ok()?;
 
     let mut group = lsp_ext::CommandLinkGroup::default();
 
@@ -2024,13 +2020,13 @@ fn prepare_hover_actions(
         .collect()
 }
 
-fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&TargetSpec>) -> bool {
+fn should_skip_target(runnable: &Runnable, cargo_spec: Option<&CargoTargetSpec>) -> bool {
     match runnable.kind {
         RunnableKind::Bin => {
             // Do not suggest binary run on other target than binary
             match &cargo_spec {
                 Some(spec) => !matches!(
-                    spec.target_kind(),
+                    spec.target_kind,
                     TargetKind::Bin | TargetKind::Example | TargetKind::Test
                 ),
                 None => true,
@@ -2107,9 +2103,9 @@ fn run_rustfmt(
         }
         RustfmtConfig::CustomCommand { command, args } => {
             let cmd = Utf8PathBuf::from(&command);
-            let target_spec = TargetSpec::for_file(snap, file_id)?;
-            let mut cmd = match target_spec {
-                Some(TargetSpec::Cargo(spec)) => {
+            let workspace = CargoTargetSpec::for_file(snap, file_id)?;
+            let mut cmd = match workspace {
+                Some(spec) => {
                     // approach: if the command name contains a path separator, join it with the workspace root.
                     // however, if the path is absolute, joining will result in the absolute path being preserved.
                     // as a fallback, rely on $PATH-based discovery.
@@ -2122,7 +2118,7 @@ fn run_rustfmt(
                     };
                     process::Command::new(cmd_path)
                 }
-                _ => process::Command::new(cmd),
+                None => process::Command::new(cmd),
             };
 
             cmd.envs(snap.config.extra_env());
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index a398e98f09..b3c11d0156 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -14,6 +14,7 @@
 pub mod cli;
 
 mod caps;
+mod cargo_target_spec;
 mod diagnostics;
 mod diff;
 mod dispatch;
@@ -23,7 +24,6 @@ mod main_loop;
 mod mem_docs;
 mod op_queue;
 mod reload;
-mod target_spec;
 mod task_pool;
 mod version;
 
diff --git a/crates/rust-analyzer/src/lsp/ext.rs b/crates/rust-analyzer/src/lsp/ext.rs
index b82ba44190..4da9054d13 100644
--- a/crates/rust-analyzer/src/lsp/ext.rs
+++ b/crates/rust-analyzer/src/lsp/ext.rs
@@ -3,6 +3,7 @@
 #![allow(clippy::disallowed_types)]
 
 use std::ops;
+use std::path::PathBuf;
 
 use ide_db::line_index::WideEncoding;
 use lsp_types::request::Request;
@@ -11,7 +12,6 @@ use lsp_types::{
     PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
 };
 use lsp_types::{PositionEncodingKind, Url};
-use paths::Utf8PathBuf;
 use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 
@@ -439,33 +439,24 @@ pub struct Runnable {
     #[serde(skip_serializing_if = "Option::is_none")]
     pub location: Option<lsp_types::LocationLink>,
     pub kind: RunnableKind,
-    pub args: RunnableArgs,
-}
-
-#[derive(Deserialize, Serialize, Debug)]
-#[serde(rename_all = "camelCase")]
-#[serde(untagged)]
-pub enum RunnableArgs {
-    Cargo(CargoRunnableArgs),
-    Shell(ShellRunnableArgs),
+    pub args: CargoRunnable,
 }
 
 #[derive(Serialize, Deserialize, Debug)]
 #[serde(rename_all = "lowercase")]
 pub enum RunnableKind {
     Cargo,
-    Shell,
 }
 
 #[derive(Deserialize, Serialize, Debug)]
 #[serde(rename_all = "camelCase")]
-pub struct CargoRunnableArgs {
+pub struct CargoRunnable {
     // command to be executed instead of cargo
     pub override_cargo: Option<String>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub workspace_root: Option<Utf8PathBuf>,
+    pub workspace_root: Option<PathBuf>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub cwd: Option<Utf8PathBuf>,
+    pub cwd: Option<PathBuf>,
     // command, --package and --lib stuff
     pub cargo_args: Vec<String>,
     // user-specified additional cargo args, like `--release`.
@@ -476,14 +467,6 @@ pub struct CargoRunnableArgs {
     pub expect_test: Option<bool>,
 }
 
-#[derive(Deserialize, Serialize, Debug)]
-#[serde(rename_all = "camelCase")]
-pub struct ShellRunnableArgs {
-    pub program: String,
-    pub args: Vec<String>,
-    pub cwd: Utf8PathBuf,
-}
-
 pub enum RelatedTests {}
 
 impl Request for RelatedTests {
diff --git a/crates/rust-analyzer/src/lsp/to_proto.rs b/crates/rust-analyzer/src/lsp/to_proto.rs
index db5f666a5b..86368c9eea 100644
--- a/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -21,17 +21,16 @@ use serde_json::to_value;
 use vfs::AbsPath;
 
 use crate::{
+    cargo_target_spec::CargoTargetSpec,
     config::{CallInfoConfig, Config},
     global_state::GlobalStateSnapshot,
     line_index::{LineEndings, LineIndex, PositionEncoding},
     lsp::{
-        ext::ShellRunnableArgs,
         semantic_tokens::{self, standard_fallback_type},
         utils::invalid_params_error,
         LspError,
     },
     lsp_ext::{self, SnippetTextEdit},
-    target_spec::{CargoTargetSpec, TargetSpec},
 };
 
 pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@@ -1357,90 +1356,34 @@ pub(crate) fn code_action(
 pub(crate) fn runnable(
     snap: &GlobalStateSnapshot,
     runnable: Runnable,
-) -> Cancellable<Option<lsp_ext::Runnable>> {
+) -> Cancellable<lsp_ext::Runnable> {
     let config = snap.config.runnables();
-    let target_spec = TargetSpec::for_file(snap, runnable.nav.file_id)?;
-
-    match target_spec {
-        Some(TargetSpec::Cargo(spec)) => {
-            let workspace_root = spec.workspace_root.clone();
-
-            let target = spec.target.clone();
-
-            let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(
-                snap,
-                Some(spec.clone()),
-                &runnable.kind,
-                &runnable.cfg,
-            );
-
-            let cwd = match runnable.kind {
-                ide::RunnableKind::Bin { .. } => workspace_root.clone(),
-                _ => spec.cargo_toml.parent().to_owned(),
-            };
+    let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?;
+    let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone());
+    let cwd = match runnable.kind {
+        ide::RunnableKind::Bin { .. } => workspace_root.clone().map(|it| it.into()),
+        _ => spec.as_ref().map(|it| it.cargo_toml.parent().into()),
+    };
+    let target = spec.as_ref().map(|s| s.target.as_str());
+    let label = runnable.label(target);
+    let (cargo_args, executable_args) =
+        CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg);
+    let location = location_link(snap, None, runnable.nav)?;
 
-            let label = runnable.label(Some(&target));
-            let location = location_link(snap, None, runnable.nav)?;
-
-            Ok(Some(lsp_ext::Runnable {
-                label,
-                location: Some(location),
-                kind: lsp_ext::RunnableKind::Cargo,
-                args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
-                    workspace_root: Some(workspace_root.into()),
-                    override_cargo: config.override_cargo,
-                    cargo_args,
-                    cwd: Some(cwd.into()),
-                    cargo_extra_args: config.cargo_extra_args,
-                    executable_args,
-                    expect_test: None,
-                }),
-            }))
-        }
-        Some(TargetSpec::ProjectJson(spec)) => {
-            let label = runnable.label(Some(&spec.label));
-            let location = location_link(snap, None, runnable.nav)?;
-
-            match spec.runnable_args(&runnable.kind) {
-                Some(json_shell_runnable_args) => {
-                    let runnable_args = ShellRunnableArgs {
-                        program: json_shell_runnable_args.program,
-                        args: json_shell_runnable_args.args,
-                        cwd: json_shell_runnable_args.cwd,
-                    };
-                    Ok(Some(lsp_ext::Runnable {
-                        label,
-                        location: Some(location),
-                        kind: lsp_ext::RunnableKind::Shell,
-                        args: lsp_ext::RunnableArgs::Shell(runnable_args),
-                    }))
-                }
-                None => Ok(None),
-            }
-        }
-        None => {
-            let (cargo_args, executable_args) =
-                CargoTargetSpec::runnable_args(snap, None, &runnable.kind, &runnable.cfg);
-
-            let label = runnable.label(None);
-            let location = location_link(snap, None, runnable.nav)?;
-
-            Ok(Some(lsp_ext::Runnable {
-                label,
-                location: Some(location),
-                kind: lsp_ext::RunnableKind::Cargo,
-                args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
-                    workspace_root: None,
-                    override_cargo: config.override_cargo,
-                    cargo_args,
-                    cwd: None,
-                    cargo_extra_args: config.cargo_extra_args,
-                    executable_args,
-                    expect_test: None,
-                }),
-            }))
-        }
-    }
+    Ok(lsp_ext::Runnable {
+        label,
+        location: Some(location),
+        kind: lsp_ext::RunnableKind::Cargo,
+        args: lsp_ext::CargoRunnable {
+            workspace_root: workspace_root.map(|it| it.into()),
+            cwd,
+            override_cargo: config.override_cargo,
+            cargo_args,
+            cargo_extra_args: config.cargo_extra_args,
+            executable_args,
+            expect_test: None,
+        },
+    })
 }
 
 pub(crate) fn code_lens(
@@ -1464,37 +1407,33 @@ pub(crate) fn code_lens(
             };
             let r = runnable(snap, run)?;
 
-            if let Some(r) = r {
-                let has_root = match &r.args {
-                    lsp_ext::RunnableArgs::Cargo(c) => c.workspace_root.is_some(),
-                    lsp_ext::RunnableArgs::Shell(_) => true,
-                };
-
-                let lens_config = snap.config.lens();
-                if lens_config.run && client_commands_config.run_single && has_root {
-                    let command = command::run_single(&r, &title);
-                    acc.push(lsp_types::CodeLens {
-                        range: annotation_range,
-                        command: Some(command),
-                        data: None,
-                    })
-                }
-                if lens_config.debug && can_debug && client_commands_config.debug_single {
-                    let command = command::debug_single(&r);
-                    acc.push(lsp_types::CodeLens {
-                        range: annotation_range,
-                        command: Some(command),
-                        data: None,
-                    })
-                }
-                if lens_config.interpret {
-                    let command = command::interpret_single(&r);
-                    acc.push(lsp_types::CodeLens {
-                        range: annotation_range,
-                        command: Some(command),
-                        data: None,
-                    })
-                }
+            let lens_config = snap.config.lens();
+            if lens_config.run
+                && client_commands_config.run_single
+                && r.args.workspace_root.is_some()
+            {
+                let command = command::run_single(&r, &title);
+                acc.push(lsp_types::CodeLens {
+                    range: annotation_range,
+                    command: Some(command),
+                    data: None,
+                })
+            }
+            if lens_config.debug && can_debug && client_commands_config.debug_single {
+                let command = command::debug_single(&r);
+                acc.push(lsp_types::CodeLens {
+                    range: annotation_range,
+                    command: Some(command),
+                    data: None,
+                })
+            }
+            if lens_config.interpret {
+                let command = command::interpret_single(&r);
+                acc.push(lsp_types::CodeLens {
+                    range: annotation_range,
+                    command: Some(command),
+                    data: None,
+                })
             }
         }
         AnnotationKind::HasImpls { pos, data } => {
@@ -1599,8 +1538,12 @@ pub(crate) fn test_item(
         id: test_item.id,
         label: test_item.label,
         kind: match test_item.kind {
-            ide::TestItemKind::Crate(id) => match snap.target_spec_for_crate(id) {
-                Some(target_spec) => match target_spec.target_kind() {
+            ide::TestItemKind::Crate(id) => 'b: {
+                let Some((cargo_ws, target)) = snap.cargo_target_for_crate_root(id) else {
+                    break 'b lsp_ext::TestItemKind::Package;
+                };
+                let target = &cargo_ws[target];
+                match target.kind {
                     project_model::TargetKind::Bin
                     | project_model::TargetKind::Lib { .. }
                     | project_model::TargetKind::Example
@@ -1609,9 +1552,8 @@ pub(crate) fn test_item(
                     project_model::TargetKind::Test => lsp_ext::TestItemKind::Test,
                     // benches are not tests needed to be shown in the test explorer
                     project_model::TargetKind::Bench => return None,
-                },
-                None => lsp_ext::TestItemKind::Package,
-            },
+                }
+            }
             ide::TestItemKind::Module => lsp_ext::TestItemKind::Module,
             ide::TestItemKind::Function => lsp_ext::TestItemKind::Test,
         },
@@ -1624,7 +1566,7 @@ pub(crate) fn test_item(
             .file
             .map(|f| lsp_types::TextDocumentIdentifier { uri: url(snap, f) }),
         range: line_index.and_then(|l| Some(range(l, test_item.text_range?))),
-        runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()).flatten(),
+        runnable: test_item.runnable.and_then(|r| runnable(snap, r).ok()),
     })
 }
 
diff --git a/crates/span/src/lib.rs b/crates/span/src/lib.rs
index bbaf1b2a6d..74693a270b 100644
--- a/crates/span/src/lib.rs
+++ b/crates/span/src/lib.rs
@@ -86,6 +86,15 @@ impl<Ctx: Copy> SpanData<Ctx> {
     }
 }
 
+impl Span {
+    #[deprecated = "dummy spans will panic if surfaced incorrectly, as such they should be replaced appropriately"]
+    pub const DUMMY: Self = Self {
+        range: TextRange::empty(TextSize::new(0)),
+        anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID },
+        ctx: SyntaxContextId::ROOT,
+    };
+}
+
 impl fmt::Display for Span {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         fmt::Debug::fmt(&self.anchor.file_id.index(), f)?;
@@ -169,8 +178,6 @@ impl salsa::InternKey for MacroCallId {
 }
 
 impl MacroCallId {
-    pub const MAX_ID: u32 = 0x7fff_ffff;
-
     pub fn as_file(self) -> HirFileId {
         MacroFileId { macro_call_id: self }.into()
     }
diff --git a/crates/vfs/src/lib.rs b/crates/vfs/src/lib.rs
index 18c8699dd4..eab66f10a9 100644
--- a/crates/vfs/src/lib.rs
+++ b/crates/vfs/src/lib.rs
@@ -69,6 +69,9 @@ pub struct FileId(u32);
 // pub struct FileId(NonMaxU32);
 
 impl FileId {
+    /// Think twice about using this outside of tests. If this ends up in a wrong place it will cause panics!
+    // FIXME: To be removed once we get rid of all `SpanData::DUMMY` usages.
+    pub const BOGUS: FileId = FileId(0xe4e4e);
     pub const MAX_FILE_ID: u32 = 0x7fff_ffff;
 
     #[inline]
diff --git a/docs/dev/lsp-extensions.md b/docs/dev/lsp-extensions.md
index 695fec7e8e..100662f4ce 100644
--- a/docs/dev/lsp-extensions.md
+++ b/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 8e6e340f2899b5e9
+lsp/ext.rs hash: a85ec97f07c6a2e3
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
@@ -372,7 +372,7 @@ interface Runnable {
 }
 ```
 
-rust-analyzer supports two `kind`s of runnables, `"cargo"` and `"shell"`. The `args` for `"cargo"` look like this:
+rust-analyzer supports only one `kind`, `"cargo"`. The `args` for `"cargo"` look like this:
 
 ```typescript
 {
@@ -386,17 +386,6 @@ rust-analyzer supports two `kind`s of runnables, `"cargo"` and `"shell"`. The `a
 }
 ```
 
-The args for `"shell"` look like this:
-
-```typescript
-{
-    kind: string;
-    program: string;
-    args: string[];
-    cwd: string;
-}
-```
-
 ## Test explorer
 
 **Experimental Client Capability:** `{ "testExplorer": boolean }`
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 14aae91741..8993a46d2b 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -19,7 +19,7 @@ Term search fuel in "units of work" for assists (Defaults to 400).
 --
 Warm up caches on project load.
 --
-[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `"physical"`)::
+[[rust-analyzer.cachePriming.numThreads]]rust-analyzer.cachePriming.numThreads (default: `0`)::
 +
 --
 How many worker threads to handle priming caches. The default `0` means to pick automatically.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 7de7576317..bd8b0e9c4e 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -1087,12 +1087,12 @@
             }
         },
         "node_modules/braces": {
-            "version": "3.0.3",
-            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
-            "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+            "version": "3.0.2",
+            "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+            "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
             "dev": true,
             "dependencies": {
-                "fill-range": "^7.1.1"
+                "fill-range": "^7.0.1"
             },
             "engines": {
                 "node": ">=8"
@@ -2243,9 +2243,9 @@
             }
         },
         "node_modules/fill-range": {
-            "version": "7.1.1",
-            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
-            "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+            "version": "7.0.1",
+            "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+            "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
             "dev": true,
             "dependencies": {
                 "to-regex-range": "^5.0.1"
diff --git a/editors/code/package.json b/editors/code/package.json
index b447106d99..cd11b56d15 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -609,25 +609,10 @@
                 "properties": {
                     "rust-analyzer.cachePriming.numThreads": {
                         "markdownDescription": "How many worker threads to handle priming caches. The default `0` means to pick automatically.",
-                        "default": "physical",
-                        "anyOf": [
-                            {
-                                "type": "number",
-                                "minimum": 0,
-                                "maximum": 255
-                            },
-                            {
-                                "type": "string",
-                                "enum": [
-                                    "physical",
-                                    "logical"
-                                ],
-                                "enumDescriptions": [
-                                    "Use the number of physical cores",
-                                    "Use the number of logical cores"
-                                ]
-                            }
-                        ]
+                        "default": 0,
+                        "type": "number",
+                        "minimum": 0,
+                        "maximum": 255
                     }
                 }
             },
@@ -2240,27 +2225,11 @@
                     "rust-analyzer.numThreads": {
                         "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.",
                         "default": null,
-                        "anyOf": [
-                            {
-                                "type": "null"
-                            },
-                            {
-                                "type": "number",
-                                "minimum": 0,
-                                "maximum": 255
-                            },
-                            {
-                                "type": "string",
-                                "enum": [
-                                    "physical",
-                                    "logical"
-                                ],
-                                "enumDescriptions": [
-                                    "Use the number of physical cores",
-                                    "Use the number of logical cores"
-                                ]
-                            }
-                        ]
+                        "type": [
+                            "null",
+                            "integer"
+                        ],
+                        "minimum": 0
                     }
                 }
             },
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 5cec2c61a5..9f4930c94a 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -9,11 +9,10 @@ import {
     applySnippetTextEdits,
     type SnippetTextDocumentEdit,
 } from "./snippets";
-import { type RunnableQuickPick, selectRunnable, createTask, createCargoArgs } from "./run";
+import { type RunnableQuickPick, selectRunnable, createTask, createArgs } from "./run";
 import { AstInspector } from "./ast_inspector";
 import {
     isRustDocument,
-    isCargoRunnableArgs,
     isCargoTomlDocument,
     sleep,
     isRustEditor,
@@ -1155,8 +1154,8 @@ export function copyRunCommandLine(ctx: CtxInit) {
     let prevRunnable: RunnableQuickPick | undefined;
     return async () => {
         const item = await selectRunnable(ctx, prevRunnable);
-        if (!item || !isCargoRunnableArgs(item.runnable.args)) return;
-        const args = createCargoArgs(item.runnable.args);
+        if (!item) return;
+        const args = createArgs(item.runnable);
         const commandLine = ["cargo", ...args].join(" ");
         await vscode.env.clipboard.writeText(commandLine);
         await vscode.window.showInformationMessage("Cargo invocation copied to the clipboard.");
diff --git a/editors/code/src/debug.ts b/editors/code/src/debug.ts
index eef2f6f4ee..4b96e4d5c8 100644
--- a/editors/code/src/debug.ts
+++ b/editors/code/src/debug.ts
@@ -7,12 +7,10 @@ import { Cargo, getRustcId, getSysroot } from "./toolchain";
 import type { Ctx } from "./ctx";
 import { prepareEnv } from "./run";
 import { unwrapUndefinable } from "./undefinable";
-import { isCargoRunnableArgs } from "./util";
 
 const debugOutput = vscode.window.createOutputChannel("Debug");
 type DebugConfigProvider = (
-    runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
+    config: ra.Runnable,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -78,11 +76,6 @@ async function getDebugConfiguration(
     ctx: Ctx,
     runnable: ra.Runnable,
 ): Promise<vscode.DebugConfiguration | undefined> {
-    if (!isCargoRunnableArgs(runnable.args)) {
-        return;
-    }
-    const runnableArgs: ra.CargoRunnableArgs = runnable.args;
-
     const editor = ctx.activeRustEditor;
     if (!editor) return;
 
@@ -126,9 +119,9 @@ async function getDebugConfiguration(
     const isMultiFolderWorkspace = workspaceFolders.length > 1;
     const firstWorkspace = workspaceFolders[0];
     const maybeWorkspace =
-        !isMultiFolderWorkspace || !runnableArgs.workspaceRoot
+        !isMultiFolderWorkspace || !runnable.args.workspaceRoot
             ? firstWorkspace
-            : workspaceFolders.find((w) => runnableArgs.workspaceRoot?.includes(w.uri.fsPath)) ||
+            : workspaceFolders.find((w) => runnable.args.workspaceRoot?.includes(w.uri.fsPath)) ||
               firstWorkspace;
 
     const workspace = unwrapUndefinable(maybeWorkspace);
@@ -139,8 +132,8 @@ async function getDebugConfiguration(
         return path.normalize(p).replace(wsFolder, "${workspaceFolder" + workspaceQualifier + "}");
     }
 
-    const env = prepareEnv(runnable.label, runnableArgs, ctx.config.runnablesExtraEnv);
-    const executable = await getDebugExecutable(runnableArgs, env);
+    const env = prepareEnv(runnable, ctx.config.runnablesExtraEnv);
+    const executable = await getDebugExecutable(runnable, env);
     let sourceFileMap = debugOptions.sourceFileMap;
     if (sourceFileMap === "auto") {
         // let's try to use the default toolchain
@@ -154,7 +147,7 @@ async function getDebugConfiguration(
     }
 
     const provider = unwrapUndefinable(knownEngines[debugEngine.id]);
-    const debugConfig = provider(runnable, runnableArgs, simplifyPath(executable), env);
+    const debugConfig = provider(runnable, simplifyPath(executable), env, sourceFileMap);
     if (debugConfig.type in debugOptions.engineSettings) {
         const settingsMap = (debugOptions.engineSettings as any)[debugConfig.type];
         for (var key in settingsMap) {
@@ -177,11 +170,11 @@ async function getDebugConfiguration(
 }
 
 async function getDebugExecutable(
-    runnableArgs: ra.CargoRunnableArgs,
+    runnable: ra.Runnable,
     env: Record<string, string>,
 ): Promise<string> {
-    const cargo = new Cargo(runnableArgs.workspaceRoot || ".", debugOutput, env);
-    const executable = await cargo.executableFromArgs(runnableArgs.cargoArgs);
+    const cargo = new Cargo(runnable.args.workspaceRoot || ".", debugOutput, env);
+    const executable = await cargo.executableFromArgs(runnable.args.cargoArgs);
 
     // if we are here, there were no compilation errors.
     return executable;
@@ -189,7 +182,6 @@ async function getDebugExecutable(
 
 function getCCppDebugConfig(
     runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -199,8 +191,8 @@ function getCCppDebugConfig(
         request: "launch",
         name: runnable.label,
         program: executable,
-        args: runnableArgs.executableArgs,
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
+        args: runnable.args.executableArgs,
+        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
         sourceFileMap,
         environment: Object.entries(env).map((entry) => ({
             name: entry[0],
@@ -215,7 +207,6 @@ function getCCppDebugConfig(
 
 function getCodeLldbDebugConfig(
     runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     sourceFileMap?: Record<string, string>,
@@ -225,8 +216,8 @@ function getCodeLldbDebugConfig(
         request: "launch",
         name: runnable.label,
         program: executable,
-        args: runnableArgs.executableArgs,
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
+        args: runnable.args.executableArgs,
+        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
         sourceMap: sourceFileMap,
         sourceLanguages: ["rust"],
         env,
@@ -235,7 +226,6 @@ function getCodeLldbDebugConfig(
 
 function getNativeDebugConfig(
     runnable: ra.Runnable,
-    runnableArgs: ra.CargoRunnableArgs,
     executable: string,
     env: Record<string, string>,
     _sourceFileMap?: Record<string, string>,
@@ -246,8 +236,8 @@ function getNativeDebugConfig(
         name: runnable.label,
         target: executable,
         // See https://github.com/WebFreak001/code-debug/issues/359
-        arguments: quote(runnableArgs.executableArgs),
-        cwd: runnable.args.cwd || runnableArgs.workspaceRoot || ".",
+        arguments: quote(runnable.args.executableArgs),
+        cwd: runnable.args.cwd || runnable.args.workspaceRoot || ".",
         env,
         valuesFormatting: "prettyPrinters",
     };
diff --git a/editors/code/src/lsp_ext.ts b/editors/code/src/lsp_ext.ts
index 2462f06f18..8e48aeef15 100644
--- a/editors/code/src/lsp_ext.ts
+++ b/editors/code/src/lsp_ext.ts
@@ -223,27 +223,17 @@ export type OpenCargoTomlParams = {
 export type Runnable = {
     label: string;
     location?: lc.LocationLink;
-    kind: "cargo" | "shell";
-    args: CargoRunnableArgs | ShellRunnableArgs;
+    kind: "cargo";
+    args: {
+        workspaceRoot?: string;
+        cwd?: string;
+        cargoArgs: string[];
+        cargoExtraArgs: string[];
+        executableArgs: string[];
+        expectTest?: boolean;
+        overrideCargo?: string;
+    };
 };
-
-export type ShellRunnableArgs = {
-    kind: string;
-    program: string;
-    args: string[];
-    cwd: string;
-};
-
-export type CargoRunnableArgs = {
-    workspaceRoot?: string;
-    cargoArgs: string[];
-    cwd: string;
-    cargoExtraArgs: string[];
-    executableArgs: string[];
-    expectTest?: boolean;
-    overrideCargo?: string;
-};
-
 export type RunnablesParams = {
     textDocument: lc.TextDocumentIdentifier;
     position: lc.Position | null;
diff --git a/editors/code/src/run.ts b/editors/code/src/run.ts
index 52117a442a..4470689cd8 100644
--- a/editors/code/src/run.ts
+++ b/editors/code/src/run.ts
@@ -9,7 +9,6 @@ import type { Config, RunnableEnvCfg, RunnableEnvCfgItem } from "./config";
 import { unwrapUndefinable } from "./undefinable";
 import type { LanguageClient } from "vscode-languageclient/node";
 import type { RustEditor } from "./util";
-import * as toolchain from "./toolchain";
 
 const quickPickButtons = [
     { iconPath: new vscode.ThemeIcon("save"), tooltip: "Save as a launch.json configuration." },
@@ -67,23 +66,17 @@ export class RunnableQuickPick implements vscode.QuickPickItem {
     }
 }
 
-export function prepareBaseEnv(): Record<string, string> {
-    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
-    Object.assign(env, process.env as { [key: string]: string });
-    return env;
-}
-
 export function prepareEnv(
-    label: string,
-    runnableArgs: ra.CargoRunnableArgs,
+    runnable: ra.Runnable,
     runnableEnvCfg: RunnableEnvCfg,
 ): Record<string, string> {
-    const env = prepareBaseEnv();
+    const env: Record<string, string> = { RUST_BACKTRACE: "short" };
 
-    if (runnableArgs.expectTest) {
+    if (runnable.args.expectTest) {
         env["UPDATE_EXPECT"] = "1";
     }
 
+    Object.assign(env, process.env as { [key: string]: string });
     const platform = process.platform;
 
     const checkPlatform = (it: RunnableEnvCfgItem) => {
@@ -97,7 +90,7 @@ export function prepareEnv(
     if (runnableEnvCfg) {
         if (Array.isArray(runnableEnvCfg)) {
             for (const it of runnableEnvCfg) {
-                const masked = !it.mask || new RegExp(it.mask).test(label);
+                const masked = !it.mask || new RegExp(it.mask).test(runnable.label);
                 if (masked && checkPlatform(it)) {
                     Object.assign(env, it.env);
                 }
@@ -111,41 +104,24 @@ export function prepareEnv(
 }
 
 export async function createTask(runnable: ra.Runnable, config: Config): Promise<vscode.Task> {
-    let definition: tasks.RustTargetDefinition;
-    if (runnable.kind === "cargo") {
-        const runnableArgs = runnable.args as ra.CargoRunnableArgs;
-        let args = createCargoArgs(runnableArgs);
-
-        let program: string;
-        if (runnableArgs.overrideCargo) {
-            // Split on spaces to allow overrides like "wrapper cargo".
-            const cargoParts = runnableArgs.overrideCargo.split(" ");
-
-            program = unwrapUndefinable(cargoParts[0]);
-            args = [...cargoParts.slice(1), ...args];
-        } else {
-            program = await toolchain.cargoPath();
-        }
+    if (runnable.kind !== "cargo") {
+        // rust-analyzer supports only one kind, "cargo"
+        // do not use tasks.TASK_TYPE here, these are completely different meanings.
 
-        definition = {
-            type: tasks.TASK_TYPE,
-            command: program,
-            args,
-            cwd: runnableArgs.workspaceRoot || ".",
-            env: prepareEnv(runnable.label, runnableArgs, config.runnablesExtraEnv),
-        };
-    } else {
-        const runnableArgs = runnable.args as ra.ShellRunnableArgs;
-
-        definition = {
-            type: "shell",
-            command: runnableArgs.program,
-            args: runnableArgs.args,
-            cwd: runnableArgs.cwd,
-            env: prepareBaseEnv(),
-        };
+        throw `Unexpected runnable kind: ${runnable.kind}`;
     }
 
+    const args = createArgs(runnable);
+
+    const definition: tasks.CargoTaskDefinition = {
+        type: tasks.TASK_TYPE,
+        command: unwrapUndefinable(args[0]), // run, test, etc...
+        args: args.slice(1),
+        cwd: runnable.args.workspaceRoot || ".",
+        env: prepareEnv(runnable, config.runnablesExtraEnv),
+        overrideCargo: runnable.args.overrideCargo,
+    };
+
     // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
     const target = vscode.workspace.workspaceFolders![0]; // safe, see main activate()
     const task = await tasks.buildRustTask(
@@ -165,13 +141,13 @@ export async function createTask(runnable: ra.Runnable, config: Config): Promise
     return task;
 }
 
-export function createCargoArgs(runnableArgs: ra.CargoRunnableArgs): string[] {
-    const args = [...runnableArgs.cargoArgs]; // should be a copy!
-    if (runnableArgs.cargoExtraArgs) {
-        args.push(...runnableArgs.cargoExtraArgs); // Append user-specified cargo options.
+export function createArgs(runnable: ra.Runnable): string[] {
+    const args = [...runnable.args.cargoArgs]; // should be a copy!
+    if (runnable.args.cargoExtraArgs) {
+        args.push(...runnable.args.cargoExtraArgs); // Append user-specified cargo options.
     }
-    if (runnableArgs.executableArgs.length > 0) {
-        args.push("--", ...runnableArgs.executableArgs);
+    if (runnable.args.executableArgs.length > 0) {
+        args.push("--", ...runnable.args.executableArgs);
     }
     return args;
 }
diff --git a/editors/code/src/tasks.ts b/editors/code/src/tasks.ts
index c28a919231..2b3abc5d65 100644
--- a/editors/code/src/tasks.ts
+++ b/editors/code/src/tasks.ts
@@ -10,7 +10,7 @@ export const TASK_TYPE = "cargo";
 
 export const TASK_SOURCE = "rust";
 
-export interface RustTargetDefinition extends vscode.TaskDefinition {
+export interface CargoTaskDefinition extends vscode.TaskDefinition {
     // The cargo command, such as "run" or "check".
     command: string;
     // Additional arguments passed to the cargo command.
@@ -69,7 +69,7 @@ class RustTaskProvider implements vscode.TaskProvider {
         // we need to inform VSCode how to execute that command by creating
         // a ShellExecution for it.
 
-        const definition = task.definition as RustTargetDefinition;
+        const definition = task.definition as CargoTaskDefinition;
 
         if (definition.type === TASK_TYPE) {
             return await buildRustTask(
@@ -87,7 +87,7 @@ class RustTaskProvider implements vscode.TaskProvider {
 
 export async function buildRustTask(
     scope: vscode.WorkspaceFolder | vscode.TaskScope | undefined,
-    definition: RustTargetDefinition,
+    definition: CargoTaskDefinition,
     name: string,
     problemMatcher: string[],
     customRunner?: string,
@@ -108,7 +108,7 @@ export async function buildRustTask(
 }
 
 async function cargoToExecution(
-    definition: RustTargetDefinition,
+    definition: CargoTaskDefinition,
     customRunner: string | undefined,
     throwOnError: boolean,
 ): Promise<vscode.ProcessExecution | vscode.ShellExecution> {
@@ -138,31 +138,20 @@ async function cargoToExecution(
         }
     }
 
-    // this is a cargo task; do Cargo-esque processing
-    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 cargoPath = await toolchain.cargoPath();
-        const cargoCommand = definition.overrideCargo?.split(" ") ?? [cargoPath];
-
-        const args = [definition.command].concat(definition.args ?? []);
-        const fullCommand = [...cargoCommand, ...args];
-        const processName = unwrapUndefinable(fullCommand[0]);
-
-        return new vscode.ProcessExecution(processName, fullCommand.slice(1), {
-            cwd: definition.cwd,
-            env: definition.env,
-        });
-    } else {
-        // we've been handed a process definition by rust-analyzer, trust all its inputs
-        // and make a shell execution.
-        const args = unwrapUndefinable(definition.args);
-
-        return new vscode.ProcessExecution(definition.command, args, {
-            cwd: definition.cwd,
-            env: definition.env,
-        });
-    }
+    // Check whether we must use a user-defined substitute for cargo.
+    // Split on spaces to allow overrides like "wrapper cargo".
+    const cargoPath = await toolchain.cargoPath();
+    const cargoCommand = definition.overrideCargo?.split(" ") ?? [cargoPath];
+
+    const args = [definition.command].concat(definition.args ?? []);
+    const fullCommand = [...cargoCommand, ...args];
+
+    const processName = unwrapUndefinable(fullCommand[0]);
+
+    return new vscode.ProcessExecution(processName, fullCommand.slice(1), {
+        cwd: definition.cwd,
+        env: definition.env,
+    });
 }
 
 export function activateTaskProvider(config: Config): vscode.Disposable {
diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts
index 868cb2b780..51f921a296 100644
--- a/editors/code/src/util.ts
+++ b/editors/code/src/util.ts
@@ -2,7 +2,6 @@ import * as vscode from "vscode";
 import { strict as nativeAssert } from "assert";
 import { exec, type ExecOptions, spawnSync } from "child_process";
 import { inspect } from "util";
-import type { CargoRunnableArgs, ShellRunnableArgs } from "./lsp_ext";
 import type { Env } from "./client";
 
 export function assert(condition: boolean, explanation: string): asserts condition {
@@ -78,12 +77,6 @@ export function isCargoTomlDocument(document: vscode.TextDocument): document is
     return document.uri.scheme === "file" && document.fileName.endsWith("Cargo.toml");
 }
 
-export function isCargoRunnableArgs(
-    args: CargoRunnableArgs | ShellRunnableArgs,
-): args is CargoRunnableArgs {
-    return (args as CargoRunnableArgs).executableArgs !== undefined;
-}
-
 export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor {
     return isRustDocument(editor.document);
 }


Test patch:
diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs
index 0011d3a20c..e8b26d5373 100644
--- a/crates/hir-def/src/body/tests.rs
+++ b/crates/hir-def/src/body/tests.rs
@@ -156,7 +156,7 @@ fn main() {
     );
 
     expect![[r#"
-        fn main() -> () {
+        fn main() {
             let are = "are";
             let count = 10;
             builtin#lang(Arguments::new_v1_formatted)(
@@ -258,7 +258,7 @@ impl SsrError {
 
     assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]);
     expect![[r#"
-        fn main() -> () {
+        fn main() {
             _ = $crate::error::SsrError::new(
                 builtin#lang(Arguments::new_v1_formatted)(
                     &[
@@ -303,7 +303,7 @@ macro_rules! m {
     };
 }
 
-fn f(a: i32, b: u32) -> String {
+fn f() {
     m!();
 }
 "#,
@@ -317,7 +317,7 @@ fn f(a: i32, b: u32) -> String {
     }
 
     expect![[r#"
-        fn f(a: i32, b: u32) -> String {
+        fn f() {
             {
                 $crate::panicking::panic_fmt(
                     builtin#lang(Arguments::new_v1_formatted)(
diff --git a/editors/code/tests/unit/runnable_env.test.ts b/editors/code/tests/unit/runnable_env.test.ts
index 21bdaf5384..b1407ce019 100644
--- a/editors/code/tests/unit/runnable_env.test.ts
+++ b/editors/code/tests/unit/runnable_env.test.ts
@@ -10,7 +10,6 @@ function makeRunnable(label: string): ra.Runnable {
         kind: "cargo",
         args: {
             cargoArgs: [],
-            cwd: ".",
             executableArgs: [],
             cargoExtraArgs: [],
         },
@@ -19,8 +18,7 @@ function makeRunnable(label: string): ra.Runnable {
 
 function fakePrepareEnv(runnableName: string, config: RunnableEnvCfg): Record<string, string> {
     const runnable = makeRunnable(runnableName);
-    const runnableArgs = runnable.args as ra.CargoRunnableArgs;
-    return prepareEnv(runnable.label, runnableArgs, config);
+    return prepareEnv(runnable, config);
 }
 
 export async function getTests(ctx: Context) {