Repository: rust-lang/rust-analyzer
Pull request #19191 (2025-02-20 17:59:33)

Remove `limit` crate in favor `usize`
The crate doesn't pull its weight imo, I've never used the tracking feature (nor know of anyone who did)

lnicola: I think I used it at one point, but I it's probably not worth it.

Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index fe090267dc..3f1c8b2a9c 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -34,14 +34,14 @@ jobs:
           - os: windows-latest
             target: aarch64-pc-windows-msvc
             code-target: win32-arm64
-          - os: ubuntu-latest
+          - os: ubuntu-20.04
             target: x86_64-unknown-linux-gnu
             code-target: linux-x64
             container: rockylinux:8
-          - os: ubuntu-latest
+          - os: ubuntu-20.04
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
-          - os: ubuntu-latest
+          - os: ubuntu-20.04
             target: arm-unknown-linux-gnueabihf
             code-target: linux-armhf
           - os: macos-13
diff --git a/Cargo.lock b/Cargo.lock
index 6d7f6042de..fc3680ce27 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -559,7 +559,6 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "mbe",
  "ra-ap-rustc_abi",
  "ra-ap-rustc_parse_format",
@@ -591,7 +590,6 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "mbe",
  "parser",
  "rustc-hash 2.0.0",
@@ -626,7 +624,6 @@ dependencies = [
  "intern",
  "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "limit",
  "nohash-hasher",
  "oorandom",
  "project-model",
@@ -744,7 +741,6 @@ dependencies = [
  "hir",
  "indexmap",
  "itertools",
- "limit",
  "line-index 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "memchr",
  "nohash-hasher",
@@ -943,10 +939,6 @@ dependencies = [
  "redox_syscall",
 ]
 
-[[package]]
-name = "limit"
-version = "0.0.0"
-
 [[package]]
 name = "line-index"
 version = "0.1.2"
@@ -1279,7 +1271,6 @@ dependencies = [
  "drop_bomb",
  "edition",
  "expect-test",
- "limit",
  "ra-ap-rustc_lexer",
  "stdx",
  "tracing",
diff --git a/Cargo.toml b/Cargo.toml
index 924ffb8dd2..5060013b13 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -64,7 +64,6 @@ ide-db = { path = "./crates/ide-db", version = "0.0.0" }
 ide-diagnostics = { path = "./crates/ide-diagnostics", version = "0.0.0" }
 ide-ssr = { path = "./crates/ide-ssr", version = "0.0.0" }
 intern = { path = "./crates/intern", version = "0.0.0" }
-limit = { path = "./crates/limit", version = "0.0.0" }
 load-cargo = { path = "./crates/load-cargo", version = "0.0.0" }
 mbe = { path = "./crates/mbe", version = "0.0.0" }
 parser = { path = "./crates/parser", version = "0.0.0" }
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index bd08387b58..c2cea07190 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -296,9 +296,6 @@ pub struct CrateData {
     pub dependencies: Vec<Dependency>,
     pub origin: CrateOrigin,
     pub is_proc_macro: bool,
-    /// The working directory to run proc-macros in. This is the workspace root of the cargo workspace
-    /// for workspace members, the crate manifest dir otherwise.
-    pub proc_macro_cwd: Option<AbsPathBuf>,
 }
 
 #[derive(Default, Clone, PartialEq, Eq)]
@@ -363,9 +360,8 @@ impl CrateGraph {
         cfg_options: Arc<CfgOptions>,
         potential_cfg_options: Option<Arc<CfgOptions>>,
         mut env: Env,
-        origin: CrateOrigin,
         is_proc_macro: bool,
-        proc_macro_cwd: Option<AbsPathBuf>,
+        origin: CrateOrigin,
     ) -> CrateId {
         env.entries.shrink_to_fit();
         let data = CrateData {
@@ -379,7 +375,6 @@ impl CrateGraph {
             dependencies: Vec::new(),
             origin,
             is_proc_macro,
-            proc_macro_cwd,
         };
         self.arena.alloc(data)
     }
@@ -703,9 +698,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -715,9 +709,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -727,9 +720,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -753,9 +745,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -765,9 +756,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -788,9 +778,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -800,9 +789,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate3 = graph.add_crate_root(
             FileId::from_raw(3u32),
@@ -812,9 +800,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         assert!(graph
             .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2,))
@@ -835,9 +822,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         let crate2 = graph.add_crate_root(
             FileId::from_raw(2u32),
@@ -847,9 +833,8 @@ mod tests {
             Default::default(),
             Default::default(),
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         assert!(graph
             .add_dep(
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index eed8c88683..c7e4168f6b 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -10,7 +10,7 @@ use rustc_hash::FxHashMap;
 use span::EditionedFileId;
 use syntax::{ast, Parse, SourceFile, SyntaxError};
 use triomphe::Arc;
-use vfs::FileId;
+use vfs::{AbsPathBuf, FileId};
 
 pub use crate::{
     change::FileChange,
@@ -85,6 +85,8 @@ pub trait SourceDatabase: FileLoader + std::fmt::Debug {
 /// Crate related data shared by the whole workspace.
 #[derive(Debug, PartialEq, Eq, Hash, Clone)]
 pub struct CrateWorkspaceData {
+    /// The working directory to run proc-macros in. This is usually the workspace root of cargo workspaces.
+    pub proc_macro_cwd: Option<AbsPathBuf>,
     // FIXME: Consider removing this, making HirDatabase::target_data_layout an input query
     pub data_layout: TargetLayoutLoadResult,
     /// Toolchain version used to compile the crate.
diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml
index 375f18d9fe..74fe49b767 100644
--- a/crates/hir-def/Cargo.toml
+++ b/crates/hir-def/Cargo.toml
@@ -43,7 +43,6 @@ hir-expand.workspace = true
 mbe.workspace = true
 cfg.workspace = true
 tt.workspace = true
-limit.workspace = true
 span.workspace = true
 
 
diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs
index 108258d5a1..a1b3123c99 100644
--- a/crates/hir-def/src/expander.rs
+++ b/crates/hir-def/src/expander.rs
@@ -9,7 +9,6 @@ use hir_expand::{
     attrs::RawAttrs, mod_path::ModPath, span_map::SpanMap, ExpandError, ExpandErrorKind,
     ExpandResult, HirFileId, InFile, Lookup, MacroCallId,
 };
-use limit::Limit;
 use span::{Edition, SyntaxContextId};
 use syntax::{ast, Parse};
 use triomphe::Arc;
@@ -28,18 +27,18 @@ pub struct Expander {
     pub(crate) module: ModuleId,
     /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
     recursion_depth: u32,
-    recursion_limit: Limit,
+    recursion_limit: usize,
 }
 
 impl Expander {
     pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
         let recursion_limit = module.def_map(db).recursion_limit() as usize;
-        let recursion_limit = Limit::new(if cfg!(test) {
+        let recursion_limit = if cfg!(test) {
             // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
             std::cmp::min(32, recursion_limit)
         } else {
             recursion_limit
-        });
+        };
         Expander {
             current_file_id,
             module,
@@ -194,7 +193,7 @@ impl Expander {
         let Some(call_id) = value else {
             return ExpandResult { value: None, err };
         };
-        if self.recursion_limit.check(self.recursion_depth as usize + 1).is_err() {
+        if self.recursion_depth as usize > self.recursion_limit {
             self.recursion_depth = u32::MAX;
             cov_mark::hit!(your_stack_belongs_to_me);
             return ExpandResult::only_err(ExpandError::new(
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 254c137991..16f3fd56eb 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -19,7 +19,6 @@ use hir_expand::{
 use intern::{sym, Interned};
 use itertools::{izip, Itertools};
 use la_arena::Idx;
-use limit::Limit;
 use rustc_hash::{FxHashMap, FxHashSet};
 use span::{Edition, EditionedFileId, FileAstId, SyntaxContextId};
 use syntax::ast;
@@ -55,8 +54,8 @@ use crate::{
     UnresolvedMacro, UseId, UseLoc,
 };
 
-static GLOB_RECURSION_LIMIT: Limit = Limit::new(100);
-static FIXED_POINT_LIMIT: Limit = Limit::new(8192);
+const GLOB_RECURSION_LIMIT: usize = 100;
+const FIXED_POINT_LIMIT: usize = 8192;
 
 pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeId) -> DefMap {
     let crate_graph = db.crate_graph();
@@ -393,7 +392,7 @@ impl DefCollector<'_> {
                 }
 
                 i += 1;
-                if FIXED_POINT_LIMIT.check(i).is_err() {
+                if i > FIXED_POINT_LIMIT {
                     tracing::error!("name resolution is stuck");
                     break 'resolve_attr;
                 }
@@ -993,7 +992,7 @@ impl DefCollector<'_> {
         import: Option<ImportOrExternCrate>,
         depth: usize,
     ) {
-        if GLOB_RECURSION_LIMIT.check(depth).is_err() {
+        if depth > GLOB_RECURSION_LIMIT {
             // prevent stack overflows (but this shouldn't be possible)
             panic!("infinite recursion in glob imports!");
         }
@@ -1470,8 +1469,7 @@ impl DefCollector<'_> {
         depth: usize,
         container: ItemContainerId,
     ) {
-        let recursion_limit = Limit::new(self.def_map.recursion_limit() as usize);
-        if recursion_limit.check(depth).is_err() {
+        if depth > self.def_map.recursion_limit() as usize {
             cov_mark::hit!(macro_expansion_overflow);
             tracing::warn!("macro expansion is too deep");
             return;
@@ -1499,7 +1497,6 @@ impl DefCollector<'_> {
 
     fn finish(mut self) -> DefMap {
         // Emit diagnostics for all remaining unexpanded macros.
-
         let _p = tracing::info_span!("DefCollector::finish").entered();
 
         for directive in &self.unresolved_macros {
diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs
index d7e4ca41cd..afee42ecec 100644
--- a/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/crates/hir-def/src/nameres/mod_resolution.rs
@@ -2,12 +2,11 @@
 use arrayvec::ArrayVec;
 use base_db::AnchoredPath;
 use hir_expand::{name::Name, HirFileIdExt};
-use limit::Limit;
 use span::EditionedFileId;
 
 use crate::{db::DefDatabase, HirFileId};
 
-static MOD_DEPTH_LIMIT: Limit = Limit::new(32);
+const MOD_DEPTH_LIMIT: usize = 32;
 
 #[derive(Clone, Debug)]
 pub(super) struct ModDir {
@@ -50,7 +49,7 @@ impl ModDir {
 
     fn child(&self, dir_path: DirPath, root_non_dir_owner: bool) -> Option<ModDir> {
         let depth = self.depth + 1;
-        if MOD_DEPTH_LIMIT.check(depth as usize).is_err() {
+        if depth as usize > MOD_DEPTH_LIMIT {
             tracing::error!("MOD_DEPTH_LIMIT exceeded");
             cov_mark::hit!(circular_mods);
             return None;
diff --git a/crates/hir-expand/Cargo.toml b/crates/hir-expand/Cargo.toml
index 03a9d54d2e..b193a34a01 100644
--- a/crates/hir-expand/Cargo.toml
+++ b/crates/hir-expand/Cargo.toml
@@ -31,7 +31,6 @@ cfg.workspace = true
 syntax.workspace = true
 tt.workspace = true
 mbe.workspace = true
-limit.workspace = true
 span.workspace = true
 parser.workspace = true
 syntax-bridge.workspace = true
diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs
index 55242ab3e5..310ddaaf9e 100644
--- a/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/crates/hir-expand/src/builtin/fn_macro.rs
@@ -833,7 +833,7 @@ fn env_expand(
         if key.as_str() == "OUT_DIR" {
             err = Some(ExpandError::other(
                 span,
-                r#"`OUT_DIR` not set, build scripts may have failed to run"#,
+                r#"`OUT_DIR` not set, enable "build scripts" to fix"#,
             ));
         }
 
diff --git a/crates/hir-expand/src/db.rs b/crates/hir-expand/src/db.rs
index b7804f888a..8ca8bf1ba4 100644
--- a/crates/hir-expand/src/db.rs
+++ b/crates/hir-expand/src/db.rs
@@ -2,7 +2,6 @@
 
 use base_db::{ra_salsa, CrateId, SourceDatabase};
 use either::Either;
-use limit::Limit;
 use mbe::MatchedArmIndex;
 use rustc_hash::FxHashSet;
 use span::{AstIdMap, Edition, EditionedFileId, Span, SyntaxContextData, SyntaxContextId};
@@ -35,7 +34,7 @@ type MacroArgResult = (Arc<tt::TopSubtree>, SyntaxFixupUndoInfo, Span);
 /// an error will be emitted.
 ///
 /// Actual max for `analysis-stats .` at some point: 30672.
-static TOKEN_LIMIT: Limit = Limit::new(2_097_152);
+const TOKEN_LIMIT: usize = 2_097_152;
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum TokenExpander {
@@ -740,20 +739,19 @@ pub(crate) fn token_tree_to_syntax_node(
 fn check_tt_count(tt: &tt::TopSubtree) -> Result<(), ExpandResult<()>> {
     let tt = tt.top_subtree();
     let count = tt.count();
-    if TOKEN_LIMIT.check(count).is_err() {
+    if count <= TOKEN_LIMIT {
+        Ok(())
+    } else {
         Err(ExpandResult {
             value: (),
             err: Some(ExpandError::other(
                 tt.delimiter.open,
                 format!(
                     "macro invocation exceeds token limit: produced {} tokens, limit is {}",
-                    count,
-                    TOKEN_LIMIT.inner(),
+                    count, TOKEN_LIMIT,
                 ),
             )),
         })
-    } else {
-        Ok(())
     }
 }
 
diff --git a/crates/hir-expand/src/proc_macro.rs b/crates/hir-expand/src/proc_macro.rs
index 3dc3dcd760..07808fea85 100644
--- a/crates/hir-expand/src/proc_macro.rs
+++ b/crates/hir-expand/src/proc_macro.rs
@@ -238,9 +238,6 @@ impl CustomProcMacroExpander {
                 let krate_graph = db.crate_graph();
                 // Proc macros have access to the environment variables of the invoking crate.
                 let env = &krate_graph[calling_crate].env;
-                let current_dir =
-                    krate_graph[calling_crate].proc_macro_cwd.as_deref().map(ToString::to_string);
-
                 match proc_macro.expander.expand(
                     tt,
                     attr_arg,
@@ -248,7 +245,10 @@ impl CustomProcMacroExpander {
                     def_site,
                     call_site,
                     mixed_site,
-                    current_dir,
+                    db.crate_workspace_data()[&calling_crate]
+                        .proc_macro_cwd
+                        .as_ref()
+                        .map(ToString::to_string),
                 ) {
                     Ok(t) => ExpandResult::ok(t),
                     Err(err) => match err {
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index 989f0955e1..eaa258a6b5 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -47,7 +47,6 @@ hir-def.workspace = true
 hir-expand.workspace = true
 base-db.workspace = true
 syntax.workspace = true
-limit.workspace = true
 span.workspace = true
 
 [dev-dependencies]
diff --git a/crates/hir-ty/src/autoderef.rs b/crates/hir-ty/src/autoderef.rs
index e0e366f450..171ba001c4 100644
--- a/crates/hir-ty/src/autoderef.rs
+++ b/crates/hir-ty/src/autoderef.rs
@@ -9,7 +9,6 @@ use chalk_ir::cast::Cast;
 use hir_def::lang_item::LangItem;
 use hir_expand::name::Name;
 use intern::sym;
-use limit::Limit;
 use triomphe::Arc;
 
 use crate::{
@@ -17,7 +16,7 @@ use crate::{
     TraitEnvironment, Ty, TyBuilder, TyKind,
 };
 
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
+const AUTODEREF_RECURSION_LIMIT: usize = 20;
 
 #[derive(Debug)]
 pub(crate) enum AutoderefKind {
@@ -140,7 +139,7 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
             return Some((self.ty.clone(), 0));
         }
 
-        if AUTODEREF_RECURSION_LIMIT.check(self.steps.len() + 1).is_err() {
+        if self.steps.len() > AUTODEREF_RECURSION_LIMIT {
             return None;
         }
 
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index c8ff6cba3d..6d4753ea38 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -768,23 +768,21 @@ pub(crate) fn adt_datum_query(
         phantom_data,
     };
 
-    // this slows down rust-analyzer by quite a bit unfortunately, so enabling this is currently not worth it
-    let _variant_id_to_fields = |id: VariantId| {
+    let variant_id_to_fields = |id: VariantId| {
         let variant_data = &id.variant_data(db.upcast());
-        let fields = if variant_data.fields().is_empty() {
+        let fields = if variant_data.fields().is_empty() || bound_vars_subst.is_empty(Interner) {
             vec![]
         } else {
-            let field_types = db.field_types(id);
-            variant_data
-                .fields()
-                .iter()
-                .map(|(idx, _)| field_types[idx].clone().substitute(Interner, &bound_vars_subst))
-                .filter(|it| !it.contains_unknown())
-                .collect()
+            // HACK: provide full struct type info slows down rust-analyzer by quite a bit unfortunately,
+            // so we trick chalk into thinking that our struct impl Unsize
+            if let Some(ty) = bound_vars_subst.at(Interner, 0).ty(Interner) {
+                vec![ty.clone()]
+            } else {
+                vec![]
+            }
         };
         rust_ir::AdtVariantDatum { fields }
     };
-    let variant_id_to_fields = |_: VariantId| rust_ir::AdtVariantDatum { fields: vec![] };
 
     let (kind, variants) = match adt_id {
         hir_def::AdtId::StructId(id) => {
diff --git a/crates/hir-ty/src/lower/path.rs b/crates/hir-ty/src/lower/path.rs
index a165932ddc..22c5bb9923 100644
--- a/crates/hir-ty/src/lower/path.rs
+++ b/crates/hir-ty/src/lower/path.rs
@@ -10,7 +10,7 @@ use hir_def::{
     generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
     path::{GenericArg, GenericArgs, Path, PathSegment, PathSegments},
     resolver::{ResolveValueResult, TypeNs, ValueNs},
-    type_ref::{TypeBound, TypeRef, TypesMap},
+    type_ref::{TypeBound, TypeRef},
     GenericDefId, GenericParamId, ItemContainerId, Lookup, TraitId,
 };
 use smallvec::SmallVec;
@@ -838,21 +838,15 @@ impl<'a, 'b> PathLoweringContext<'a, 'b> {
                         (_, ImplTraitLoweringMode::Param | ImplTraitLoweringMode::Variable) => {
                             // Find the generic index for the target of our `bound`
                             let target_param_idx =
-                                self.ctx.resolver.where_predicates_in_scope().find_map(
-                                    |(p, (_, types_map))| match p {
+                                self.ctx.resolver.where_predicates_in_scope().find_map(|(p, _)| {
+                                    match p {
                                         WherePredicate::TypeBound {
                                             target: WherePredicateTypeTarget::TypeOrConstParam(idx),
                                             bound: b,
-                                        } if std::ptr::eq::<TypesMap>(
-                                            self.ctx.types_map,
-                                            types_map,
-                                        ) && bound == b =>
-                                        {
-                                            Some(idx)
-                                        }
+                                        } if b == bound => Some(idx),
                                         _ => None,
-                                    },
-                                );
+                                    }
+                                });
                             let ty = if let Some(target_param_idx) = target_param_idx {
                                 let mut counter = 0;
                                 let generics = self.ctx.generics().expect("generics in scope");
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index 05105c8c92..fb533077d9 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -20,7 +20,6 @@ pub struct AssistConfig {
     pub assist_emit_must_use: bool,
     pub term_search_fuel: u64,
     pub term_search_borrowck: bool,
-    pub code_action_grouping: bool,
 }
 
 impl AssistConfig {
diff --git a/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index 220259451e..081e36b4ff 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -48,10 +48,6 @@ use crate::{
 // }
 // ```
 pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    if !ctx.config.code_action_grouping {
-        return None;
-    }
-
     let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
     let strukt_name = strukt.name()?;
     let current_module = ctx.sema.scope(strukt.syntax())?.module();
@@ -217,9 +213,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{
-        check_assist, check_assist_not_applicable, check_assist_not_applicable_no_grouping,
-    };
+    use crate::tests::{check_assist, check_assist_not_applicable};
 
     use super::*;
 
@@ -723,21 +717,4 @@ impl Person {
 "#,
         );
     }
-
-    #[test]
-    fn delegate_method_skipped_when_no_grouping() {
-        check_assist_not_applicable_no_grouping(
-            generate_delegate_methods,
-            r#"
-struct Age(u8);
-impl Age {
-    fn age(&self) -> u8 {
-        self.0
-    }
-}
-struct Person {
-    ag$0e: Age,
-}"#,
-        );
-    }
 }
diff --git a/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 55b860d0ff..66bf9b0186 100644
--- a/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -88,10 +88,6 @@ use syntax::{
 // }
 // ```
 pub(crate) fn generate_delegate_trait(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    if !ctx.config.code_action_grouping {
-        return None;
-    }
-
     let strukt = Struct::new(ctx.find_node_at_offset::<ast::Struct>()?)?;
 
     let field: Field = match ctx.find_node_at_offset::<ast::RecordField>() {
@@ -792,9 +788,7 @@ fn qualified_path(qual_path_ty: ast::Path, path_expr_seg: ast::Path) -> ast::Pat
 mod test {
 
     use super::*;
-    use crate::tests::{
-        check_assist, check_assist_not_applicable, check_assist_not_applicable_no_grouping,
-    };
+    use crate::tests::{check_assist, check_assist_not_applicable};
 
     #[test]
     fn test_tuple_struct_basic() {
@@ -1842,33 +1836,4 @@ impl<D, T: C<A>> C<D> for B<T> {
 "#,
         )
     }
-
-    #[test]
-    fn delegate_trait_skipped_when_no_grouping() {
-        check_assist_not_applicable_no_grouping(
-            generate_delegate_trait,
-            r#"
-trait SomeTrait {
-    type T;
-    fn fn_(arg: u32) -> u32;
-    fn method_(&mut self) -> bool;
-}
-struct A;
-impl SomeTrait for A {
-    type T = u32;
-
-    fn fn_(arg: u32) -> u32 {
-        42
-    }
-
-    fn method_(&mut self) -> bool {
-        false
-    }
-}
-struct B {
-    a$0 : A,
-}
-"#,
-        );
-    }
 }
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index 17f0e69bde..c8a8a2d169 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -30,7 +30,6 @@ bitflags.workspace = true
 
 # local deps
 base-db.workspace = true
-limit.workspace = true
 parser.workspace = true
 profile.workspace = true
 stdx.workspace = true
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index ad86d855b5..77fc59b4ec 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -357,7 +357,7 @@ fn path_applicable_imports(
                 let mod_path = mod_path(item)?;
                 Some(LocatedImport::new(mod_path, item, item))
             })
-            .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
+            .take(DEFAULT_QUERY_SEARCH_LIMIT)
             .collect()
         }
         // we have some unresolved qualifier that we search an import for
@@ -383,7 +383,7 @@ fn path_applicable_imports(
                 qualifier_rest,
             )
         })
-        .take(DEFAULT_QUERY_SEARCH_LIMIT.inner())
+        .take(DEFAULT_QUERY_SEARCH_LIMIT)
         .collect(),
     }
 }
diff --git a/crates/ide-db/src/items_locator.rs b/crates/ide-db/src/items_locator.rs
index a2062f36d3..4d9c051354 100644
--- a/crates/ide-db/src/items_locator.rs
+++ b/crates/ide-db/src/items_locator.rs
@@ -6,7 +6,6 @@ use std::ops::ControlFlow;
 
 use either::Either;
 use hir::{import_map, Crate, ItemInNs, Module, Semantics};
-use limit::Limit;
 
 use crate::{
     imports::import_assets::NameToImport,
@@ -15,7 +14,7 @@ use crate::{
 };
 
 /// A value to use, when uncertain which limit to pick.
-pub static DEFAULT_QUERY_SEARCH_LIMIT: Limit = Limit::new(100);
+pub const DEFAULT_QUERY_SEARCH_LIMIT: usize = 100;
 
 pub use import_map::AssocSearchMode;
 
diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs
index 2f13298589..99894fefef 100644
--- a/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -133,7 +133,7 @@ macro_rules! env { () => {} }
 macro_rules! concat { () => {} }
 
   include!(concat!(env!("OUT_DIR"), "/out.rs"));
-                      //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
+                      //^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
 "#,
         );
     }
@@ -186,7 +186,7 @@ fn main() {
        //^^^^^^^ error: expected string literal
 
     env!("OUT_DIR");
-       //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
+       //^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
 
     compile_error!("compile_error works");
   //^^^^^^^^^^^^^ error: compile_error works
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 27a1a510b4..e942f5a6aa 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -252,14 +252,14 @@ impl Analysis {
             Arc::new(cfg_options),
             None,
             Env::default(),
-            CrateOrigin::Local { repo: None, name: None },
             false,
-            None,
+            CrateOrigin::Local { repo: None, name: None },
         );
         change.change_file(file_id, Some(text));
         let ws_data = crate_graph
             .iter()
             .zip(iter::repeat(Arc::new(CrateWorkspaceData {
+                proc_macro_cwd: None,
                 data_layout: Err("fixture has no layout".into()),
                 toolchain: None,
             })))
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index f8ecaa8fdf..b0022cfac7 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -68,7 +68,6 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
                 dependencies,
                 origin,
                 is_proc_macro,
-                proc_macro_cwd,
             } = &crate_graph[crate_id];
             format_to!(
                 buf,
@@ -86,7 +85,6 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
             format_to!(buf, "    Env: {:?}\n", env);
             format_to!(buf, "    Origin: {:?}\n", origin);
             format_to!(buf, "    Is a proc macro crate: {}\n", is_proc_macro);
-            format_to!(buf, "    Proc macro cwd: {:?}\n", proc_macro_cwd);
             let deps = dependencies
                 .iter()
                 .map(|dep| format!("{}={}", dep.name, dep.crate_id.into_raw()))
diff --git a/crates/limit/Cargo.toml b/crates/limit/Cargo.toml
deleted file mode 100644
index 30666f5219..0000000000
--- a/crates/limit/Cargo.toml
+++ /dev/null
@@ -1,16 +0,0 @@
-[package]
-name = "limit"
-version = "0.0.0"
-repository.workspace = true
-description = "A struct to enforce limits for rust-analyzer."
-
-authors.workspace = true
-edition.workspace = true
-license.workspace = true
-rust-version.workspace = true
-
-[features]
-tracking = []
-
-[lints]
-workspace = true
diff --git a/crates/limit/src/lib.rs b/crates/limit/src/lib.rs
deleted file mode 100644
index c1caeed2f8..0000000000
--- a/crates/limit/src/lib.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-//! limit defines a struct to enforce limits.
-
-#[cfg(feature = "tracking")]
-use std::sync::atomic::AtomicUsize;
-
-/// Represents a struct used to enforce a numerical limit.
-#[derive(Debug)]
-pub struct Limit {
-    upper_bound: usize,
-    #[cfg(feature = "tracking")]
-    max: AtomicUsize,
-}
-
-impl Limit {
-    /// Creates a new limit.
-    #[inline]
-    pub const fn new(upper_bound: usize) -> Self {
-        Self {
-            upper_bound,
-            #[cfg(feature = "tracking")]
-            max: AtomicUsize::new(0),
-        }
-    }
-
-    /// Creates a new limit.
-    #[inline]
-    #[cfg(feature = "tracking")]
-    pub const fn new_tracking(upper_bound: usize) -> Self {
-        Self {
-            upper_bound,
-            #[cfg(feature = "tracking")]
-            max: AtomicUsize::new(1),
-        }
-    }
-
-    /// Gets the underlying numeric limit.
-    #[inline]
-    pub const fn inner(&self) -> usize {
-        self.upper_bound
-    }
-
-    /// Checks whether the given value is below the limit.
-    /// Returns `Ok` when `other` is below `self`, and `Err` otherwise.
-    #[inline]
-    pub fn check(&self, other: usize) -> Result<(), ()> {
-        if other > self.upper_bound {
-            Err(())
-        } else {
-            #[cfg(feature = "tracking")]
-            loop {
-                use std::sync::atomic::Ordering;
-                let old_max = self.max.load(Ordering::Relaxed);
-                if other <= old_max || old_max == 0 {
-                    break;
-                }
-                _ = self.max.compare_exchange_weak(
-                    old_max,
-                    other,
-                    Ordering::Relaxed,
-                    Ordering::Relaxed,
-                );
-            }
-
-            Ok(())
-        }
-    }
-}
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index 76f1a7f48b..67ee9d1119 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -456,6 +456,7 @@ fn load_crate_graph(
     let ws_data = crate_graph
         .iter()
         .zip(iter::repeat(From::from(CrateWorkspaceData {
+            proc_macro_cwd: None,
             data_layout: target_layout.clone(),
             toolchain: toolchain.clone(),
         })))
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 3629d275c0..48436ec71f 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -15,7 +15,6 @@ doctest = false
 [dependencies]
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
-limit.workspace = true
 tracing = { workspace = true, optional = true }
 
 edition.workspace = true
diff --git a/crates/parser/src/parser.rs b/crates/parser/src/parser.rs
index 2f6ba52574..b058686276 100644
--- a/crates/parser/src/parser.rs
+++ b/crates/parser/src/parser.rs
@@ -3,7 +3,6 @@
 use std::cell::Cell;
 
 use drop_bomb::DropBomb;
-use limit::Limit;
 
 use crate::{
     event::Event,
@@ -30,7 +29,7 @@ pub(crate) struct Parser<'t> {
     edition: Edition,
 }
 
-static PARSER_STEP_LIMIT: Limit = Limit::new(15_000_000);
+const PARSER_STEP_LIMIT: usize = 15_000_000;
 
 impl<'t> Parser<'t> {
     pub(super) fn new(inp: &'t Input, edition: Edition) -> Parser<'t> {
@@ -54,7 +53,7 @@ impl<'t> Parser<'t> {
         assert!(n <= 3);
 
         let steps = self.steps.get();
-        assert!(PARSER_STEP_LIMIT.check(steps as usize).is_ok(), "the parser seems stuck");
+        assert!((steps as usize) < PARSER_STEP_LIMIT, "the parser seems stuck");
         self.steps.set(steps + 1);
 
         self.inp.kind(self.pos + n)
diff --git a/crates/project-model/src/project_json.rs b/crates/project-model/src/project_json.rs
index 2f9612e3a4..feee40a1fc 100644
--- a/crates/project-model/src/project_json.rs
+++ b/crates/project-model/src/project_json.rs
@@ -164,7 +164,6 @@ impl ProjectJson {
                         is_proc_macro: crate_data.is_proc_macro,
                         repository: crate_data.repository,
                         build,
-                        proc_macro_cwd: crate_data.proc_macro_cwd.map(absolutize_on_base),
                     }
                 })
                 .collect(),
@@ -241,8 +240,6 @@ pub struct Crate {
     pub(crate) include: Vec<AbsPathBuf>,
     pub(crate) exclude: Vec<AbsPathBuf>,
     pub(crate) is_proc_macro: bool,
-    /// The working directory to run proc-macros in. This is usually the workspace root of cargo workspaces.
-    pub(crate) proc_macro_cwd: Option<AbsPathBuf>,
     pub(crate) repository: Option<String>,
     pub build: Option<Build>,
 }
@@ -365,8 +362,6 @@ struct CrateData {
     repository: Option<String>,
     #[serde(default)]
     build: Option<BuildData>,
-    #[serde(default)]
-    proc_macro_cwd: Option<Utf8PathBuf>,
 }
 
 mod cfg_ {
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index fb752fe47b..544ba43ba6 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -312,8 +312,8 @@ impl Sysroot {
                     RustLibSrcWorkspace::Empty => true,
                 };
                 if !has_core {
-                    let var_note = if env::var_os("RUST_SRC_PATH").is_some() {
-                        " (env var `RUST_SRC_PATH` is set and may be incorrect, try unsetting it)"
+                    let var_note = if env::var_os("rust_lib_src_PATH").is_some() {
+                        " (env var `rust_lib_src_PATH` is set and may be incorrect, try unsetting it)"
                     } else {
                         ", try running `rustup component add rust-src` to possibly fix this"
                     };
@@ -422,16 +422,18 @@ fn discover_sysroot_dir(
 }
 
 fn discover_rust_lib_src_dir(sysroot_path: &AbsPathBuf) -> Option<AbsPathBuf> {
-    if let Ok(path) = env::var("RUST_SRC_PATH") {
+    if let Ok(path) = env::var("rust_lib_src_PATH") {
         if let Ok(path) = AbsPathBuf::try_from(path.as_str()) {
             let core = path.join("core");
             if fs::metadata(&core).is_ok() {
-                tracing::debug!("Discovered sysroot by RUST_SRC_PATH: {path}");
+                tracing::debug!("Discovered sysroot by rust_lib_src_PATH: {path}");
                 return Some(path);
             }
-            tracing::debug!("RUST_SRC_PATH is set, but is invalid (no core: {core:?}), ignoring");
+            tracing::debug!(
+                "rust_lib_src_PATH is set, but is invalid (no core: {core:?}), ignoring"
+            );
         } else {
-            tracing::debug!("RUST_SRC_PATH is set, but is invalid, ignoring");
+            tracing::debug!("rust_lib_src_PATH is set, but is invalid, ignoring");
         }
     }
 
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 16b5bb11af..f5d46daa80 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -958,7 +958,6 @@ fn project_json_to_crate_graph(
                     is_proc_macro,
                     repository,
                     is_workspace_member,
-                    proc_macro_cwd,
                     ..
                 },
                 file_id,
@@ -1006,6 +1005,7 @@ fn project_json_to_crate_graph(
                     Arc::new(cfg_options),
                     None,
                     env,
+                    *is_proc_macro,
                     if let Some(name) = display_name.clone() {
                         CrateOrigin::Local {
                             repo: repository.clone(),
@@ -1014,8 +1014,6 @@ fn project_json_to_crate_graph(
                     } else {
                         CrateOrigin::Local { repo: None, name: None }
                     },
-                    *is_proc_macro,
-                    proc_macro_cwd.clone(),
                 );
                 debug!(
                     ?crate_graph_crate_id,
@@ -1285,12 +1283,11 @@ fn detached_file_to_crate_graph(
         cfg_options.clone(),
         None,
         Env::default(),
+        false,
         CrateOrigin::Local {
             repo: None,
             name: display_name.map(|n| n.canonical_name().to_owned()),
         },
-        false,
-        None,
     );
 
     public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
@@ -1451,13 +1448,8 @@ fn add_target_crate_root(
         Arc::new(cfg_options),
         potential_cfg_options.map(Arc::new),
         env,
-        origin,
         matches!(kind, TargetKind::Lib { is_proc_macro: true }),
-        Some(if pkg.is_member {
-            cargo.workspace_root().to_path_buf()
-        } else {
-            pkg.manifest.parent().to_path_buf()
-        }),
+        origin,
     );
     if let TargetKind::Lib { is_proc_macro: true } = kind {
         let proc_macro = match build_data {
@@ -1595,9 +1587,8 @@ fn sysroot_to_crate_graph(
                         cfg_options.clone(),
                         None,
                         Env::default(),
-                        CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
                         false,
-                        None,
+                        CrateOrigin::Lang(LangCrateOrigin::from(&*stitched[krate].name)),
                     );
                     Some((krate, crate_id))
                 })
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1dce0bea1a..d7e9a5c586 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -1476,7 +1476,6 @@ impl Config {
             prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
             term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
             term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
-            code_action_grouping: self.code_action_group(),
         }
     }
 
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 56dcad0eb1..ba72ea35df 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -885,6 +885,7 @@ pub fn ws_to_crate_graph(
         ws_data.extend(mapping.values().copied().zip(iter::repeat(Arc::new(CrateWorkspaceData {
             toolchain: toolchain.clone(),
             data_layout: target_layout.clone(),
+            proc_macro_cwd: Some(ws.workspace_root().to_owned()),
         }))));
         proc_macro_paths.push(crate_proc_macros);
     }
diff --git a/docs/book/src/configuration.md b/docs/book/src/configuration.md
index fd94a4221a..221a571c17 100644
--- a/docs/book/src/configuration.md
+++ b/docs/book/src/configuration.md
@@ -3,13 +3,13 @@
 **Source:**
 [config.rs](https://github.com/rust-lang/rust-analyzer/blob/master/crates/rust-analyzer/src/config.rs)
 
-The [Installation](./installation.md) section contains details on
+The [Installation](#_installation) section contains details on
 configuration for some of the editors. In general `rust-analyzer` is
 configured via LSP messages, which means that it’s up to the editor to
 decide on the exact format and location of configuration files.
 
-Some clients, such as [VS Code](./vs_code.md) or [COC plugin in
-Vim](./other_editors.md#coc-rust-analyzer) provide `rust-analyzer` specific configuration
+Some clients, such as [VS Code](#vs-code) or [COC plugin in
+Vim](#coc-rust-analyzer) provide `rust-analyzer` specific configuration
 UIs. Others may require you to know a bit more about the interaction
 with `rust-analyzer`.
 
diff --git a/docs/book/src/contributing/architecture.md b/docs/book/src/contributing/architecture.md
index 1cc13b3b96..b9b98bfea3 100644
--- a/docs/book/src/contributing/architecture.md
+++ b/docs/book/src/contributing/architecture.md
@@ -296,7 +296,7 @@ For this reason, all path APIs generally take some existing path as a "file syst
 ### `crates/stdx`
 
 This crate contains various non-rust-analyzer specific utils, which could have been in std, as well
-as copies of unstable std items we would like to make use of already.
+as copies of unstable std items we would like to make use of already, like `std::str::split_once`.
 
 ### `crates/profile`
 
diff --git a/docs/book/src/contributing/style.md b/docs/book/src/contributing/style.md
index 5654e37753..6e5d1869b1 100644
--- a/docs/book/src/contributing/style.md
+++ b/docs/book/src/contributing/style.md
@@ -276,7 +276,7 @@ fn f() {
 Assert liberally.
 Prefer [`stdx::never!`](https://docs.rs/always-assert/0.1.2/always_assert/macro.never.html) to standard `assert!`.
 
-**Rationale:** See [cross cutting concern: error handling](https://github.com/rust-lang/rust-analyzer/blob/master/docs/book/src/contributing/architecture.md#error-handling).
+**Rationale:** See [cross cutting concern: error handling](https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/architecture.md#error-handling).
 
 ## Getters & Setters
 
diff --git a/docs/book/src/editor_features.md b/docs/book/src/editor_features.md
index 5521e395c7..73fe9f49a9 100644
--- a/docs/book/src/editor_features.md
+++ b/docs/book/src/editor_features.md
@@ -1,5 +1,6 @@
 # Editor Features
 
+
 ## VS Code
 
 ### Color configurations
@@ -117,7 +118,7 @@ Or it is possible to specify vars more granularly:
 "rust-analyzer.runnables.extraEnv": [
     {
         // "mask": null, // null mask means that this rule will be applied for all runnables
-        "env": {
+        env: {
                 "APP_ID": "1",
                 "APP_DATA": "asdf"
         }
@@ -144,7 +145,7 @@ If needed, you can set different values for different platforms:
 "rust-analyzer.runnables.extraEnv": [
     {
         "platform": "win32", // windows only
-        "env": {
+        env: {
                 "APP_DATA": "windows specific data"
         }
     },
diff --git a/docs/book/src/other_editors.md b/docs/book/src/other_editors.md
index 1eac7dd2c2..0a9a453e01 100644
--- a/docs/book/src/other_editors.md
+++ b/docs/book/src/other_editors.md
@@ -6,8 +6,6 @@ Protocol](https://microsoft.github.io/language-server-protocol/).
 This page assumes that you have already [installed the rust-analyzer
 binary](./rust_analyzer_binary.html).
 
-<!-- toc -->
-
 ## Emacs
 
 To use `rust-analyzer`, you need to install and enable one of the two
diff --git a/xtask/src/codegen.rs b/xtask/src/codegen.rs
index 8165a2a12b..e84c259e97 100644
--- a/xtask/src/codegen.rs
+++ b/xtask/src/codegen.rs
@@ -117,13 +117,7 @@ impl fmt::Display for Location {
         let path = self.file.strip_prefix(project_root()).unwrap().display().to_string();
         let path = path.replace('\\', "/");
         let name = self.file.file_name().unwrap();
-        write!(
-            f,
-            " [{}](https://github.com/rust-lang/rust-analyzer/blob/master/{}#L{}) ",
-            name.to_str().unwrap(),
-            path,
-            self.line
-        )
+        write!(f, " [{}](/{}#{}) ", name.to_str().unwrap(), path, self.line)
     }
 }
 
diff --git a/xtask/src/tidy.rs b/xtask/src/tidy.rs
index b500b251ed..fbc88e7acf 100644
--- a/xtask/src/tidy.rs
+++ b/xtask/src/tidy.rs
@@ -186,7 +186,7 @@ Zlib OR Apache-2.0 OR MIT
 
 fn check_test_attrs(path: &Path, text: &str) {
     let panic_rule =
-        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/book/src/contributing/style.md#should_panic";
+        "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#should_panic";
     let need_panic: &[&str] = &[
         // This file.
         "slow-tests/tidy.rs",


Test patch:
diff --git a/crates/hir-ty/src/mir/eval/tests.rs b/crates/hir-ty/src/mir/eval/tests.rs
index 2b5486fc5f..9625ae5f88 100644
--- a/crates/hir-ty/src/mir/eval/tests.rs
+++ b/crates/hir-ty/src/mir/eval/tests.rs
@@ -3,7 +3,7 @@ use span::{Edition, EditionedFileId};
 use syntax::{TextRange, TextSize};
 use test_fixture::WithFixture;
 
-use crate::{db::HirDatabase, mir::MirLowerError, test_db::TestDB, Interner, Substitution};
+use crate::{db::HirDatabase, test_db::TestDB, Interner, Substitution};
 
 use super::{interpret_mir, MirEvalError};
 
@@ -84,16 +84,6 @@ fn check_panic(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected_panic:
     assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic);
 }
 
-fn check_error_with(
-    #[rust_analyzer::rust_fixture] ra_fixture: &str,
-    expect_err: impl FnOnce(MirEvalError) -> bool,
-) {
-    let (db, file_ids) = TestDB::with_many_files(ra_fixture);
-    let file_id = *file_ids.last().unwrap();
-    let e = eval_main(&db, file_id).unwrap_err();
-    assert!(expect_err(e));
-}
-
 #[test]
 fn function_with_extern_c_abi() {
     check_pass(
@@ -955,27 +945,3 @@ fn main() {
 "#,
     );
 }
-
-#[test]
-fn regression_19177() {
-    check_error_with(
-        r#"
-//- minicore: copy
-trait Foo {}
-trait Bar {}
-trait Baz {}
-trait Qux {
-    type Assoc;
-}
-
-fn main<'a, T: Foo + Bar + Baz>(
-    x: &T,
-    y: (),
-    z: &'a dyn Qux<Assoc = T>,
-    w: impl Foo + Bar,
-) {
-}
-"#,
-        |e| matches!(e, MirEvalError::MirLowerError(_, MirLowerError::GenericArgNotProvided(..))),
-    );
-}
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index 7e7c1f835c..ef94814d58 100644
--- a/crates/hir-ty/src/tests/coercion.rs
+++ b/crates/hir-ty/src/tests/coercion.rs
@@ -535,7 +535,7 @@ fn test() {
 
 #[test]
 fn coerce_unsize_generic() {
-    check(
+    check_no_mismatches(
         r#"
 //- minicore: coerce_unsized
 struct Foo<T> { t: T };
@@ -543,9 +543,7 @@ struct Bar<T>(Foo<T>);
 
 fn test() {
     let _: &Foo<[usize]> = &Foo { t: [1, 2, 3] };
-                         //^^^^^^^^^^^^^^^^^^^^^ expected &'? Foo<[usize]>, got &'? Foo<[i32; 3]>
     let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
-                         //^^^^^^^^^^^^^^^^^^^^^^^^^^ expected &'? Bar<[usize]>, got &'? Bar<[i32; 3]>
 }
 "#,
     );
@@ -957,3 +955,24 @@ fn f() {
     "#,
     );
 }
+
+#[test]
+fn coerce_nested_unsized_struct() {
+    check_types(
+        r#"
+//- minicore: fn, coerce_unsized, dispatch_from_dyn, sized
+use core::marker::Unsize;
+
+struct Foo<T: ?Sized>(T);
+
+fn need(_: &Foo<dyn Fn(i32) -> i32>) {
+}
+
+fn test() {
+    let callback = |x| x;
+                  //^ i32
+    need(&Foo(callback));
+}
+"#,
+    )
+}
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index dda7bfb2ba..f0eb41b1ce 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -4694,21 +4694,21 @@ fn f<T: Send, U>() {
     Struct::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^Yes
     Struct::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^{unknown}
     Struct::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     Enum::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^Yes
     Enum::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^{unknown}
     Enum::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     Union::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^Yes
     Union::<U>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^{unknown}
     Union::<*const T>::IS_SEND;
-  //^^^^^^^^^^^^^^^^^^^^^^^^^^Yes
+  //^^^^^^^^^^^^^^^^^^^^^^^^^^{unknown}
     PhantomData::<T>::IS_SEND;
   //^^^^^^^^^^^^^^^^^^^^^^^^^Yes
     PhantomData::<U>::IS_SEND;
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 11aeb21c77..48d2af6d3f 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -34,26 +34,6 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
-    code_action_grouping: true,
-};
-
-pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
-    snippet_cap: SnippetCap::new(true),
-    allowed: None,
-    insert_use: InsertUseConfig {
-        granularity: ImportGranularity::Crate,
-        prefix_kind: hir::PrefixKind::Plain,
-        enforce_granularity: true,
-        group: true,
-        skip_glob_imports: true,
-    },
-    prefer_no_std: false,
-    prefer_prelude: true,
-    prefer_absolute: false,
-    assist_emit_must_use: false,
-    term_search_fuel: 400,
-    term_search_borrowck: true,
-    code_action_grouping: false,
 };
 
 pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
@@ -72,7 +52,6 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
-    code_action_grouping: true,
 };
 
 pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
@@ -91,7 +70,6 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
     assist_emit_must_use: false,
     term_search_fuel: 400,
     term_search_borrowck: true,
-    code_action_grouping: true,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, EditionedFileId) {
@@ -195,20 +173,6 @@ pub(crate) fn check_assist_not_applicable_for_import_one(
     );
 }
 
-#[track_caller]
-pub(crate) fn check_assist_not_applicable_no_grouping(
-    assist: Handler,
-    #[rust_analyzer::rust_fixture] ra_fixture: &str,
-) {
-    check_with_config(
-        TEST_CONFIG_NO_GROUPING,
-        assist,
-        ra_fixture,
-        ExpectedResult::NotApplicable,
-        None,
-    );
-}
-
 /// Check assist in unresolved state. Useful to check assists for lazy computation.
 #[track_caller]
 pub(crate) fn check_assist_unresolved(
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 1a74773158..c8ea8c547a 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -721,16 +721,16 @@ mod err {
     #[test]
     fn bad_asm_expr() { run_and_expect_errors("test_data/parser/inline/err/bad_asm_expr.rs"); }
     #[test]
-    fn comma_after_default_values_syntax() {
-        run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
-    }
-    #[test]
     fn comma_after_functional_update_syntax() {
         run_and_expect_errors(
             "test_data/parser/inline/err/comma_after_functional_update_syntax.rs",
         );
     }
     #[test]
+    fn comma_after_default_values_syntax() {
+        run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
+    }
+    #[test]
     fn crate_visibility_empty_recover() {
         run_and_expect_errors("test_data/parser/inline/err/crate_visibility_empty_recover.rs");
     }
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index fae0b6fcca..880e90c52a 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -61,11 +61,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -137,11 +132,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -213,11 +203,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -289,11 +274,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -361,10 +341,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-            ),
-        ),
     },
 }
\ No newline at end of file
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index fae0b6fcca..880e90c52a 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -61,11 +61,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -137,11 +132,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -213,11 +203,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -289,11 +274,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -361,10 +341,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-            ),
-        ),
     },
 }
\ No newline at end of file
diff --git a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 566174882d..7746acd225 100644
--- a/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -60,11 +60,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     1: CrateData {
         root_file_id: FileId(
@@ -135,11 +130,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     2: CrateData {
         root_file_id: FileId(
@@ -210,11 +200,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     3: CrateData {
         root_file_id: FileId(
@@ -285,11 +270,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$hello-world",
-            ),
-        ),
     },
     4: CrateData {
         root_file_id: FileId(
@@ -357,10 +337,5 @@
             name: "libc",
         },
         is_proc_macro: false,
-        proc_macro_cwd: Some(
-            AbsPathBuf(
-                "$ROOT$.cargo/registry/src/github.com-1ecc6299db9ec823/libc-0.2.98",
-            ),
-        ),
     },
 }
\ No newline at end of file
diff --git a/crates/project-model/test_data/output/rust_project_cfg_groups.txt b/crates/project-model/test_data/output/rust_project_cfg_groups.txt
index 9b4be19c41..587d3c1782 100644
--- a/crates/project-model/test_data/output/rust_project_cfg_groups.txt
+++ b/crates/project-model/test_data/output/rust_project_cfg_groups.txt
@@ -38,7 +38,6 @@
             Alloc,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -70,7 +69,6 @@
             Core,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -102,7 +100,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -134,7 +131,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -183,7 +179,6 @@
             ProcMacro,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     5: CrateData {
         root_file_id: FileId(
@@ -215,7 +210,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     6: CrateData {
         root_file_id: FileId(
@@ -312,7 +306,6 @@
             Std,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     7: CrateData {
         root_file_id: FileId(
@@ -344,7 +337,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     8: CrateData {
         root_file_id: FileId(
@@ -376,7 +368,6 @@
             Test,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     9: CrateData {
         root_file_id: FileId(
@@ -408,7 +399,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     10: CrateData {
         root_file_id: FileId(
@@ -487,7 +477,6 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     11: CrateData {
         root_file_id: FileId(
@@ -566,6 +555,5 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
 }
\ No newline at end of file
diff --git a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index 4c8e66e8e9..00805c79bc 100644
--- a/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -38,7 +38,6 @@
             Alloc,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     1: CrateData {
         root_file_id: FileId(
@@ -70,7 +69,6 @@
             Core,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     2: CrateData {
         root_file_id: FileId(
@@ -102,7 +100,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     3: CrateData {
         root_file_id: FileId(
@@ -134,7 +131,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     4: CrateData {
         root_file_id: FileId(
@@ -183,7 +179,6 @@
             ProcMacro,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     5: CrateData {
         root_file_id: FileId(
@@ -215,7 +210,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     6: CrateData {
         root_file_id: FileId(
@@ -312,7 +306,6 @@
             Std,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     7: CrateData {
         root_file_id: FileId(
@@ -344,7 +337,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     8: CrateData {
         root_file_id: FileId(
@@ -376,7 +368,6 @@
             Test,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     9: CrateData {
         root_file_id: FileId(
@@ -408,7 +399,6 @@
             Other,
         ),
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
     10: CrateData {
         root_file_id: FileId(
@@ -484,6 +474,5 @@
             ),
         },
         is_proc_macro: false,
-        proc_macro_cwd: None,
     },
 }
\ No newline at end of file
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index 37dfb87721..613f27c795 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -211,9 +211,8 @@ impl ChangeFixture {
                     From::from(meta.cfg.clone()),
                     Some(From::from(meta.cfg)),
                     meta.env,
-                    origin,
                     false,
-                    None,
+                    origin,
                 );
                 let prev = crates.insert(crate_name.clone(), crate_id);
                 assert!(prev.is_none(), "multiple crates with same name: {crate_name}");
@@ -250,9 +249,8 @@ impl ChangeFixture {
                 From::from(default_cfg.clone()),
                 Some(From::from(default_cfg)),
                 default_env,
-                CrateOrigin::Local { repo: None, name: None },
                 false,
-                None,
+                CrateOrigin::Local { repo: None, name: None },
             );
         } else {
             for (from, to, prelude) in crate_deps {
@@ -288,9 +286,8 @@ impl ChangeFixture {
                     String::from("__ra_is_test_fixture"),
                     String::from("__ra_is_test_fixture"),
                 )]),
-                CrateOrigin::Lang(LangCrateOrigin::Core),
                 false,
-                None,
+                CrateOrigin::Lang(LangCrateOrigin::Core),
             );
 
             for krate in all_crates {
@@ -336,9 +333,8 @@ impl ChangeFixture {
                     String::from("__ra_is_test_fixture"),
                     String::from("__ra_is_test_fixture"),
                 )]),
-                CrateOrigin::Local { repo: None, name: None },
                 true,
-                None,
+                CrateOrigin::Local { repo: None, name: None },
             );
             proc_macros.insert(proc_macros_crate, Ok(proc_macro));
 
@@ -366,6 +362,7 @@ impl ChangeFixture {
             crate_graph
                 .iter()
                 .zip(iter::repeat(From::from(CrateWorkspaceData {
+                    proc_macro_cwd: None,
                     data_layout: target_data_layout,
                     toolchain,
                 })))
diff --git a/xtask/src/codegen/parser_inline_tests.rs b/xtask/src/codegen/parser_inline_tests.rs
index 88732cebe7..f9f73df8eb 100644
--- a/xtask/src/codegen/parser_inline_tests.rs
+++ b/xtask/src/codegen/parser_inline_tests.rs
@@ -18,87 +18,92 @@ use crate::{
     util::list_rust_files,
 };
 
-pub(crate) fn generate(check: bool) {
-    let parser_crate_root = project_root().join("crates/parser");
-    let parser_test_data = parser_crate_root.join("test_data");
-    let parser_test_data_inline = parser_test_data.join("parser/inline");
+const PARSER_CRATE_ROOT: &str = "crates/parser";
+const PARSER_TEST_DATA: &str = "crates/parser/test_data";
+const PARSER_TEST_DATA_INLINE: &str = "crates/parser/test_data/parser/inline";
 
-    let tests = tests_from_dir(&parser_crate_root.join("src/grammar"));
+pub(crate) fn generate(check: bool) {
+    let tests = tests_from_dir(
+        &project_root().join(Path::new(&format!("{PARSER_CRATE_ROOT}/src/grammar"))),
+    );
 
     let mut some_file_was_updated = false;
     some_file_was_updated |=
-        install_tests(&tests.ok, parser_test_data_inline.join("ok"), check).unwrap();
+        install_tests(&tests.ok, &format!("{PARSER_TEST_DATA_INLINE}/ok"), check).unwrap();
     some_file_was_updated |=
-        install_tests(&tests.err, parser_test_data_inline.join("err"), check).unwrap();
+        install_tests(&tests.err, &format!("{PARSER_TEST_DATA_INLINE}/err"), check).unwrap();
 
     if some_file_was_updated {
-        let _ = fs::File::open(parser_crate_root.join("src/tests.rs"))
+        let _ = fs::File::open(format!("{PARSER_CRATE_ROOT}/src/tests.rs"))
             .unwrap()
             .set_modified(SystemTime::now());
-    }
 
-    let ok_tests = tests.ok.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
-        let test_name = quote::format_ident!("{}", test.name);
-        let test_file = format!("test_data/parser/inline/ok/{test_name}.rs");
-        let (test_func, args) = match &test.edition {
-            Some(edition) => {
-                let edition = quote::format_ident!("Edition{edition}");
-                (
-                    quote::format_ident!("run_and_expect_no_errors_with_edition"),
-                    quote::quote! {#test_file, crate::Edition::#edition},
-                )
+        let ok_tests = tests.ok.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+            let test_name = quote::format_ident!("{}", test.name);
+            let test_file = format!("test_data/parser/inline/ok/{test_name}.rs");
+            let (test_func, args) = match &test.edition {
+                Some(edition) => {
+                    let edition = quote::format_ident!("Edition{edition}");
+                    (
+                        quote::format_ident!("run_and_expect_no_errors_with_edition"),
+                        quote::quote! {#test_file, crate::Edition::#edition},
+                    )
+                }
+                None => {
+                    (quote::format_ident!("run_and_expect_no_errors"), quote::quote! {#test_file})
+                }
+            };
+            quote::quote! {
+                #[test]
+                fn #test_name() {
+                    #test_func(#args);
+                }
             }
-            None => (quote::format_ident!("run_and_expect_no_errors"), quote::quote! {#test_file}),
-        };
-        quote::quote! {
-            #[test]
-            fn #test_name() {
-                #test_func(#args);
+        });
+        let err_tests = tests.err.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
+            let test_name = quote::format_ident!("{}", test.name);
+            let test_file = format!("test_data/parser/inline/err/{test_name}.rs");
+            let (test_func, args) = match &test.edition {
+                Some(edition) => {
+                    let edition = quote::format_ident!("Edition{edition}");
+                    (
+                        quote::format_ident!("run_and_expect_errors_with_edition"),
+                        quote::quote! {#test_file, crate::Edition::#edition},
+                    )
+                }
+                None => (quote::format_ident!("run_and_expect_errors"), quote::quote! {#test_file}),
+            };
+            quote::quote! {
+                #[test]
+                fn #test_name() {
+                    #test_func(#args);
+                }
             }
-        }
-    });
-    let err_tests = tests.err.values().sorted_by(|a, b| a.name.cmp(&b.name)).map(|test| {
-        let test_name = quote::format_ident!("{}", test.name);
-        let test_file = format!("test_data/parser/inline/err/{test_name}.rs");
-        let (test_func, args) = match &test.edition {
-            Some(edition) => {
-                let edition = quote::format_ident!("Edition{edition}");
-                (
-                    quote::format_ident!("run_and_expect_errors_with_edition"),
-                    quote::quote! {#test_file, crate::Edition::#edition},
-                )
+        });
+
+        let output = quote::quote! {
+            mod ok {
+                use crate::tests::*;
+                #(#ok_tests)*
             }
-            None => (quote::format_ident!("run_and_expect_errors"), quote::quote! {#test_file}),
-        };
-        quote::quote! {
-            #[test]
-            fn #test_name() {
-                #test_func(#args);
+            mod err {
+                use crate::tests::*;
+                #(#err_tests)*
             }
-        }
-    });
+        };
 
-    let output = quote::quote! {
-        mod ok {
-            use crate::tests::*;
-            #(#ok_tests)*
-        }
-        mod err {
-            use crate::tests::*;
-            #(#err_tests)*
-        }
-    };
-
-    let pretty = reformat(output.to_string());
-    ensure_file_contents(
-        crate::flags::CodegenType::ParserTests,
-        parser_test_data.join("generated/runner.rs").as_ref(),
-        &pretty,
-        check,
-    );
+        let pretty = reformat(output.to_string());
+        ensure_file_contents(
+            crate::flags::CodegenType::ParserTests,
+            format!("{PARSER_TEST_DATA}/generated/runner.rs").as_ref(),
+            &pretty,
+            check,
+        );
+    }
 }
 
-fn install_tests(tests: &HashMap<String, Test>, tests_dir: PathBuf, check: bool) -> Result<bool> {
+fn install_tests(tests: &HashMap<String, Test>, into: &str, check: bool) -> Result<bool> {
+    let tests_dir = project_root().join(into);
     if !tests_dir.is_dir() {
         fs::create_dir_all(&tests_dir)?;
     }