Repository: rust-lang/rust-analyzer
Pull request #19189 (2025-02-20 12:05:29)

minor: Improve unset `OUT_DIR` error message


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/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-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs
index 310ddaaf9e..55242ab3e5 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, enable "build scripts" to fix"#,
+                r#"`OUT_DIR` not set, build scripts may have failed to run"#,
             ));
         }
 
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/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/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-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs
index 99894fefef..2f13298589 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, enable "build scripts" to fix
+                      //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
 "#,
         );
     }
@@ -186,7 +186,7 @@ fn main() {
        //^^^^^^^ error: expected string literal
 
     env!("OUT_DIR");
-       //^^^^^^^^^ error: `OUT_DIR` not set, enable "build scripts" to fix
+       //^^^^^^^^^ error: `OUT_DIR` not set, build scripts may have failed to run
 
     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/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/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/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/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/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/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/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,
                 })))