about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorRalf Jung <post@ralfj.de>2023-11-30 11:02:40 +0100
committerRalf Jung <post@ralfj.de>2023-11-30 11:02:40 +0100
commit7a661d048ca63c58fe45399ac813f347fa754294 (patch)
tree6ea6290c08709fe4102bdf4dc88f8849cb69f647 /src
parent76ec47782ad310262598c21b618225d718cefbea (diff)
parent2d476222e8458aa873e6760aac189b5e9d0a9930 (diff)
Merge from rustc
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/bootstrap.py5
-rw-r--r--src/bootstrap/src/core/build_steps/llvm.rs18
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs14
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile59
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile2
-rwxr-xr-xsrc/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh (renamed from src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh)0
-rw-r--r--src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile2
-rw-r--r--src/ci/github-actions/ci.yml7
-rw-r--r--src/doc/rustc/src/platform-support/nto-qnx.md6
-rw-r--r--src/doc/unstable-book/src/compiler-flags/function-return.md25
-rw-r--r--src/librustdoc/clean/mod.rs7
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/clean/utils.rs3
-rw-r--r--src/librustdoc/formats/mod.rs15
-rw-r--r--src/librustdoc/html/format.rs2
-rw-r--r--src/librustdoc/html/render/mod.rs17
-rw-r--r--src/librustdoc/html/render/print_item.rs5
-rw-r--r--src/librustdoc/html/render/write_shared.rs4
-rw-r--r--src/librustdoc/html/static/js/main.js3
m---------src/tools/cargo0
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/precedence.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs1
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/compiletest/src/common.rs3
-rw-r--r--src/tools/compiletest/src/header/cfg.rs4
-rw-r--r--src/tools/compiletest/src/lib.rs3
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs26
-rw-r--r--src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs27
-rw-r--r--src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr15
-rw-r--r--src/tools/rust-analyzer/Cargo.lock304
-rw-r--r--src/tools/rust-analyzer/crates/base-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/fixture.rs28
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs189
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/cfg/src/lib.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs69
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs77
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/extend_selection.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs52
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs67
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json140
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json66
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt7
-rw-r--r--src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs27
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs26
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml8
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc2
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json5
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts3
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lang_client.ts26
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/lib.rs169
-rw-r--r--src/tools/rustfmt/src/expr.rs2
-rw-r--r--src/tools/rustfmt/src/pairs.rs2
-rw-r--r--src/tools/rustfmt/src/patterns.rs5
-rw-r--r--src/tools/tidy/src/deps.rs1
81 files changed, 1311 insertions, 461 deletions
diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py
index 5a84e37f8cf..4691fb3ad6f 100644
--- a/src/bootstrap/bootstrap.py
+++ b/src/bootstrap/bootstrap.py
@@ -1083,6 +1083,11 @@ def bootstrap(args):
         include_file = 'config.{}.toml'.format(profile_aliases.get(profile) or profile)
         include_dir = os.path.join(rust_root, 'src', 'bootstrap', 'defaults')
         include_path = os.path.join(include_dir, include_file)
+
+        if not os.path.exists(include_path):
+            raise Exception("Unrecognized config profile '{}'. Check src/bootstrap/defaults"
+            " for available options.".format(profile))
+
         # HACK: This works because `self.get_toml()` returns the first match it finds for a
         # specific key, so appending our defaults at the end allows the user to override them
         with open(include_path) as included_toml:
diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs
index f710c01ca33..7c119b0273b 100644
--- a/src/bootstrap/src/core/build_steps/llvm.rs
+++ b/src/bootstrap/src/core/build_steps/llvm.rs
@@ -15,6 +15,7 @@ use std::fs::{self, File};
 use std::io;
 use std::path::{Path, PathBuf};
 use std::process::Command;
+use std::sync::OnceLock;
 
 use crate::core::builder::{Builder, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
@@ -105,13 +106,16 @@ pub fn prebuilt_llvm_config(
     let llvm_cmake_dir = out_dir.join("lib/cmake/llvm");
     let res = LlvmResult { llvm_config: build_llvm_config, llvm_cmake_dir };
 
-    let smart_stamp_hash = generate_smart_stamp_hash(
-        &builder.config.src.join("src/llvm-project"),
-        &builder.in_tree_llvm_info.sha().unwrap_or_default(),
-    );
+    static STAMP_HASH_MEMO: OnceLock<String> = OnceLock::new();
+    let smart_stamp_hash = STAMP_HASH_MEMO.get_or_init(|| {
+        generate_smart_stamp_hash(
+            &builder.config.src.join("src/llvm-project"),
+            &builder.in_tree_llvm_info.sha().unwrap_or_default(),
+        )
+    });
 
     let stamp = out_dir.join("llvm-finished-building");
-    let stamp = HashStamp::new(stamp, Some(&smart_stamp_hash));
+    let stamp = HashStamp::new(stamp, Some(smart_stamp_hash));
 
     if stamp.is_done() {
         if stamp.hash.is_none() {
@@ -565,11 +569,11 @@ fn check_llvm_version(builder: &Builder<'_>, llvm_config: &Path) {
     let version = output(cmd.arg("--version"));
     let mut parts = version.split('.').take(2).filter_map(|s| s.parse::<u32>().ok());
     if let (Some(major), Some(_minor)) = (parts.next(), parts.next()) {
-        if major >= 15 {
+        if major >= 16 {
             return;
         }
     }
-    panic!("\n\nbad LLVM version: {version}, need >=15.0\n\n")
+    panic!("\n\nbad LLVM version: {version}, need >=16.0\n\n")
 }
 
 fn configure_cmake(
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index ec859d30c82..77a4f2c4cb2 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -999,6 +999,7 @@ impl Step for RustdocGUI {
         let run = run.suite_path("tests/rustdoc-gui");
         run.lazy_default_condition(Box::new(move || {
             builder.config.nodejs.is_some()
+                && builder.doc_tests != DocTests::Only
                 && builder
                     .config
                     .npm
@@ -1158,7 +1159,8 @@ HELP: to skip test's attempt to check tidiness, pass `--skip src/tools/tidy` to
     }
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/tidy")
+        let default = run.builder.doc_tests != DocTests::Only;
+        run.path("src/tools/tidy").default_condition(default)
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1560,6 +1562,10 @@ impl Step for Compiletest {
     /// compiletest `mode` and `suite` arguments. For example `mode` can be
     /// "run-pass" or `suite` can be something like `debuginfo`.
     fn run(self, builder: &Builder<'_>) {
+        if builder.doc_tests == DocTests::Only {
+            return;
+        }
+
         if builder.top_stage == 0 && env::var("COMPILETEST_FORCE_STAGE0").is_err() {
             eprintln!("\
 ERROR: `--stage 0` runs compiletest on the beta compiler, not your local changes, and will almost always cause tests to fail
@@ -1821,6 +1827,10 @@ NOTE: if you're sure you want to do this, please open an issue as to why. In the
 
         cmd.arg("--json");
 
+        if builder.config.rust_debug_assertions_std {
+            cmd.arg("--with-debug-assertions");
+        };
+
         let mut llvm_components_passed = false;
         let mut copts_passed = false;
         if builder.config.llvm_enabled() {
@@ -2323,6 +2333,8 @@ impl Step for CrateLibrustc {
     }
 
     fn run(self, builder: &Builder<'_>) {
+        builder.ensure(compile::Std::new(self.compiler, self.target));
+
         builder.ensure(Crate {
             compiler: self.compiler,
             target: self.target,
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
deleted file mode 100644
index cefdcad7643..00000000000
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/Dockerfile
+++ /dev/null
@@ -1,59 +0,0 @@
-FROM ubuntu:22.04
-
-ARG DEBIAN_FRONTEND=noninteractive
-
-RUN apt-get update && apt-get install -y --no-install-recommends \
-  g++ \
-  gcc-multilib \
-  make \
-  ninja-build \
-  file \
-  curl \
-  ca-certificates \
-  python3.11 \
-  git \
-  cmake \
-  sudo \
-  gdb \
-  llvm-15-tools \
-  llvm-15-dev \
-  libedit-dev \
-  libssl-dev \
-  pkg-config \
-  zlib1g-dev \
-  xz-utils \
-  nodejs \
-  mingw-w64 \
-  libgccjit-12-dev \
-  && rm -rf /var/lib/apt/lists/*
-
-# Install powershell (universal package) so we can test x.ps1 on Linux
-RUN curl -sL "https://github.com/PowerShell/PowerShell/releases/download/v7.3.1/powershell_7.3.1-1.deb_amd64.deb" > powershell.deb && \
-    dpkg -i powershell.deb && \
-    rm -f powershell.deb
-
-COPY scripts/sccache.sh /scripts/
-RUN sh /scripts/sccache.sh
-
-# Make `libgccjit.so` accessible to the linker.
-RUN ln -s /usr/lib/gcc/x86_64-linux-gnu/12/libgccjit.so /usr/lib/x86_64-linux-gnu/libgccjit.so
-
-# We are disabling CI LLVM since this builder is intentionally using a host
-# LLVM, rather than the typical src/llvm-project LLVM.
-ENV NO_DOWNLOAD_CI_LLVM 1
-
-# This is not the latest LLVM version, so some components required by tests may
-# be missing.
-ENV IS_NOT_LATEST_LLVM 1
-
-# Using llvm-link-shared due to libffi issues -- see #34486
-ENV RUST_CONFIGURE_ARGS \
-      --build=x86_64-unknown-linux-gnu \
-      --llvm-root=/usr/lib/llvm-15 \
-      --enable-llvm-link-shared \
-      $USE_NEW_MANGLING \
-      --set rust.thin-lto-import-instr-limit=10
-
-COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/
-
-ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
index c177e7387fc..4757c3e7329 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/Dockerfile
@@ -49,6 +49,6 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/
+COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
 
 ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh
index 2eb751ca376..2eb751ca376 100755
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-15/script.sh
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-16/script.sh
diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
index 76846f1fed7..dc5a04d4e06 100644
--- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
+++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-17/Dockerfile
@@ -45,6 +45,6 @@ ENV RUST_CONFIGURE_ARGS \
       --enable-llvm-link-shared \
       --set rust.thin-lto-import-instr-limit=10
 
-COPY host-x86_64/x86_64-gnu-llvm-15/script.sh /tmp/
+COPY host-x86_64/x86_64-gnu-llvm-16/script.sh /tmp/
 
 ENV SCRIPT /tmp/script.sh
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index da29ffb8e5f..5b9c90273a3 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -334,7 +334,7 @@ jobs:
           - name: mingw-check-tidy
             <<: *job-linux-4c
 
-          - name: x86_64-gnu-llvm-15
+          - name: x86_64-gnu-llvm-16
             env:
               ENABLE_GCC_CODEGEN: "1"
             <<: *job-linux-16c
@@ -486,11 +486,6 @@ jobs:
               RUST_BACKTRACE: 1
             <<: *job-linux-8c
 
-          - name: x86_64-gnu-llvm-15
-            env:
-              RUST_BACKTRACE: 1
-            <<: *job-linux-8c
-
           - name: x86_64-gnu-nopt
             <<: *job-linux-4c
 
diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md
index 9f0662783a4..2a741fa3d02 100644
--- a/src/doc/rustc/src/platform-support/nto-qnx.md
+++ b/src/doc/rustc/src/platform-support/nto-qnx.md
@@ -121,10 +121,8 @@ export build_env='
 
 env $build_env \
     ./x.py build \
-        --target aarch64-unknown-nto-qnx710 \
-        --target x86_64-pc-nto-qnx710 \
-        --target x86_64-unknown-linux-gnu \
-        rustc library/core library/alloc
+        --target aarch64-unknown-nto-qnx710,x86_64-pc-nto-qnx710,x86_64-unknown-linux-gnu \
+        rustc library/core library/alloc library/std
 ```
 
 ## Running the Rust test suite
diff --git a/src/doc/unstable-book/src/compiler-flags/function-return.md b/src/doc/unstable-book/src/compiler-flags/function-return.md
new file mode 100644
index 00000000000..d044a6f68aa
--- /dev/null
+++ b/src/doc/unstable-book/src/compiler-flags/function-return.md
@@ -0,0 +1,25 @@
+# `function-return`
+
+The tracking issue for this feature is: https://github.com/rust-lang/rust/issues/116853.
+
+------------------------
+
+Option `-Zfunction-return` controls how function returns are converted.
+
+It is equivalent to [Clang]'s and [GCC]'s `-mfunction-return`. The Linux kernel
+uses it for RETHUNK builds. For details, see [LLVM commit 2240d72f15f3] ("[X86]
+initial -mfunction-return=thunk-extern support") which introduces the feature.
+
+Supported values for this option are:
+
+  - `keep`: do not convert function returns.
+  - `thunk-extern`: convert function returns (`ret`) to jumps (`jmp`)
+    to an external symbol called `__x86_return_thunk`.
+
+Like in Clang, GCC's values `thunk` and `thunk-inline` are not supported.
+
+Only x86 and non-large code models are supported.
+
+[Clang]: https://clang.llvm.org/docs/ClangCommandLineReference.html#cmdoption-clang-mfunction-return
+[GCC]: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html#index-mfunction-return
+[LLVM commit 2240d72f15f3]: https://github.com/llvm/llvm-project/commit/2240d72f15f3b7b9d9fb65450f9bf635fd310f6f
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index dc9098d3ade..fe1f43835ef 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -1821,11 +1821,8 @@ fn maybe_expand_private_type_alias<'tcx>(
                     }
                     _ => None,
                 });
-                if let Some(ct) = const_ {
-                    args.insert(
-                        param.def_id.to_def_id(),
-                        SubstParam::Constant(clean_const(ct, cx)),
-                    );
+                if let Some(_) = const_ {
+                    args.insert(param.def_id.to_def_id(), SubstParam::Constant);
                 }
                 // FIXME(const_generics_defaults)
                 indices.consts += 1;
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index f079d01bd84..7a5cf803137 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2546,7 +2546,7 @@ pub(crate) enum TypeBindingKind {
 pub(crate) enum SubstParam {
     Type(Type),
     Lifetime(Lifetime),
-    Constant(Constant),
+    Constant,
 }
 
 impl SubstParam {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index c22ad43e049..82f4a38384d 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
     debug!("trying to get a name from pattern: {p:?}");
 
     Symbol::intern(&match p.kind {
-        PatKind::Wild | PatKind::Struct(..) => return kw::Underscore,
+        // FIXME(never_patterns): does this make sense?
+        PatKind::Wild | PatKind::Never | PatKind::Struct(..) => return kw::Underscore,
         PatKind::Binding(_, _, ident, _) => return ident.name,
         PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
         PatKind::Or(pats) => {
diff --git a/src/librustdoc/formats/mod.rs b/src/librustdoc/formats/mod.rs
index e607a16ad54..0056fb48530 100644
--- a/src/librustdoc/formats/mod.rs
+++ b/src/librustdoc/formats/mod.rs
@@ -9,21 +9,6 @@ pub(crate) use renderer::{run_format, FormatRenderer};
 use crate::clean::{self, ItemId};
 use crate::html::render::Context;
 
-/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
-/// impl.
-pub(crate) enum AssocItemRender<'a> {
-    All,
-    DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
-}
-
-/// For different handling of associated items from the Deref target of a type rather than the type
-/// itself.
-#[derive(Copy, Clone, PartialEq)]
-pub(crate) enum RenderMode {
-    Normal,
-    ForDeref { mut_: bool },
-}
-
 /// Metadata about implementations for a type or trait.
 #[derive(Clone, Debug)]
 pub(crate) struct Impl {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index 06bfd4652d6..bed8f6ffef5 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1305,7 +1305,7 @@ impl clean::Impl {
                 primitive_link_fragment(
                     f,
                     PrimitiveType::Tuple,
-                    format_args!("fn ({name}₁, {name}₂, …, {name}ₙ{ellipsis})"),
+                    format_args!("fn({name}₁, {name}₂, …, {name}ₙ{ellipsis})"),
                     "#trait-implementations-1",
                     cx,
                 )?;
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index ff5c761208b..348d546c236 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -66,7 +66,7 @@ use crate::clean::{self, ItemId, RenderedLink, SelfTy};
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::formats::{AssocItemRender, Impl, RenderMode};
+use crate::formats::Impl;
 use crate::html::escape::Escape;
 use crate::html::format::{
     display_fn, href, join_with_double_colon, print_abi_with_space, print_constness_with_space,
@@ -89,6 +89,21 @@ pub(crate) fn ensure_trailing_slash(v: &str) -> impl fmt::Display + '_ {
     })
 }
 
+/// Specifies whether rendering directly implemented trait items or ones from a certain Deref
+/// impl.
+pub(crate) enum AssocItemRender<'a> {
+    All,
+    DerefFor { trait_: &'a clean::Path, type_: &'a clean::Type, deref_mut_: bool },
+}
+
+/// For different handling of associated items from the Deref target of a type rather than the type
+/// itself.
+#[derive(Copy, Clone, PartialEq)]
+pub(crate) enum RenderMode {
+    Normal,
+    ForDeref { mut_: bool },
+}
+
 // Helper structs for rendering items/sidebars and carrying along contextual
 // information
 
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index 14387e0d45d..2dac943f695 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -22,12 +22,13 @@ use super::{
     item_ty_to_section, notable_traits_button, notable_traits_json, render_all_impls,
     render_assoc_item, render_assoc_items, render_attributes_in_code, render_attributes_in_pre,
     render_impl, render_rightside, render_stability_since_raw,
-    render_stability_since_raw_with_extra, AssocItemLink, Context, ImplRenderingParameters,
+    render_stability_since_raw_with_extra, AssocItemLink, AssocItemRender, Context,
+    ImplRenderingParameters, RenderMode,
 };
 use crate::clean;
 use crate::config::ModuleSorting;
 use crate::formats::item_type::ItemType;
-use crate::formats::{AssocItemRender, Impl, RenderMode};
+use crate::formats::Impl;
 use crate::html::escape::Escape;
 use crate::html::format::{
     display_fn, join_with_double_colon, print_abi_with_space, print_constness_with_space,
diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs
index d2c7c578c08..b04776e91dc 100644
--- a/src/librustdoc/html/render/write_shared.rs
+++ b/src/librustdoc/html/render/write_shared.rs
@@ -15,14 +15,14 @@ use rustc_span::Symbol;
 use serde::ser::SerializeSeq;
 use serde::{Serialize, Serializer};
 
-use super::{collect_paths_for_type, ensure_trailing_slash, Context};
+use super::{collect_paths_for_type, ensure_trailing_slash, Context, RenderMode};
 use crate::clean::{Crate, Item, ItemId, ItemKind};
 use crate::config::{EmitType, RenderOptions};
 use crate::docfs::PathError;
 use crate::error::Error;
 use crate::formats::cache::Cache;
 use crate::formats::item_type::ItemType;
-use crate::formats::{Impl, RenderMode};
+use crate::formats::Impl;
 use crate::html::format::Buffer;
 use crate::html::render::{AssocItemLink, ImplRenderingParameters};
 use crate::html::{layout, static_files};
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 7cc0f2e8f1e..d613997cd7f 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -1318,8 +1318,7 @@ function preLoadCss(cssUrl) {
 
         const infos = [
             `For a full list of all search features, take a look <a \
-href="https://doc.rust-lang.org/${channel}/rustdoc/how-to-read-rustdoc.html\
-#the-search-interface">here</a>.`,
+href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.html">here</a>.`,
             "Prefix searches with a type followed by a colon (e.g., <code>fn:</code>) to \
              restrict the search to a given item kind.",
             "Accepted kinds are: <code>fn</code>, <code>mod</code>, <code>struct</code>, \
diff --git a/src/tools/cargo b/src/tools/cargo
-Subproject 9b13310ca596020a737aaa47daa4ed9ff8898a2
+Subproject 26333c732095d207aa05932ce863d850fb30938
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 575fead5bf3..630df9a84f5 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -46,7 +46,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         pats.iter().all(unary_pattern)
     }
     match &pat.kind {
-        PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Or(_) => {
+        PatKind::Slice(_, _, _) | PatKind::Range(_, _, _) | PatKind::Binding(..) | PatKind::Wild | PatKind::Never | PatKind::Or(_) => {
             false
         },
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index 70892ce608f..2ab04682f1d 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -1,7 +1,7 @@
 use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_note};
 use clippy_utils::is_span_if;
 use clippy_utils::source::snippet_opt;
-use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
+use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind};
 use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
 use rustc_middle::lint::in_external_macro;
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -144,7 +144,7 @@ fn check_assign(cx: &EarlyContext<'_>, expr: &Expr) {
             let eq_span = lhs.span.between(rhs.span);
             if let ExprKind::Unary(op, ref sub_rhs) = rhs.kind {
                 if let Some(eq_snippet) = snippet_opt(cx, eq_span) {
-                    let op = UnOp::to_string(op);
+                    let op = op.as_str();
                     let eqop_span = lhs.span.between(sub_rhs.span);
                     if eq_snippet.ends_with('=') {
                         span_lint_and_note(
@@ -177,11 +177,11 @@ fn check_unop(cx: &EarlyContext<'_>, expr: &Expr) {
         && let unop_operand_span = rhs.span.until(un_rhs.span)
         && let Some(binop_snippet) = snippet_opt(cx, binop_span)
         && let Some(unop_operand_snippet) = snippet_opt(cx, unop_operand_span)
-        && let binop_str = BinOpKind::to_string(&binop.node)
+        && let binop_str = binop.node.as_str()
         // no space after BinOp operator and space after UnOp operator
         && binop_snippet.ends_with(binop_str) && unop_operand_snippet.ends_with(' ')
     {
-        let unop_str = UnOp::to_string(op);
+        let unop_str = op.as_str();
         let eqop_span = lhs.span.between(un_rhs.span);
         span_lint_and_help(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 745be671b86..cbf478620ec 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -150,6 +150,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>]) {
 #[derive(Clone, Copy)]
 enum NormalizedPat<'a> {
     Wild,
+    Never,
     Struct(Option<DefId>, &'a [(Symbol, Self)]),
     Tuple(Option<DefId>, &'a [Self]),
     Or(&'a [Self]),
@@ -229,6 +230,7 @@ impl<'a> NormalizedPat<'a> {
             PatKind::Binding(.., Some(pat)) | PatKind::Box(pat) | PatKind::Ref(pat, _) => {
                 Self::from_pat(cx, arena, pat)
             },
+            PatKind::Never => Self::Never,
             PatKind::Struct(ref path, fields, _) => {
                 let fields =
                     arena.alloc_from_iter(fields.iter().map(|f| (f.ident.name, Self::from_pat(cx, arena, f.pat))));
@@ -333,6 +335,7 @@ impl<'a> NormalizedPat<'a> {
     fn has_overlapping_values(&self, other: &Self) -> bool {
         match (*self, *other) {
             (Self::Wild, _) | (_, Self::Wild) => true,
+            (Self::Never, Self::Never) => true,
             (Self::Or(pats), ref other) | (ref other, Self::Or(pats)) => {
                 pats.iter().any(|pat| pat.has_overlapping_values(other))
             },
diff --git a/src/tools/clippy/clippy_lints/src/precedence.rs b/src/tools/clippy/clippy_lints/src/precedence.rs
index b638e83997a..52cec437378 100644
--- a/src/tools/clippy/clippy_lints/src/precedence.rs
+++ b/src/tools/clippy/clippy_lints/src/precedence.rs
@@ -78,7 +78,7 @@ impl EarlyLintPass for Precedence {
                     let sugg = format!(
                         "({}) {} ({})",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
-                        op.to_string(),
+                        op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
                     span_sugg(expr, sugg, applicability);
@@ -87,7 +87,7 @@ impl EarlyLintPass for Precedence {
                     let sugg = format!(
                         "({}) {} {}",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
-                        op.to_string(),
+                        op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
                     span_sugg(expr, sugg, applicability);
@@ -96,7 +96,7 @@ impl EarlyLintPass for Precedence {
                     let sugg = format!(
                         "{} {} ({})",
                         snippet_with_applicability(cx, left.span, "..", &mut applicability),
-                        op.to_string(),
+                        op.as_str(),
                         snippet_with_applicability(cx, right.span, "..", &mut applicability)
                     );
                     span_sugg(expr, sugg, applicability);
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 92de7917871..b332309a552 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -298,7 +298,7 @@ fn replace_left_sugg(
 ) -> String {
     format!(
         "{left_suggestion} {} {}",
-        binop.op.to_string(),
+        binop.op.as_str(),
         snippet_with_applicability(cx, binop.right.span, "..", applicability),
     )
 }
@@ -312,7 +312,7 @@ fn replace_right_sugg(
     format!(
         "{} {} {right_suggestion}",
         snippet_with_applicability(cx, binop.left.span, "..", applicability),
-        binop.op.to_string(),
+        binop.op.as_str(),
     )
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 8ff088a208f..952c0dc72b1 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -226,7 +226,7 @@ fn transform_with_focus_on_idx(alternatives: &mut ThinVec<P<Pat>>, focus_idx: us
         // Therefore they are not some form of constructor `C`,
         // with which a pattern `C(p_0)` may be formed,
         // which we would want to join with other `C(p_j)`s.
-        Ident(.., None) | Lit(_) | Wild | Path(..) | Range(..) | Rest | MacCall(_)
+        Ident(.., None) | Lit(_) | Wild | Never | Path(..) | Range(..) | Rest | MacCall(_)
         // Skip immutable refs, as grouping them saves few characters,
         // and almost always requires adding parens (increasing noisiness).
         // In the case of only two patterns, replacement adds net characters.
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index e8842ce10f8..e83c04eda20 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -629,6 +629,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
 
         match pat.value.kind {
             PatKind::Wild => kind!("Wild"),
+            PatKind::Never => kind!("Never"),
             PatKind::Binding(ann, _, name, sub) => {
                 bind!(self, name);
                 opt_bind!(self, sub);
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 8031e6faa74..34ec83709ff 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1017,6 +1017,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                 }
                 e.hash(&mut self.s);
             },
+            PatKind::Never => {},
             PatKind::Wild => {},
         }
     }
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 172b063df31..fd37713fc60 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -1707,6 +1707,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 
     match pat.kind {
         PatKind::Wild => false,
+        PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.map_or(false, |pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Lit(..) | PatKind::Range(..) => true,
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index db79dd78801..f143163152e 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -382,7 +382,7 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String {
         | AssocOp::GreaterEqual => {
             format!(
                 "{lhs} {} {rhs}",
-                op.to_ast_binop().expect("Those are AST ops").to_string()
+                op.to_ast_binop().expect("Those are AST ops").as_str()
             )
         },
         AssocOp::Assign => format!("{lhs} = {rhs}"),
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index e7d2e1aab3a..e85f6319936 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -242,6 +242,9 @@ pub struct Config {
     /// Run ignored tests
     pub run_ignored: bool,
 
+    /// Whether to run tests with `ignore-debug` header
+    pub with_debug_assertions: bool,
+
     /// Only run tests that match these filters
     pub filters: Vec<String>,
 
diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs
index 3a1b9dff3a6..e2a04b7e558 100644
--- a/src/tools/compiletest/src/header/cfg.rs
+++ b/src/tools/compiletest/src/header/cfg.rs
@@ -190,8 +190,8 @@ pub(super) fn parse_cfg_name_directive<'a>(
     }
     condition! {
         name: "debug",
-        condition: cfg!(debug_assertions),
-        message: "when building with debug assertions",
+        condition: config.with_debug_assertions,
+        message: "when running tests with `ignore-debug` header",
     }
     condition! {
         name: config.debugger.as_ref().map(|d| d.to_str()),
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index bb09c03ef5b..5a80b9121f0 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -81,6 +81,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         )
         .optopt("", "run", "whether to execute run-* tests", "auto | always | never")
         .optflag("", "ignored", "run tests marked as ignored")
+        .optflag("", "with-debug-assertions", "whether to run tests with `ignore-debug` header")
         .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING")
         .optflag("", "exact", "filters match exactly")
         .optopt(
@@ -203,6 +204,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
 
     let src_base = opt_path(matches, "src-base");
     let run_ignored = matches.opt_present("ignored");
+    let with_debug_assertions = matches.opt_present("with-debug-assertions");
     let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode");
     let has_tidy = if mode == Mode::Rustdoc {
         Command::new("tidy")
@@ -238,6 +240,7 @@ pub fn parse_config(args: Vec<String>) -> Config {
         suite: matches.opt_str("suite").unwrap(),
         debugger: None,
         run_ignored,
+        with_debug_assertions,
         filters: matches.free.clone(),
         skip: matches.opt_strs("skip"),
         filter_exact: matches.opt_present("exact"),
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index ba40a1b3c32..be30627cf0c 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -66,11 +66,6 @@ pub trait FileDescriptor: std::fmt::Debug + Any {
     fn is_tty(&self, _communicate_allowed: bool) -> bool {
         false
     }
-
-    #[cfg(unix)]
-    fn as_unix_host_fd(&self) -> Option<i32> {
-        None
-    }
 }
 
 impl dyn FileDescriptor {
@@ -150,12 +145,6 @@ impl FileDescriptor for FileHandle {
         Ok(Box::new(FileHandle { file: duplicated, writable: self.writable }))
     }
 
-    #[cfg(unix)]
-    fn as_unix_host_fd(&self) -> Option<i32> {
-        use std::os::unix::io::AsRawFd;
-        Some(self.file.as_raw_fd())
-    }
-
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.file.is_terminal()
     }
@@ -183,11 +172,6 @@ impl FileDescriptor for io::Stdin {
         Ok(Box::new(io::stdin()))
     }
 
-    #[cfg(unix)]
-    fn as_unix_host_fd(&self) -> Option<i32> {
-        Some(libc::STDIN_FILENO)
-    }
-
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.is_terminal()
     }
@@ -220,11 +204,6 @@ impl FileDescriptor for io::Stdout {
         Ok(Box::new(io::stdout()))
     }
 
-    #[cfg(unix)]
-    fn as_unix_host_fd(&self) -> Option<i32> {
-        Some(libc::STDOUT_FILENO)
-    }
-
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.is_terminal()
     }
@@ -250,11 +229,6 @@ impl FileDescriptor for io::Stderr {
         Ok(Box::new(io::stderr()))
     }
 
-    #[cfg(unix)]
-    fn as_unix_host_fd(&self) -> Option<i32> {
-        Some(libc::STDERR_FILENO)
-    }
-
     fn is_tty(&self, communicate_allowed: bool) -> bool {
         communicate_allowed && self.is_terminal()
     }
diff --git a/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs
new file mode 100644
index 00000000000..98f9cc96fd0
--- /dev/null
+++ b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.rs
@@ -0,0 +1,27 @@
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
+
+use std::intrinsics::mir::*;
+use std::ptr;
+
+#[repr(C)]
+struct S(u8, u16);
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn main() {
+    mir! {
+        let s: S;
+        let sptr;
+        let sptr2;
+        let _val;
+        {
+            sptr = ptr::addr_of_mut!(s);
+            sptr2 = sptr as *mut [u8; 4];
+            *sptr2 = [0; 4];
+            *sptr = S(0, 0); // should reset the padding
+            _val = *sptr2; // should hence be UB
+            //~^ERROR: encountered uninitialized memory
+            Return()
+        }
+    }
+}
diff --git a/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr
new file mode 100644
index 00000000000..5f3d9bde1f2
--- /dev/null
+++ b/src/tools/miri/tests/fail/uninit-after-aggregate-assign.stderr
@@ -0,0 +1,15 @@
+error: Undefined Behavior: constructing invalid value at [1]: encountered uninitialized memory, but expected an integer
+  --> $DIR/uninit-after-aggregate-assign.rs:LL:CC
+   |
+LL |             _val = *sptr2; // should hence be UB
+   |             ^^^^^^^^^^^^^ constructing invalid value at [1]: encountered uninitialized memory, but expected an integer
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `main` at $DIR/uninit-after-aggregate-assign.rs:LL:CC
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 701e36d74a6..5a8d971c3d4 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -72,8 +72,8 @@ dependencies = [
  "cfg",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile",
+ "rust-analyzer-salsa",
  "rustc-hash",
- "salsa",
  "stdx",
  "syntax",
  "test-utils",
@@ -160,32 +160,32 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0322d5289ceba3217a03c9af72aa403d87542822b753daa1da32e4b992a4e80"
+checksum = "329427f28cd2bddaacd47c4dcd3d7082d315c61fb164394c690fe98c1b6ee9d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "synstructure",
 ]
 
 [[package]]
 name = "chalk-ir"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0946cbc6d9136980a24a2dddf1888b5f0aa978dda300a3aa470b55b777b6bf3c"
+checksum = "9e1e1659238bd598d0f7dbc5034cf1ff46010a3d6827704c9ed443c8359cb484"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.1",
  "chalk-derive",
  "lazy_static",
 ]
 
 [[package]]
 name = "chalk-recursive"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd93fedbeeadc0cd4d0eb73bd061b621af99f5324a6a518264c8ef5e526e0ec"
+checksum = "b3e0bff0ba1bed11407384fcec0353aeb6888901e63cb47d04505ec47adad847"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -196,15 +196,15 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.94.0"
+version = "0.95.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a254cff72303c58c82df421cfe9465606372b81588923fcf179922b7eaad9a53"
+checksum = "eb9c46d501cf83732a91056c0c846ae7a16d6b3c67a6a6bb5e9cc0a2e91563b6"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
  "ena",
- "indexmap 2.1.0",
- "itertools 0.10.5",
+ "indexmap",
+ "itertools",
  "petgraph",
  "rustc-hash",
  "tracing",
@@ -216,7 +216,7 @@ version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5080df6b0f0ecb76cab30808f00d937ba725cebe266a3da8cd89dff92f2a9916"
 dependencies = [
- "nix",
+ "nix 0.26.2",
  "winapi",
 ]
 
@@ -290,6 +290,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "ctrlc"
+version = "3.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "82e95fbd621905b854affdc67943b043a0fbb6ed7385fd5a25650d19a8a6cfdf"
+dependencies = [
+ "nix 0.27.1",
+ "windows-sys 0.48.0",
+]
+
+[[package]]
 name = "dashmap"
 version = "5.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -299,7 +309,7 @@ dependencies = [
  "hashbrown 0.12.3",
  "lock_api",
  "once_cell",
- "parking_lot_core 0.9.6",
+ "parking_lot_core",
 ]
 
 [[package]]
@@ -310,7 +320,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -450,12 +460,9 @@ checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
 
 [[package]]
 name = "heck"
-version = "0.3.3"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
-dependencies = [
- "unicode-segmentation",
-]
+checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
 name = "hermit-abi"
@@ -477,7 +484,7 @@ dependencies = [
  "hir-def",
  "hir-expand",
  "hir-ty",
- "itertools 0.12.0",
+ "itertools",
  "once_cell",
  "profile",
  "rustc-hash",
@@ -504,9 +511,9 @@ dependencies = [
  "fst",
  "hashbrown 0.12.3",
  "hir-expand",
- "indexmap 2.1.0",
+ "indexmap",
  "intern",
- "itertools 0.12.0",
+ "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "limit",
  "mbe",
@@ -534,7 +541,7 @@ dependencies = [
  "expect-test",
  "hashbrown 0.12.3",
  "intern",
- "itertools 0.12.0",
+ "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "limit",
  "mbe",
@@ -566,7 +573,7 @@ dependencies = [
  "hir-def",
  "hir-expand",
  "intern",
- "itertools 0.12.0",
+ "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "limit",
  "nohash-hasher",
@@ -613,7 +620,7 @@ dependencies = [
  "ide-db",
  "ide-diagnostics",
  "ide-ssr",
- "itertools 0.12.0",
+ "itertools",
  "nohash-hasher",
  "oorandom",
  "profile",
@@ -639,7 +646,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide-db",
- "itertools 0.12.0",
+ "itertools",
  "profile",
  "smallvec",
  "sourcegen",
@@ -658,7 +665,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide-db",
- "itertools 0.12.0",
+ "itertools",
  "once_cell",
  "profile",
  "smallvec",
@@ -679,8 +686,8 @@ dependencies = [
  "expect-test",
  "fst",
  "hir",
- "indexmap 2.1.0",
- "itertools 0.12.0",
+ "indexmap",
+ "itertools",
  "limit",
  "line-index 0.1.0-pre.1",
  "memchr",
@@ -711,7 +718,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide-db",
- "itertools 0.12.0",
+ "itertools",
  "once_cell",
  "profile",
  "serde_json",
@@ -730,7 +737,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide-db",
- "itertools 0.12.0",
+ "itertools",
  "nohash-hasher",
  "parser",
  "stdx",
@@ -752,16 +759,6 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "1.9.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
-dependencies = [
- "autocfg",
- "hashbrown 0.12.3",
-]
-
-[[package]]
-name = "indexmap"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f"
@@ -791,15 +788,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "instant"
-version = "0.1.12"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
-dependencies = [
- "cfg-if",
-]
-
-[[package]]
 name = "intern"
 version = "0.0.0"
 dependencies = [
@@ -811,15 +799,6 @@ dependencies = [
 
 [[package]]
 name = "itertools"
-version = "0.10.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
-dependencies = [
- "either",
-]
-
-[[package]]
-name = "itertools"
 version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0"
@@ -931,7 +910,7 @@ dependencies = [
  "crossbeam-channel",
  "ide",
  "ide-db",
- "itertools 0.12.0",
+ "itertools",
  "proc-macro-api",
  "project-model",
  "tracing",
@@ -961,6 +940,7 @@ name = "lsp-server"
 version = "0.7.4"
 dependencies = [
  "crossbeam-channel",
+ "ctrlc",
  "log",
  "lsp-types",
  "serde",
@@ -1101,6 +1081,17 @@ dependencies = [
 ]
 
 [[package]]
+name = "nix"
+version = "0.27.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053"
+dependencies = [
+ "bitflags 2.4.1",
+ "cfg-if",
+ "libc",
+]
+
+[[package]]
 name = "nohash-hasher"
 version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1176,37 +1167,12 @@ checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575"
 
 [[package]]
 name = "parking_lot"
-version = "0.11.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
-dependencies = [
- "instant",
- "lock_api",
- "parking_lot_core 0.8.6",
-]
-
-[[package]]
-name = "parking_lot"
 version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.6",
-]
-
-[[package]]
-name = "parking_lot_core"
-version = "0.8.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
-dependencies = [
- "cfg-if",
- "instant",
- "libc",
- "redox_syscall 0.2.16",
- "smallvec",
- "winapi",
+ "parking_lot_core",
 ]
 
 [[package]]
@@ -1276,7 +1242,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9"
 dependencies = [
  "fixedbitset",
- "indexmap 2.1.0",
+ "indexmap",
 ]
 
 [[package]]
@@ -1371,7 +1337,7 @@ dependencies = [
  "cargo_metadata",
  "cfg",
  "expect-test",
- "itertools 0.12.0",
+ "itertools",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "paths",
  "profile",
@@ -1436,50 +1402,43 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_abi"
-version = "0.19.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2ea80a299f04a896000ce17b76f3aa1d2fe59f347fbc99c4b8970316ef5a0d"
+checksum = "b5f38444d48da534b3bb612713fce9b0aeeffb2e0dfa242764f55482acc5b52d"
 dependencies = [
  "bitflags 1.3.2",
- "ra-ap-rustc_index 0.19.0",
+ "ra-ap-rustc_index",
  "tracing",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.14.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "643ca3609870b1778d9cd1f2a8e4ccb4af0f48f3637cc257a09494d087bd93dc"
-dependencies = [
- "arrayvec",
- "smallvec",
-]
-
-[[package]]
-name = "ra-ap-rustc_index"
-version = "0.19.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4556489ef652e5eb6cdad6078fff08507badac80bfc1f79085c85a6d8b77ab5c"
+checksum = "69fb5da07e1a39222d9c311203123c3b6a86420fa06dc695aa1661b0aecf8d16"
 dependencies = [
  "arrayvec",
+ "ra-ap-rustc_index_macros",
  "smallvec",
 ]
 
 [[package]]
-name = "ra-ap-rustc_lexer"
-version = "0.14.0"
+name = "ra-ap-rustc_index_macros"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30ffd24f9ba4f1d25ff27ca1469b8d22a3bdfb12cf644fc8bfcb63121fa5da6b"
+checksum = "3d69f9f6af58124f2da0cb8b0c3d8494e0d883a5fe0c6732258bde81ac5a87cc"
 dependencies = [
- "unicode-properties",
- "unicode-xid",
+ "proc-macro2",
+ "quote",
+ "syn",
+ "synstructure",
 ]
 
 [[package]]
 name = "ra-ap-rustc_lexer"
-version = "0.19.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90e573bf707e01fe2841dbdedeed42012004274db0edc0314e6e3e58a40598fc"
+checksum = "9d5e8650195795c4023d8321846466994a975bc457cb8a91c0b3b17a5fc8ba40"
 dependencies = [
  "unicode-properties",
  "unicode-xid",
@@ -1487,12 +1446,12 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_parse_format"
-version = "0.14.0"
+version = "0.20.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "207b5ac1a21d4926695e03b605ffb9f63d4968e0488e9197c04c512c37303aa7"
+checksum = "0a6b325ee1ec90e4dbd4394913adf4ef32e4fcf2b311ec9563a0fa50cd549af6"
 dependencies = [
- "ra-ap-rustc_index 0.14.0",
- "ra-ap-rustc_lexer 0.14.0",
+ "ra-ap-rustc_index",
+ "ra-ap-rustc_lexer",
 ]
 
 [[package]]
@@ -1563,7 +1522,7 @@ dependencies = [
  "ide",
  "ide-db",
  "ide-ssr",
- "itertools 0.12.0",
+ "itertools",
  "load-cargo",
  "lsp-server 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
  "lsp-types",
@@ -1573,8 +1532,8 @@ dependencies = [
  "nohash-hasher",
  "num_cpus",
  "oorandom",
- "parking_lot 0.12.1",
- "parking_lot_core 0.9.6",
+ "parking_lot",
+ "parking_lot_core",
  "parser",
  "proc-macro-api",
  "profile",
@@ -1604,6 +1563,35 @@ dependencies = [
 ]
 
 [[package]]
+name = "rust-analyzer-salsa"
+version = "0.17.0-pre.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4ca92b657d614d076800aa7bf5d5ba33564e71fa7f16cd79eacdfe301a50ab1c"
+dependencies = [
+ "crossbeam-utils",
+ "indexmap",
+ "lock_api",
+ "log",
+ "oorandom",
+ "parking_lot",
+ "rust-analyzer-salsa-macros",
+ "rustc-hash",
+ "smallvec",
+]
+
+[[package]]
+name = "rust-analyzer-salsa-macros"
+version = "0.17.0-pre.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b190359266d293f2ee13eaa502a766dc8b77b63fbaa5d460d24fd0210675ceef"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "rustc-demangle"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1614,8 +1602,8 @@ name = "rustc-dependencies"
 version = "0.0.0"
 dependencies = [
  "ra-ap-rustc_abi",
- "ra-ap-rustc_index 0.19.0",
- "ra-ap-rustc_lexer 0.19.0",
+ "ra-ap-rustc_index",
+ "ra-ap-rustc_lexer",
  "ra-ap-rustc_parse_format",
 ]
 
@@ -1632,35 +1620,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
 
 [[package]]
-name = "salsa"
-version = "0.17.0-pre.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b223dccb46c32753144d0b51290da7230bb4aedcd8379d6b4c9a474c18bf17a"
-dependencies = [
- "crossbeam-utils",
- "indexmap 1.9.3",
- "lock_api",
- "log",
- "oorandom",
- "parking_lot 0.11.2",
- "rustc-hash",
- "salsa-macros",
- "smallvec",
-]
-
-[[package]]
-name = "salsa-macros"
-version = "0.17.0-pre.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac6c2e352df550bf019da7b16164ed2f7fa107c39653d1311d1bba42d1582ff7"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
 name = "same-file"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1701,22 +1660,22 @@ dependencies = [
 
 [[package]]
 name = "serde"
-version = "1.0.192"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bca2a08484b285dcb282d0f67b26cadc0df8b19f8c12502c13d966bf9482f001"
+checksum = "25dd9975e68d0cb5aa1120c288333fc98731bd1dd12f561e468ea4728c042b89"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.192"
+version = "1.0.193"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6c7207fbec9faa48073f3e3074cbe553af6ea512d7c21ba46e434e70ea9fbc1"
+checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -1725,7 +1684,7 @@ version = "1.0.108"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
 dependencies = [
- "indexmap 2.1.0",
+ "indexmap",
  "itoa",
  "ryu",
  "serde",
@@ -1739,7 +1698,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -1800,17 +1759,6 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
 version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
@@ -1828,7 +1776,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "unicode-xid",
 ]
 
@@ -1839,8 +1787,8 @@ dependencies = [
  "cov-mark",
  "either",
  "expect-test",
- "indexmap 2.1.0",
- "itertools 0.12.0",
+ "indexmap",
+ "itertools",
  "once_cell",
  "parser",
  "proc-macro2",
@@ -1874,7 +1822,7 @@ dependencies = [
 name = "text-edit"
 version = "0.0.0"
 dependencies = [
- "itertools 0.12.0",
+ "itertools",
  "text-size",
 ]
 
@@ -1901,7 +1849,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -2002,7 +1950,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -2113,12 +2061,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
 
 [[package]]
-name = "unicode-segmentation"
-version = "1.10.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
-
-[[package]]
 name = "unicode-xid"
 version = "0.2.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2153,7 +2095,7 @@ name = "vfs"
 version = "0.0.0"
 dependencies = [
  "fst",
- "indexmap 2.1.0",
+ "indexmap",
  "nohash-hasher",
  "paths",
  "rustc-hash",
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index 171c113a950..5ad88f65188 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -12,7 +12,7 @@ rust-version.workspace = true
 doctest = false
 
 [dependencies]
-salsa = "0.17.0-pre.2"
+rust-analyzer-salsa = "0.17.0-pre.3"
 rustc-hash = "1.1.0"
 
 triomphe.workspace = true
diff --git a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
index 3f5ccb621c7..3da555a47ac 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/fixture.rs
@@ -13,9 +13,9 @@ use vfs::{file_set::FileSet, VfsPath};
 
 use crate::{
     input::{CrateName, CrateOrigin, LangCrateOrigin},
-    Change, CrateDisplayName, CrateGraph, CrateId, Dependency, Edition, Env, FileId, FilePosition,
-    FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError, ProcMacros, ReleaseChannel,
-    SourceDatabaseExt, SourceRoot, SourceRootId,
+    Change, CrateDisplayName, CrateGraph, CrateId, Dependency, DependencyKind, Edition, Env,
+    FileId, FilePosition, FileRange, ProcMacro, ProcMacroExpander, ProcMacroExpansionError,
+    ProcMacros, ReleaseChannel, SourceDatabaseExt, SourceRoot, SourceRootId,
 };
 
 pub const WORKSPACE: SourceRootId = SourceRootId(0);
@@ -237,7 +237,12 @@ impl ChangeFixture {
                 crate_graph
                     .add_dep(
                         from_id,
-                        Dependency::with_prelude(CrateName::new(&to).unwrap(), to_id, prelude),
+                        Dependency::with_prelude(
+                            CrateName::new(&to).unwrap(),
+                            to_id,
+                            prelude,
+                            DependencyKind::Normal,
+                        ),
                     )
                     .unwrap();
             }
@@ -275,7 +280,14 @@ impl ChangeFixture {
 
             for krate in all_crates {
                 crate_graph
-                    .add_dep(krate, Dependency::new(CrateName::new("core").unwrap(), core_crate))
+                    .add_dep(
+                        krate,
+                        Dependency::new(
+                            CrateName::new("core").unwrap(),
+                            core_crate,
+                            DependencyKind::Normal,
+                        ),
+                    )
                     .unwrap();
             }
         }
@@ -317,7 +329,11 @@ impl ChangeFixture {
                 crate_graph
                     .add_dep(
                         krate,
-                        Dependency::new(CrateName::new("proc_macros").unwrap(), proc_macros_crate),
+                        Dependency::new(
+                            CrateName::new("proc_macros").unwrap(),
+                            proc_macros_crate,
+                            DependencyKind::Normal,
+                        ),
                     )
                     .unwrap();
             }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 65db5c0fc7d..e4f78321e21 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -155,6 +155,10 @@ impl CrateOrigin {
     pub fn is_local(&self) -> bool {
         matches!(self, CrateOrigin::Local { .. })
     }
+
+    pub fn is_lib(&self) -> bool {
+        matches!(self, CrateOrigin::Library { .. })
+    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -324,6 +328,62 @@ pub struct CrateData {
     pub channel: Option<ReleaseChannel>,
 }
 
+impl CrateData {
+    /// Check if [`other`] is almost equal to [`self`] ignoring `CrateOrigin` value.
+    pub fn eq_ignoring_origin_and_deps(&self, other: &CrateData, ignore_dev_deps: bool) -> bool {
+        // This method has some obscure bits. These are mostly there to be compliant with
+        // some patches. References to the patches are given.
+        if self.root_file_id != other.root_file_id {
+            return false;
+        }
+
+        if self.display_name != other.display_name {
+            return false;
+        }
+
+        if self.is_proc_macro != other.is_proc_macro {
+            return false;
+        }
+
+        if self.edition != other.edition {
+            return false;
+        }
+
+        if self.version != other.version {
+            return false;
+        }
+
+        let mut opts = self.cfg_options.difference(&other.cfg_options);
+        if let Some(it) = opts.next() {
+            // Don't care if rust_analyzer CfgAtom is the only cfg in the difference set of self's and other's cfgs.
+            // https://github.com/rust-lang/rust-analyzer/blob/0840038f02daec6ba3238f05d8caa037d28701a0/crates/project-model/src/workspace.rs#L894
+            if it.to_string() != "rust_analyzer" {
+                return false;
+            }
+
+            if let Some(_) = opts.next() {
+                return false;
+            }
+        }
+
+        if self.env != other.env {
+            return false;
+        }
+
+        let slf_deps = self.dependencies.iter();
+        let other_deps = other.dependencies.iter();
+
+        if ignore_dev_deps {
+            return slf_deps
+                .clone()
+                .filter(|it| it.kind != DependencyKind::Dev)
+                .eq(other_deps.clone().filter(|it| it.kind != DependencyKind::Dev));
+        }
+
+        slf_deps.eq(other_deps)
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum Edition {
     Edition2015,
@@ -351,26 +411,43 @@ impl Env {
     }
 }
 
+#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
+pub enum DependencyKind {
+    Normal,
+    Dev,
+    Build,
+}
+
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Dependency {
     pub crate_id: CrateId,
     pub name: CrateName,
+    kind: DependencyKind,
     prelude: bool,
 }
 
 impl Dependency {
-    pub fn new(name: CrateName, crate_id: CrateId) -> Self {
-        Self { name, crate_id, prelude: true }
+    pub fn new(name: CrateName, crate_id: CrateId, kind: DependencyKind) -> Self {
+        Self { name, crate_id, prelude: true, kind }
     }
 
-    pub fn with_prelude(name: CrateName, crate_id: CrateId, prelude: bool) -> Self {
-        Self { name, crate_id, prelude }
+    pub fn with_prelude(
+        name: CrateName,
+        crate_id: CrateId,
+        prelude: bool,
+        kind: DependencyKind,
+    ) -> Self {
+        Self { name, crate_id, prelude, kind }
     }
 
     /// Whether this dependency is to be added to the depending crate's extern prelude.
     pub fn is_prelude(&self) -> bool {
         self.prelude
     }
+
+    pub fn kind(&self) -> DependencyKind {
+        self.kind
+    }
 }
 
 impl CrateGraph {
@@ -574,23 +651,46 @@ impl CrateGraph {
     pub fn extend(&mut self, mut other: CrateGraph, proc_macros: &mut ProcMacroPaths) {
         let topo = other.crates_in_topological_order();
         let mut id_map: FxHashMap<CrateId, CrateId> = FxHashMap::default();
-
         for topo in topo {
             let crate_data = &mut other.arena[topo];
+
             crate_data.dependencies.iter_mut().for_each(|dep| dep.crate_id = id_map[&dep.crate_id]);
             crate_data.dependencies.sort_by_key(|dep| dep.crate_id);
-
-            let res = self.arena.iter().find_map(
-                |(id, data)| {
-                    if data == crate_data {
-                        Some(id)
-                    } else {
-                        None
+            let res = self.arena.iter().find_map(|(id, data)| {
+                match (&data.origin, &crate_data.origin) {
+                    (a, b) if a == b => {
+                        if data.eq_ignoring_origin_and_deps(&crate_data, false) {
+                            return Some((id, false));
+                        }
+                    }
+                    (a @ CrateOrigin::Local { .. }, CrateOrigin::Library { .. })
+                    | (a @ CrateOrigin::Library { .. }, CrateOrigin::Local { .. }) => {
+                        // If the origins differ, check if the two crates are equal without
+                        // considering the dev dependencies, if they are, they most likely are in
+                        // different loaded workspaces which may cause issues. We keep the local
+                        // version and discard the library one as the local version may have
+                        // dev-dependencies that we want to keep resolving. See #15656 for more
+                        // information.
+                        if data.eq_ignoring_origin_and_deps(&crate_data, true) {
+                            return Some((id, if a.is_local() { false } else { true }));
+                        }
                     }
-                },
-            );
-            if let Some(res) = res {
+                    (_, _) => return None,
+                }
+
+                None
+            });
+
+            if let Some((res, should_update_lib_to_local)) = res {
                 id_map.insert(topo, res);
+                if should_update_lib_to_local {
+                    assert!(self.arena[res].origin.is_lib());
+                    assert!(crate_data.origin.is_local());
+                    self.arena[res].origin = crate_data.origin.clone();
+
+                    // Move local's dev dependencies into the newly-local-formerly-lib crate.
+                    self.arena[res].dependencies = crate_data.dependencies.clone();
+                }
             } else {
                 let id = self.arena.alloc(crate_data.clone());
                 id_map.insert(topo, id);
@@ -636,9 +736,11 @@ impl CrateGraph {
         match (cfg_if, std) {
             (Some(cfg_if), Some(std)) => {
                 self.arena[cfg_if].dependencies.clear();
-                self.arena[std]
-                    .dependencies
-                    .push(Dependency::new(CrateName::new("cfg_if").unwrap(), cfg_if));
+                self.arena[std].dependencies.push(Dependency::new(
+                    CrateName::new("cfg_if").unwrap(),
+                    cfg_if,
+                    DependencyKind::Normal,
+                ));
                 true
             }
             _ => false,
@@ -658,6 +760,8 @@ impl ops::Index<CrateId> for CrateGraph {
 }
 
 impl CrateData {
+    /// Add a dependency to `self` without checking if the dependency
+    // is existent among `self.dependencies`.
     fn add_dep(&mut self, dep: Dependency) {
         self.dependencies.push(dep)
     }
@@ -759,7 +863,7 @@ impl fmt::Display for CyclicDependenciesError {
 
 #[cfg(test)]
 mod tests {
-    use crate::CrateOrigin;
+    use crate::{CrateOrigin, DependencyKind};
 
     use super::{CrateGraph, CrateName, Dependency, Edition::Edition2018, Env, FileId};
 
@@ -806,13 +910,22 @@ mod tests {
             None,
         );
         assert!(graph
-            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+            .add_dep(
+                crate1,
+                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+            )
             .is_ok());
         assert!(graph
-            .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3))
+            .add_dep(
+                crate2,
+                Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
+            )
             .is_ok());
         assert!(graph
-            .add_dep(crate3, Dependency::new(CrateName::new("crate1").unwrap(), crate1))
+            .add_dep(
+                crate3,
+                Dependency::new(CrateName::new("crate1").unwrap(), crate1, DependencyKind::Normal)
+            )
             .is_err());
     }
 
@@ -846,10 +959,16 @@ mod tests {
             None,
         );
         assert!(graph
-            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+            .add_dep(
+                crate1,
+                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+            )
             .is_ok());
         assert!(graph
-            .add_dep(crate2, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+            .add_dep(
+                crate2,
+                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+            )
             .is_err());
     }
 
@@ -896,10 +1015,16 @@ mod tests {
             None,
         );
         assert!(graph
-            .add_dep(crate1, Dependency::new(CrateName::new("crate2").unwrap(), crate2))
+            .add_dep(
+                crate1,
+                Dependency::new(CrateName::new("crate2").unwrap(), crate2, DependencyKind::Normal)
+            )
             .is_ok());
         assert!(graph
-            .add_dep(crate2, Dependency::new(CrateName::new("crate3").unwrap(), crate3))
+            .add_dep(
+                crate2,
+                Dependency::new(CrateName::new("crate3").unwrap(), crate3, DependencyKind::Normal)
+            )
             .is_ok());
     }
 
@@ -935,12 +1060,20 @@ mod tests {
         assert!(graph
             .add_dep(
                 crate1,
-                Dependency::new(CrateName::normalize_dashes("crate-name-with-dashes"), crate2)
+                Dependency::new(
+                    CrateName::normalize_dashes("crate-name-with-dashes"),
+                    crate2,
+                    DependencyKind::Normal
+                )
             )
             .is_ok());
         assert_eq!(
             graph[crate1].dependencies,
-            vec![Dependency::new(CrateName::new("crate_name_with_dashes").unwrap(), crate2)]
+            vec![Dependency::new(
+                CrateName::new("crate_name_with_dashes").unwrap(),
+                crate2,
+                DependencyKind::Normal
+            )]
         );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index c5c4afa30f7..40cfab88afd 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -12,6 +12,7 @@ use rustc_hash::FxHashSet;
 use syntax::{ast, Parse, SourceFile, TextRange, TextSize};
 use triomphe::Arc;
 
+pub use crate::input::DependencyKind;
 pub use crate::{
     change::Change,
     input::{
diff --git a/src/tools/rust-analyzer/crates/cfg/src/lib.rs b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
index 0aeb0b05052..8bbe5e2a8c2 100644
--- a/src/tools/rust-analyzer/crates/cfg/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/cfg/src/lib.rs
@@ -58,6 +58,13 @@ impl CfgOptions {
         self.enabled.insert(CfgAtom::KeyValue { key, value });
     }
 
+    pub fn difference<'a>(
+        &'a self,
+        other: &'a CfgOptions,
+    ) -> impl Iterator<Item = &'a CfgAtom> + 'a {
+        self.enabled.difference(&other.enabled)
+    }
+
     pub fn apply_diff(&mut self, diff: CfgDiff) {
         for atom in diff.enable {
             self.enabled.insert(atom);
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 460a908b6db..4c1b8f306c5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -183,15 +183,6 @@ impl DefMap {
         shadow: BuiltinShadowMode,
         expected_macro_subns: Option<MacroSubNs>,
     ) -> ResolvePathResult {
-        let graph = db.crate_graph();
-        let _cx = stdx::panic_context::enter(format!(
-            "DefMap {:?} crate_name={:?} block={:?} path={}",
-            self.krate,
-            graph[self.krate].display_name,
-            self.block,
-            path.display(db.upcast())
-        ));
-
         let mut segments = path.segments().iter().enumerate();
         let mut curr_per_ns = match path.kind {
             PathKind::DollarCrate(krate) => {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index f2d2451511f..bbcb76a43ff 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -23,10 +23,10 @@ oorandom = "11.1.3"
 tracing.workspace = true
 rustc-hash = "1.1.0"
 scoped-tls = "1.0.0"
-chalk-solve = { version = "0.94.0", default-features = false }
-chalk-ir = "0.94.0"
-chalk-recursive = { version = "0.94.0", default-features = false }
-chalk-derive = "0.94.0"
+chalk-solve = { version = "0.95.0", default-features = false }
+chalk-ir = "0.95.0"
+chalk-recursive = { version = "0.95.0", default-features = false }
+chalk-derive = "0.95.0"
 la-arena.workspace = true
 once_cell = "1.17.0"
 triomphe.workspace = true
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 0a68a9f3b58..ac39bdf5bf5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -43,7 +43,7 @@ where
 }
 
 impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
-    pub(super) fn apply_solution(
+    pub(crate) fn apply_solution(
         &self,
         ctx: &mut InferenceTable<'_>,
         solution: Canonical<Substitution>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index c8a85b4a9ff..04005311b67 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -1097,10 +1097,25 @@ impl<'a> TyLoweringContext<'a> {
                     binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(),
                 );
                 if let Some(type_ref) = &binding.type_ref {
-                    let ty = self.lower_ty(type_ref);
-                    let alias_eq =
-                        AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
-                    predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                    if let (TypeRef::ImplTrait(bounds), ImplTraitLoweringState::Disallowed) =
+                        (type_ref, &self.impl_trait_mode)
+                    {
+                        for bound in bounds {
+                            predicates.extend(
+                                self.lower_type_bound(
+                                    bound,
+                                    TyKind::Alias(AliasTy::Projection(projection_ty.clone()))
+                                        .intern(Interner),
+                                    false,
+                                ),
+                            );
+                        }
+                    } else {
+                        let ty = self.lower_ty(type_ref);
+                        let alias_eq =
+                            AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
+                        predicates.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
+                    }
                 }
                 for bound in binding.bounds.iter() {
                     predicates.extend(self.lower_type_bound(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 87c93283361..732643566a2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -27,8 +27,9 @@ use crate::{
     primitive::{FloatTy, IntTy, UintTy},
     static_lifetime, to_chalk_trait_id,
     utils::all_super_traits,
-    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, InEnvironment,
-    Interner, Scalar, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt,
+    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, DynTyExt, ForeignDefId, Goal, Guidance,
+    InEnvironment, Interner, Scalar, Solution, Substitution, TraitEnvironment, TraitRef,
+    TraitRefExt, Ty, TyBuilder, TyExt,
 };
 
 /// This is used as a key for indexing impls.
@@ -1478,26 +1479,52 @@ fn is_valid_fn_candidate(
             // We need to consider the bounds on the impl to distinguish functions of the same name
             // for a type.
             let predicates = db.generic_predicates(impl_id.into());
-            let valid = predicates
-                .iter()
-                .map(|predicate| {
-                    let (p, b) = predicate
-                        .clone()
-                        .substitute(Interner, &impl_subst)
-                        // Skipping the inner binders is ok, as we don't handle quantified where
-                        // clauses yet.
-                        .into_value_and_skipped_binders();
-                    stdx::always!(b.len(Interner) == 0);
-                    p
-                })
-                // It's ok to get ambiguity here, as we may not have enough information to prove
-                // obligations. We'll check if the user is calling the selected method properly
-                // later anyway.
-                .all(|p| table.try_obligation(p.cast(Interner)).is_some());
-            match valid {
-                true => IsValidCandidate::Yes,
-                false => IsValidCandidate::No,
+            let goals = predicates.iter().map(|p| {
+                let (p, b) = p
+                    .clone()
+                    .substitute(Interner, &impl_subst)
+                    // Skipping the inner binders is ok, as we don't handle quantified where
+                    // clauses yet.
+                    .into_value_and_skipped_binders();
+                stdx::always!(b.len(Interner) == 0);
+
+                p.cast::<Goal>(Interner)
+            });
+
+            for goal in goals.clone() {
+                let in_env = InEnvironment::new(&table.trait_env.env, goal);
+                let canonicalized = table.canonicalize(in_env);
+                let solution = table.db.trait_solve(
+                    table.trait_env.krate,
+                    table.trait_env.block,
+                    canonicalized.value.clone(),
+                );
+
+                match solution {
+                    Some(Solution::Unique(canonical_subst)) => {
+                        canonicalized.apply_solution(
+                            table,
+                            Canonical {
+                                binders: canonical_subst.binders,
+                                value: canonical_subst.value.subst,
+                            },
+                        );
+                    }
+                    Some(Solution::Ambig(Guidance::Definite(substs))) => {
+                        canonicalized.apply_solution(table, substs);
+                    }
+                    Some(_) => (),
+                    None => return IsValidCandidate::No,
+                }
             }
+
+            for goal in goals {
+                if table.try_obligation(goal).is_none() {
+                    return IsValidCandidate::No;
+                }
+            }
+
+            IsValidCandidate::Yes
         } else {
             // For `ItemContainerId::TraitId`, we check if `self_ty` implements the trait in
             // `iterate_trait_method_candidates()`.
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 48dd9540329..003ae60e8e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -2598,6 +2598,34 @@ fn test<T: Trait>() {
 }
 
 #[test]
+fn associated_type_in_type_bound() {
+    check_types(
+        r#"
+//- minicore: deref
+fn fb(f: Foo<&u8>) {
+    f.foobar();
+  //^^^^^^^^^^ u8
+}
+trait Bar {
+    fn bar(&self) -> u8;
+}
+impl Bar for u8 {
+    fn bar(&self) -> u8 { *self }
+}
+
+struct Foo<F> {
+    foo: F,
+}
+impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
+    fn foobar(&self) -> u8 {
+        self.foo.deref().bar()
+    }
+}
+"#,
+    )
+}
+
+#[test]
 fn dyn_trait_through_chalk() {
     check_types(
         r#"
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index bdc11aa3561..1bfbf7212bf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -667,21 +667,21 @@ impl Module {
                 let items = &db.trait_data(trait_.into()).items;
                 let required_items = items.iter().filter(|&(_, assoc)| match *assoc {
                     AssocItemId::FunctionId(it) => !db.function_data(it).has_body(),
-                    AssocItemId::ConstId(_) => true,
+                    AssocItemId::ConstId(id) => Const::from(id).value(db).is_none(),
                     AssocItemId::TypeAliasId(it) => db.type_alias_data(it).type_ref.is_none(),
                 });
-                impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().map(
+                impl_assoc_items_scratch.extend(db.impl_data(impl_def.id).items.iter().filter_map(
                     |&item| {
-                        (
+                        Some((
                             item,
                             match item {
                                 AssocItemId::FunctionId(it) => db.function_data(it).name.clone(),
                                 AssocItemId::ConstId(it) => {
-                                    db.const_data(it).name.as_ref().unwrap().clone()
+                                    db.const_data(it).name.as_ref()?.clone()
                                 }
                                 AssocItemId::TypeAliasId(it) => db.type_alias_data(it).name.clone(),
                             },
-                        )
+                        ))
                     },
                 ));
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
index b7d57f02be5..f864ee50c81 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/toggle_ignore.rs
@@ -55,7 +55,7 @@ pub(crate) fn toggle_ignore(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
 }
 
 fn has_ignore_attribute(fn_def: &ast::Fn) -> Option<ast::Attr> {
-    fn_def.attrs().find(|attr| attr.path().map(|it| it.syntax().text() == "ignore") == Some(true))
+    fn_def.attrs().find(|attr| attr.path().is_some_and(|it| it.syntax().text() == "ignore"))
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
index 0bf1782a489..0876246e90b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unqualify_method_call.rs
@@ -91,7 +91,7 @@ fn add_import(
 ) {
     if let Some(path_segment) = qualifier.segment() {
         // for `<i32 as std::ops::Add>`
-        let path_type = path_segment.syntax().children().filter_map(ast::PathType::cast).last();
+        let path_type = path_segment.qualifying_trait();
         let import = match path_type {
             Some(it) => {
                 if let Some(path) = it.path() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index c5bbb7f8d75..5bcc867fe18 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -1095,4 +1095,81 @@ fn test(s: S<Unknown>) {
             "#]],
         );
     }
+
+    #[test]
+    fn assoc_impl_1() {
+        check(
+            r#"
+//- minicore: deref
+fn main() {
+    let foo: Foo<&u8> = Foo::new(&42_u8);
+    foo.$0
+}
+
+trait Bar {
+    fn bar(&self);
+}
+
+impl Bar for u8 {
+    fn bar(&self) {}
+}
+
+struct Foo<F> {
+    foo: F,
+}
+
+impl<F> Foo<F> {
+    fn new(foo: F) -> Foo<F> {
+        Foo { foo }
+    }
+}
+
+impl<F: core::ops::Deref<Target = impl Bar>> Foo<F> {
+    fn foobar(&self) {
+        self.foo.deref().bar()
+    }
+}
+"#,
+            expect![[r#"
+                fd foo      &u8
+                me foobar() fn(&self)
+            "#]],
+        );
+    }
+
+    #[test]
+    fn assoc_impl_2() {
+        check(
+            r#"
+//- minicore: deref
+fn main() {
+    let foo: Foo<&u8> = Foo::new(&42_u8);
+    foo.$0
+}
+
+trait Bar {
+    fn bar(&self);
+}
+
+struct Foo<F> {
+    foo: F,
+}
+
+impl<F> Foo<F> {
+    fn new(foo: F) -> Foo<F> {
+        Foo { foo }
+    }
+}
+
+impl<B: Bar, F: core::ops::Deref<Target = B>> Foo<F> {
+    fn foobar(&self) {
+        self.foo.deref().bar()
+    }
+}
+"#,
+            expect![[r#"
+            fd foo &u8
+        "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index ed74ef7b667..99b895eed4d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -26,6 +26,10 @@ use crate::{
 pub struct CompletionItem {
     /// Label in the completion pop up which identifies completion.
     pub label: SmolStr,
+    /// Additional label details in the completion pop up that are
+    /// displayed and aligned on the right side after the label.
+    pub label_detail: Option<SmolStr>,
+
     /// Range of identifier that is being completed.
     ///
     /// It should be used primarily for UI, but we also use this to convert
@@ -425,13 +429,14 @@ impl Builder {
     pub(crate) fn build(self, db: &RootDatabase) -> CompletionItem {
         let _p = profile::span("item::Builder::build");
 
-        let mut label = self.label;
+        let label = self.label;
+        let mut label_detail = None;
         let mut lookup = self.lookup.unwrap_or_else(|| label.clone());
         let insert_text = self.insert_text.unwrap_or_else(|| label.to_string());
 
         if !self.doc_aliases.is_empty() {
             let doc_aliases = self.doc_aliases.iter().join(", ");
-            label = SmolStr::from(format!("{label} (alias {doc_aliases})"));
+            label_detail.replace(SmolStr::from(format!(" (alias {doc_aliases})")));
             let lookup_doc_aliases = self
                 .doc_aliases
                 .iter()
@@ -454,10 +459,17 @@ impl Builder {
         if let [import_edit] = &*self.imports_to_add {
             // snippets can have multiple imports, but normal completions only have up to one
             if let Some(original_path) = import_edit.original_path.as_ref() {
-                label = SmolStr::from(format!("{label} (use {})", original_path.display(db)));
+                label_detail.replace(SmolStr::from(format!(
+                    "{} (use {})",
+                    label_detail.as_deref().unwrap_or_default(),
+                    original_path.display(db)
+                )));
             }
         } else if let Some(trait_name) = self.trait_name {
-            label = SmolStr::from(format!("{label} (as {trait_name})"));
+            label_detail.replace(SmolStr::from(format!(
+                "{} (as {trait_name})",
+                label_detail.as_deref().unwrap_or_default(),
+            )));
         }
 
         let text_edit = match self.text_edit {
@@ -479,6 +491,7 @@ impl Builder {
         CompletionItem {
             source_range: self.source_range,
             label,
+            label_detail,
             text_edit,
             is_snippet: self.is_snippet,
             detail: self.detail,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index dfe8fe7e2f7..00a9081985b 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -557,7 +557,11 @@ mod tests {
 
                 let tag = it.kind.tag();
                 let relevance = display_relevance(it.relevance);
-                items.push(format!("{tag} {} {relevance}\n", it.label));
+                items.push(format!(
+                    "{tag} {}{} {relevance}\n",
+                    it.label,
+                    it.label_detail.clone().unwrap_or_default(),
+                ));
 
                 if let Some((label, _indel, relevance)) = it.ref_match() {
                     let relevance = display_relevance(relevance);
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index 9db8e972dd4..f28afacc586 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -150,16 +150,29 @@ fn render_completion_list(completions: Vec<CompletionItem>) -> String {
     fn monospace_width(s: &str) -> usize {
         s.chars().count()
     }
-    let label_width =
-        completions.iter().map(|it| monospace_width(&it.label)).max().unwrap_or_default().min(22);
+    let label_width = completions
+        .iter()
+        .map(|it| {
+            monospace_width(&it.label)
+                + monospace_width(it.label_detail.as_deref().unwrap_or_default())
+        })
+        .max()
+        .unwrap_or_default()
+        .min(22);
     completions
         .into_iter()
         .map(|it| {
             let tag = it.kind.tag();
             let var_name = format!("{tag} {}", it.label);
             let mut buf = var_name;
+            if let Some(ref label_detail) = it.label_detail {
+                format_to!(buf, "{label_detail}");
+            }
             if let Some(detail) = it.detail {
-                let width = label_width.saturating_sub(monospace_width(&it.label));
+                let width = label_width.saturating_sub(
+                    monospace_width(&it.label)
+                        + monospace_width(&it.label_detail.unwrap_or_default()),
+                );
                 format_to!(buf, "{:width$} {}", "", detail, width = width);
             }
             if it.deprecated {
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
index 40d0b6fdd4b..51923797ac9 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_missing_assoc_item.rs
@@ -36,6 +36,19 @@ mod tests {
     use crate::tests::check_diagnostics;
 
     #[test]
+    fn trait_with_default_value() {
+        check_diagnostics(
+            r#"
+trait Marker {
+    const FLAG: bool = false;
+}
+struct Foo;
+impl Marker for Foo {}
+            "#,
+        )
+    }
+
+    #[test]
     fn simple() {
         check_diagnostics(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
index 3d89599c583..9b2ff070c74 100644
--- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
@@ -108,7 +108,7 @@ fn try_extend_selection(
 
     let node = shallowest_node(&node);
 
-    if node.parent().map(|n| list_kinds.contains(&n.kind())) == Some(true) {
+    if node.parent().is_some_and(|n| list_kinds.contains(&n.kind())) {
         if let Some(range) = extend_list_item(&node) {
             return Some(range);
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 46a0464e9e6..a7f5ae92a4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -43,7 +43,7 @@ pub struct HighlightRelatedConfig {
 //
 // . if on an identifier, highlights all references to that identifier in the current file
 // .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
-// . if on an `async` or `await token, highlights all yield points for that async context
+// . if on an `async` or `await` token, highlights all yield points for that async context
 // . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
 // . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
 // . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index 80897f7478c..931eba11576 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -49,7 +49,7 @@
 //! user explores them belongs to that extension (it's totally valid to change
 //! rust-project.json over time via configuration request!)
 
-use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, Edition};
+use base_db::{CrateDisplayName, CrateId, CrateName, Dependency, DependencyKind, Edition};
 use la_arena::RawIdx;
 use paths::{AbsPath, AbsPathBuf};
 use rustc_hash::FxHashMap;
@@ -135,6 +135,7 @@ impl ProjectJson {
                                 Dependency::new(
                                     dep_data.name,
                                     CrateId::from_raw(RawIdx::from(dep_data.krate as u32)),
+                                    DependencyKind::Normal,
                                 )
                             })
                             .collect::<Vec<_>>(),
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 7815b9dda77..98f3063bb98 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -249,3 +249,55 @@ fn crate_graph_dedup() {
     crate_graph.extend(regex_crate_graph, &mut regex_proc_macros);
     assert_eq!(crate_graph.iter().count(), 118);
 }
+
+#[test]
+fn test_deduplicate_origin_dev() {
+    let path_map = &mut Default::default();
+    let (mut crate_graph, _proc_macros) =
+        load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
+    crate_graph.sort_deps();
+    let (crate_graph_1, mut _proc_macros_2) =
+        load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
+
+    crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
+
+    let mut crates_named_p2 = vec![];
+    for id in crate_graph.iter() {
+        let krate = &crate_graph[id];
+        if let Some(name) = krate.display_name.as_ref() {
+            if name.to_string() == "p2" {
+                crates_named_p2.push(krate);
+            }
+        }
+    }
+
+    assert!(crates_named_p2.len() == 1);
+    let p2 = crates_named_p2[0];
+    assert!(p2.origin.is_local());
+}
+
+#[test]
+fn test_deduplicate_origin_dev_rev() {
+    let path_map = &mut Default::default();
+    let (mut crate_graph, _proc_macros) =
+        load_cargo_with_sysroot(path_map, "deduplication_crate_graph_B.json");
+    crate_graph.sort_deps();
+    let (crate_graph_1, mut _proc_macros_2) =
+        load_cargo_with_sysroot(path_map, "deduplication_crate_graph_A.json");
+
+    crate_graph.extend(crate_graph_1, &mut _proc_macros_2);
+
+    let mut crates_named_p2 = vec![];
+    for id in crate_graph.iter() {
+        let krate = &crate_graph[id];
+        if let Some(name) = krate.display_name.as_ref() {
+            if name.to_string() == "p2" {
+                crates_named_p2.push(krate);
+            }
+        }
+    }
+
+    assert!(crates_named_p2.len() == 1);
+    let p2 = crates_named_p2[0];
+    assert!(p2.origin.is_local());
+}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index e0209ca15a5..9333570354a 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -6,8 +6,8 @@ use std::{collections::VecDeque, fmt, fs, iter, process::Command, str::FromStr,
 
 use anyhow::{format_err, Context};
 use base_db::{
-    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, Edition, Env,
-    FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult,
+    CrateDisplayName, CrateGraph, CrateId, CrateName, CrateOrigin, Dependency, DependencyKind,
+    Edition, Env, FileId, LangCrateOrigin, ProcMacroPaths, ReleaseChannel, TargetLayoutLoadResult,
 };
 use cfg::{CfgDiff, CfgOptions};
 use paths::{AbsPath, AbsPathBuf};
@@ -834,7 +834,7 @@ fn project_json_to_crate_graph(
 
             for dep in &krate.deps {
                 if let Some(&to) = crates.get(&dep.crate_id) {
-                    add_dep(crate_graph, from, dep.name.clone(), to)
+                    add_dep(crate_graph, from, dep.name.clone(), to, dep.kind().to_owned())
                 }
             }
         }
@@ -979,7 +979,7 @@ fn cargo_to_crate_graph(
                     // cargo metadata does not do any normalization,
                     // so we do it ourselves currently
                     let name = CrateName::normalize_dashes(&name);
-                    add_dep(crate_graph, from, name, to);
+                    add_dep(crate_graph, from, name, to, DependencyKind::Normal);
                 }
             }
         }
@@ -999,7 +999,17 @@ fn cargo_to_crate_graph(
                     continue;
                 }
 
-                add_dep(crate_graph, from, name.clone(), to)
+                add_dep(
+                    crate_graph,
+                    from,
+                    name.clone(),
+                    to,
+                    match dep.kind {
+                        DepKind::Normal => DependencyKind::Normal,
+                        DepKind::Dev => DependencyKind::Dev,
+                        DepKind::Build => DependencyKind::Build,
+                    },
+                )
             }
         }
     }
@@ -1187,7 +1197,17 @@ fn handle_rustc_crates(
             let name = CrateName::new(&dep.name).unwrap();
             if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) {
                 for &from in rustc_pkg_crates.get(&pkg).into_iter().flatten() {
-                    add_dep(crate_graph, from, name.clone(), to);
+                    add_dep(
+                        crate_graph,
+                        from,
+                        name.clone(),
+                        to,
+                        match dep.kind {
+                            DepKind::Normal => DependencyKind::Normal,
+                            DepKind::Dev => DependencyKind::Dev,
+                            DepKind::Build => DependencyKind::Build,
+                        },
+                    );
                 }
             }
         }
@@ -1209,7 +1229,7 @@ fn handle_rustc_crates(
                     // `rust_analyzer` thinks that it should use the one from the `rustc_source`
                     // instead of the one from `crates.io`
                     if !crate_graph[*from].dependencies.iter().any(|d| d.name == name) {
-                        add_dep(crate_graph, *from, name.clone(), to);
+                        add_dep(crate_graph, *from, name.clone(), to, DependencyKind::Normal);
                     }
                 }
             }
@@ -1308,7 +1328,14 @@ impl SysrootPublicDeps {
     /// Makes `from` depend on the public sysroot crates.
     fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
         for (name, krate, prelude) in &self.deps {
-            add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
+            add_dep_with_prelude(
+                crate_graph,
+                from,
+                name.clone(),
+                *krate,
+                *prelude,
+                DependencyKind::Normal,
+            );
         }
     }
 }
@@ -1363,7 +1390,7 @@ fn sysroot_to_crate_graph(
         for &to in sysroot[from].deps.iter() {
             let name = CrateName::new(&sysroot[to].name).unwrap();
             if let (Some(&from), Some(&to)) = (sysroot_crates.get(&from), sysroot_crates.get(&to)) {
-                add_dep(crate_graph, from, name, to);
+                add_dep(crate_graph, from, name, to, DependencyKind::Normal);
             }
         }
     }
@@ -1442,8 +1469,14 @@ fn handle_hack_cargo_workspace(
         .collect()
 }
 
-fn add_dep(graph: &mut CrateGraph, from: CrateId, name: CrateName, to: CrateId) {
-    add_dep_inner(graph, from, Dependency::new(name, to))
+fn add_dep(
+    graph: &mut CrateGraph,
+    from: CrateId,
+    name: CrateName,
+    to: CrateId,
+    kind: DependencyKind,
+) {
+    add_dep_inner(graph, from, Dependency::new(name, to, kind))
 }
 
 fn add_dep_with_prelude(
@@ -1452,12 +1485,20 @@ fn add_dep_with_prelude(
     name: CrateName,
     to: CrateId,
     prelude: bool,
+    kind: DependencyKind,
 ) {
-    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude))
+    add_dep_inner(graph, from, Dependency::with_prelude(name, to, prelude, kind))
 }
 
 fn add_proc_macro_dep(crate_graph: &mut CrateGraph, from: CrateId, to: CrateId, prelude: bool) {
-    add_dep_with_prelude(crate_graph, from, CrateName::new("proc_macro").unwrap(), to, prelude);
+    add_dep_with_prelude(
+        crate_graph,
+        from,
+        CrateName::new("proc_macro").unwrap(),
+        to,
+        prelude,
+        DependencyKind::Normal,
+    );
 }
 
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json
new file mode 100644
index 00000000000..b0fb5845cef
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_A.json
@@ -0,0 +1,140 @@
+{
+  "packages": [
+    {
+      "name": "p1",
+      "version": "0.1.0",
+      "id": "p1 0.1.0 (path+file:///example_project/p1)",
+      "license": null,
+      "license_file": null,
+      "description": null,
+      "source": null,
+      "dependencies": [
+        {
+          "name": "p2",
+          "source": null,
+          "req": "*",
+          "kind": null,
+          "rename": null,
+          "optional": false,
+          "uses_default_features": true,
+          "features": [],
+          "target": null,
+          "registry": null,
+          "path": "$ROOT$example_project/p2"
+        }
+      ],
+      "targets": [
+        {
+          "kind": [
+            "lib"
+          ],
+          "crate_types": [
+            "lib"
+          ],
+          "name": "p1",
+          "src_path": "$ROOT$example_project/p1/src/lib.rs",
+          "edition": "2021",
+          "doc": true,
+          "doctest": true,
+          "test": true
+        }
+      ],
+      "features": {},
+      "manifest_path": "$ROOT$example_project/p1/Cargo.toml",
+      "metadata": null,
+      "publish": null,
+      "authors": [],
+      "categories": [],
+      "keywords": [],
+      "readme": null,
+      "repository": null,
+      "homepage": null,
+      "documentation": null,
+      "edition": "2021",
+      "links": null,
+      "default_run": null,
+      "rust_version": null
+    },
+    {
+      "name": "p2",
+      "version": "0.1.0",
+      "id": "p2 0.1.0 (path+file:///example_project/p2)",
+      "license": null,
+      "license_file": null,
+      "description": null,
+      "source": null,
+      "dependencies": [],
+      "targets": [
+        {
+          "kind": [
+            "lib"
+          ],
+          "crate_types": [
+            "lib"
+          ],
+          "name": "p2",
+          "src_path": "$ROOT$example_project/p2/src/lib.rs",
+          "edition": "2021",
+          "doc": true,
+          "doctest": true,
+          "test": true
+        }
+      ],
+      "features": {},
+      "manifest_path": "$ROOT$example_project/p2/Cargo.toml",
+      "metadata": null,
+      "publish": null,
+      "authors": [],
+      "categories": [],
+      "keywords": [],
+      "readme": null,
+      "repository": null,
+      "homepage": null,
+      "documentation": null,
+      "edition": "2021",
+      "links": null,
+      "default_run": null,
+      "rust_version": null
+    }
+  ],
+  "workspace_members": [
+    "p1 0.1.0 (path+file:///example_project/p1)"
+  ],
+  "workspace_default_members": [
+    "p1 0.1.0 (path+file:///example_project/p1)"
+  ],
+  "resolve": {
+    "nodes": [
+      {
+        "id": "p1 0.1.0 (path+file:///example_project/p1)",
+        "dependencies": [
+          "p2 0.1.0 (path+file:///example_project/p2)"
+        ],
+        "deps": [
+          {
+            "name": "p2",
+            "pkg": "p2 0.1.0 (path+file:///example_project/p2)",
+            "dep_kinds": [
+              {
+                "kind": null,
+                "target": null
+              }
+            ]
+          }
+        ],
+        "features": []
+      },
+      {
+        "id": "p2 0.1.0 (path+file:///example_project/p2)",
+        "dependencies": [],
+        "deps": [],
+        "features": []
+      }
+    ],
+    "root": "p1 0.1.0 (path+file:///example_project/p1)"
+  },
+  "target_directory": "$ROOT$example_project/p1/target",
+  "version": 1,
+  "workspace_root": "$ROOT$example_project/p1",
+  "metadata": null
+}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json
new file mode 100644
index 00000000000..b5d1e16e62e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/deduplication_crate_graph_B.json
@@ -0,0 +1,66 @@
+{
+  "packages": [
+    {
+      "name": "p2",
+      "version": "0.1.0",
+      "id": "p2 0.1.0 (path+file:///example_project/p2)",
+      "license": null,
+      "license_file": null,
+      "description": null,
+      "source": null,
+      "dependencies": [],
+      "targets": [
+        {
+          "kind": [
+            "lib"
+          ],
+          "crate_types": [
+            "lib"
+          ],
+          "name": "p2",
+          "src_path": "$ROOT$example_project/p2/src/lib.rs",
+          "edition": "2021",
+          "doc": true,
+          "doctest": true,
+          "test": true
+        }
+      ],
+      "features": {},
+      "manifest_path": "$ROOT$example_project/p2/Cargo.toml",
+      "metadata": null,
+      "publish": null,
+      "authors": [],
+      "categories": [],
+      "keywords": [],
+      "readme": null,
+      "repository": null,
+      "homepage": null,
+      "documentation": null,
+      "edition": "2021",
+      "links": null,
+      "default_run": null,
+      "rust_version": null
+    }
+  ],
+  "workspace_members": [
+    "p2 0.1.0 (path+file:///example_project/p2)"
+  ],
+  "workspace_default_members": [
+    "p2 0.1.0 (path+file:///example_project/p2)"
+  ],
+  "resolve": {
+    "nodes": [
+      {
+        "id": "p2 0.1.0 (path+file:///example_project/p2)",
+        "dependencies": [],
+        "deps": [],
+        "features": []
+      }
+    ],
+    "root": "p2 0.1.0 (path+file:///example_project/p2)"
+  },
+  "target_directory": "$ROOT$example_project/p2/target",
+  "version": 1,
+  "workspace_root": "$ROOT$example_project/p2",
+  "metadata": null
+}
\ No newline at end of file
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
index 727d39a3077..e98f016ca7d 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model.txt
@@ -48,6 +48,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -112,6 +113,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -119,6 +121,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -183,6 +186,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -190,6 +194,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -254,6 +259,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -261,6 +267,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
index 727d39a3077..e98f016ca7d 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_selective_overrides.txt
@@ -48,6 +48,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -112,6 +113,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -119,6 +121,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -183,6 +186,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -190,6 +194,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -254,6 +259,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -261,6 +267,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
index 89728babd82..7ecd53572e2 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/cargo_hello_world_project_model_with_wildcard_overrides.txt
@@ -47,6 +47,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -110,6 +111,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -117,6 +119,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -180,6 +183,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -187,6 +191,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -250,6 +255,7 @@
                 name: CrateName(
                     "hello_world",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -257,6 +263,7 @@
                 name: CrateName(
                     "libc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
index b7bf6cb2774..581a6afc148 100644
--- a/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
+++ b/src/tools/rust-analyzer/crates/project-model/test_data/output/rust_project_hello_world_project_model.txt
@@ -28,6 +28,7 @@
                 name: CrateName(
                     "core",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -168,6 +169,7 @@
                 name: CrateName(
                     "std",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -175,6 +177,7 @@
                 name: CrateName(
                     "core",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -249,6 +252,7 @@
                 name: CrateName(
                     "alloc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -256,6 +260,7 @@
                 name: CrateName(
                     "panic_unwind",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -263,6 +268,7 @@
                 name: CrateName(
                     "panic_abort",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -270,6 +276,7 @@
                 name: CrateName(
                     "core",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -277,6 +284,7 @@
                 name: CrateName(
                     "profiler_builtins",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -284,6 +292,7 @@
                 name: CrateName(
                     "unwind",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -291,6 +300,7 @@
                 name: CrateName(
                     "std_detect",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -298,6 +308,7 @@
                 name: CrateName(
                     "test",
                 ),
+                kind: Normal,
                 prelude: true,
             },
         ],
@@ -438,6 +449,7 @@
                 name: CrateName(
                     "core",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -445,6 +457,7 @@
                 name: CrateName(
                     "alloc",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -452,6 +465,7 @@
                 name: CrateName(
                     "std",
                 ),
+                kind: Normal,
                 prelude: true,
             },
             Dependency {
@@ -459,6 +473,7 @@
                 name: CrateName(
                     "test",
                 ),
+                kind: Normal,
                 prelude: false,
             },
             Dependency {
@@ -466,6 +481,7 @@
                 name: CrateName(
                     "proc_macro",
                 ),
+                kind: Normal,
                 prelude: false,
             },
         ],
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
index aca91570f7c..fb366fd5cc4 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs
@@ -1,7 +1,7 @@
 //! Conversion of rust-analyzer specific types to lsp_types equivalents.
 use std::{
     iter::once,
-    path,
+    mem, path,
     sync::atomic::{AtomicU32, Ordering},
 };
 
@@ -301,9 +301,11 @@ fn completion_item(
 
     if config.completion_label_details_support() {
         lsp_item.label_details = Some(lsp_types::CompletionItemLabelDetails {
-            detail: None,
+            detail: item.label_detail.as_ref().map(ToString::to_string),
             description: lsp_item.detail.clone(),
         });
+    } else if let Some(label_detail) = item.label_detail {
+        lsp_item.label.push_str(label_detail.as_str());
     }
 
     set_score(&mut lsp_item, max_relevance, item.relevance);
@@ -1123,13 +1125,20 @@ pub(crate) fn snippet_text_document_ops(
 
 pub(crate) fn snippet_workspace_edit(
     snap: &GlobalStateSnapshot,
-    source_change: SourceChange,
+    mut source_change: SourceChange,
 ) -> Cancellable<lsp_ext::SnippetWorkspaceEdit> {
     let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
 
-    for op in source_change.file_system_edits {
-        let ops = snippet_text_document_ops(snap, op)?;
-        document_changes.extend_from_slice(&ops);
+    for op in &mut source_change.file_system_edits {
+        if let FileSystemEdit::CreateFile { dst, initial_contents } = op {
+            // replace with a placeholder to avoid cloneing the edit
+            let op = FileSystemEdit::CreateFile {
+                dst: dst.clone(),
+                initial_contents: mem::take(initial_contents),
+            };
+            let ops = snippet_text_document_ops(snap, op)?;
+            document_changes.extend_from_slice(&ops);
+        }
     }
     for (file_id, (edit, snippet_edit)) in source_change.source_file_edits {
         let edit = snippet_text_document_edit(
@@ -1141,6 +1150,12 @@ pub(crate) fn snippet_workspace_edit(
         )?;
         document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
     }
+    for op in source_change.file_system_edits {
+        if !matches!(op, FileSystemEdit::CreateFile { .. }) {
+            let ops = snippet_text_document_ops(snap, op)?;
+            document_changes.extend_from_slice(&ops);
+        }
+    }
     let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit {
         changes: None,
         document_changes: Some(document_changes),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index d5991429899..5cd02f78404 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -984,6 +984,11 @@ fn main() {}
 //- /src/old_file.rs
 
 //- /src/old_folder/mod.rs
+mod nested;
+
+//- /src/old_folder/nested.rs
+struct foo;
+use crate::old_folder::nested::foo as bar;
 
 //- /src/from_mod/mod.rs
 
@@ -1080,6 +1085,27 @@ fn main() {}
                   "newText": "new_folder"
                 }
               ]
+            },
+            {
+              "textDocument": {
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")),
+                "version": null
+              },
+              "edits": [
+                {
+                  "range": {
+                    "start": {
+                      "line": 1,
+                      "character": 11
+                    },
+                    "end": {
+                      "line": 1,
+                      "character": 21
+                    }
+                  },
+                  "newText": "new_folder"
+                }
+              ]
             }
           ]
         }),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 56b5fcef3c2..45adbf5c573 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -316,7 +316,7 @@ fn check_trailing_ws(path: &Path, text: &str) {
         return;
     }
     for (line_number, line) in text.lines().enumerate() {
-        if line.chars().last().map(char::is_whitespace) == Some(true) {
+        if line.chars().last().is_some_and(char::is_whitespace) {
             panic!("Trailing whitespace in {} at line {}", path.display(), line_number + 1)
         }
     }
diff --git a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml
index ba36fb0b044..cd7ec305936 100644
--- a/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rustc-dependencies/Cargo.toml
@@ -11,10 +11,10 @@ authors.workspace = true
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-ra-ap-rustc_lexer = { version = "0.19.0" }
-ra-ap-rustc_parse_format = { version = "0.14.0", default-features = false }
-ra-ap-rustc_index = { version = "0.19.0", default-features = false }
-ra-ap-rustc_abi = { version = "0.19.0", default-features = false }
+ra-ap-rustc_lexer = { version = "0.20.0" }
+ra-ap-rustc_parse_format = { version = "0.20.0", default-features = false }
+ra-ap-rustc_index = { version = "0.20.0", default-features = false }
+ra-ap-rustc_abi = { version = "0.20.0", default-features = false }
 
 [features]
 in-rust-tree = []
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 18d5ddd4d0a..9fc19a7d074 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -174,7 +174,7 @@ $ rustup component add rust-analyzer
 
 The `rust-analyzer` binary can be installed from the repos or AUR (Arch User Repository):
 
-- https://www.archlinux.org/packages/community/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source)
+- https://www.archlinux.org/packages/extra/x86_64/rust-analyzer/[`rust-analyzer`] (built from latest tagged source)
 - https://aur.archlinux.org/packages/rust-analyzer-git[`rust-analyzer-git`] (latest Git version)
 
 Install it with pacman, for example:
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 265c63f3e2d..c43f2b964fd 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -498,6 +498,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.showRequestFailedErrorNotification": {
+                    "markdownDescription": "Whether to show error notifications for failing requests.",
+                    "default": true,
+                    "type": "boolean"
+                },
                 "rust-analyzer.showDependenciesExplorer": {
                     "markdownDescription": "Whether to show the dependencies view.",
                     "default": true,
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index 96e888402ba..c27a446b380 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -10,6 +10,7 @@ import { type Config, prepareVSCodeConfig } from "./config";
 import { randomUUID } from "crypto";
 import { sep as pathSeparator } from "path";
 import { unwrapUndefinable } from "./undefinable";
+import { RaLanguageClient } from "./lang_client";
 
 export interface Env {
     [name: string]: string;
@@ -363,7 +364,7 @@ export async function createClient(
         },
     };
 
-    const client = new lc.LanguageClient(
+    const client = new RaLanguageClient(
         "rust-analyzer",
         "Rust Analyzer Language Server",
         serverOptions,
diff --git a/src/tools/rust-analyzer/editors/code/src/lang_client.ts b/src/tools/rust-analyzer/editors/code/src/lang_client.ts
new file mode 100644
index 00000000000..09d64efc048
--- /dev/null
+++ b/src/tools/rust-analyzer/editors/code/src/lang_client.ts
@@ -0,0 +1,26 @@
+import * as lc from "vscode-languageclient/node";
+import * as vscode from "vscode";
+
+export class RaLanguageClient extends lc.LanguageClient {
+    override handleFailedRequest<T>(
+        type: lc.MessageSignature,
+        token: vscode.CancellationToken | undefined,
+        error: any,
+        defaultValue: T,
+        showNotification?: boolean | undefined,
+    ): T {
+        const showError = vscode.workspace
+            .getConfiguration("rust-analyzer")
+            .get("showRequestFailedErrorNotification");
+        if (
+            !showError &&
+            error instanceof lc.ResponseError &&
+            error.code === lc.ErrorCodes.InternalError
+        ) {
+            // Don't show notification for internal errors, these are emitted by r-a when a request fails.
+            showNotification = false;
+        }
+
+        return super.handleFailedRequest(type, token, error, defaultValue, showNotification);
+    }
+}
diff --git a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
index 8d00813b0d7..be1573913ff 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
+++ b/src/tools/rust-analyzer/lib/lsp-server/Cargo.toml
@@ -14,3 +14,4 @@ crossbeam-channel = "0.5.6"
 
 [dev-dependencies]
 lsp-types = "=0.94"
+ctrlc = "3.4.1"
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
index affab60a227..b190c0af73d 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
@@ -17,7 +17,7 @@ use std::{
     net::{TcpListener, TcpStream, ToSocketAddrs},
 };
 
-use crossbeam_channel::{Receiver, Sender};
+use crossbeam_channel::{Receiver, RecvTimeoutError, Sender};
 
 pub use crate::{
     error::{ExtractError, ProtocolError},
@@ -113,11 +113,62 @@ impl Connection {
     /// }
     /// ```
     pub fn initialize_start(&self) -> Result<(RequestId, serde_json::Value), ProtocolError> {
-        loop {
-            break match self.receiver.recv() {
-                Ok(Message::Request(req)) if req.is_initialize() => Ok((req.id, req.params)),
+        self.initialize_start_while(|| true)
+    }
+
+    /// Starts the initialization process by waiting for an initialize as described in
+    /// [`Self::initialize_start`] as long as `running` returns
+    /// `true` while the return value can be changed through a sig handler such as `CTRL + C`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    /// use std::sync::Arc;
+    /// # use std::error::Error;
+    /// # use lsp_types::{ClientCapabilities, InitializeParams, ServerCapabilities};
+    /// # use lsp_server::{Connection, Message, Request, RequestId, Response};
+    /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
+    /// let running = Arc::new(AtomicBool::new(true));
+    /// # running.store(true, Ordering::SeqCst);
+    /// let r = running.clone();
+    ///
+    /// ctrlc::set_handler(move || {
+    ///     r.store(false, Ordering::SeqCst);
+    /// }).expect("Error setting Ctrl-C handler");
+    ///
+    /// let (connection, io_threads) = Connection::stdio();
+    ///
+    /// let res = connection.initialize_start_while(|| running.load(Ordering::SeqCst));
+    /// # assert!(res.is_err());
+    ///
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn initialize_start_while<C>(
+        &self,
+        running: C,
+    ) -> Result<(RequestId, serde_json::Value), ProtocolError>
+    where
+        C: Fn() -> bool,
+    {
+        while running() {
+            let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) {
+                Ok(msg) => msg,
+                Err(RecvTimeoutError::Timeout) => {
+                    continue;
+                }
+                Err(e) => {
+                    return Err(ProtocolError(format!(
+                        "expected initialize request, got error: {e}"
+                    )))
+                }
+            };
+
+            match msg {
+                Message::Request(req) if req.is_initialize() => return Ok((req.id, req.params)),
                 // Respond to non-initialize requests with ServerNotInitialized
-                Ok(Message::Request(req)) => {
+                Message::Request(req) => {
                     let resp = Response::new_err(
                         req.id.clone(),
                         ErrorCode::ServerNotInitialized as i32,
@@ -126,15 +177,18 @@ impl Connection {
                     self.sender.send(resp.into()).unwrap();
                     continue;
                 }
-                Ok(Message::Notification(n)) if !n.is_exit() => {
+                Message::Notification(n) if !n.is_exit() => {
                     continue;
                 }
-                Ok(msg) => Err(ProtocolError(format!("expected initialize request, got {msg:?}"))),
-                Err(e) => {
-                    Err(ProtocolError(format!("expected initialize request, got error: {e}")))
+                msg => {
+                    return Err(ProtocolError(format!("expected initialize request, got {msg:?}")));
                 }
             };
         }
+
+        return Err(ProtocolError(String::from(
+            "Initialization has been aborted during initialization",
+        )));
     }
 
     /// Finishes the initialization process by sending an `InitializeResult` to the client
@@ -156,6 +210,51 @@ impl Connection {
         }
     }
 
+    /// Finishes the initialization process as described in [`Self::initialize_finish`] as
+    /// long as `running` returns `true` while the return value can be changed through a sig
+    /// handler such as `CTRL + C`.
+    pub fn initialize_finish_while<C>(
+        &self,
+        initialize_id: RequestId,
+        initialize_result: serde_json::Value,
+        running: C,
+    ) -> Result<(), ProtocolError>
+    where
+        C: Fn() -> bool,
+    {
+        let resp = Response::new_ok(initialize_id, initialize_result);
+        self.sender.send(resp.into()).unwrap();
+
+        while running() {
+            let msg = match self.receiver.recv_timeout(std::time::Duration::from_secs(1)) {
+                Ok(msg) => msg,
+                Err(RecvTimeoutError::Timeout) => {
+                    continue;
+                }
+                Err(e) => {
+                    return Err(ProtocolError(format!(
+                        "expected initialized notification, got error: {e}",
+                    )));
+                }
+            };
+
+            match msg {
+                Message::Notification(n) if n.is_initialized() => {
+                    return Ok(());
+                }
+                msg => {
+                    return Err(ProtocolError(format!(
+                        r#"expected initialized notification, got: {msg:?}"#
+                    )));
+                }
+            }
+        }
+
+        return Err(ProtocolError(String::from(
+            "Initialization has been aborted during initialization",
+        )));
+    }
+
     /// Initialize the connection. Sends the server capabilities
     /// to the client and returns the serialized client capabilities
     /// on success. If more fine-grained initialization is required use
@@ -198,6 +297,58 @@ impl Connection {
         Ok(params)
     }
 
+    /// Initialize the connection as described in [`Self::initialize`] as long as `running` returns
+    /// `true` while the return value can be changed through a sig handler such as `CTRL + C`.
+    ///
+    /// # Example
+    ///
+    /// ```rust
+    /// use std::sync::atomic::{AtomicBool, Ordering};
+    /// use std::sync::Arc;
+    /// # use std::error::Error;
+    /// # use lsp_types::ServerCapabilities;
+    /// # use lsp_server::{Connection, Message, Request, RequestId, Response};
+    ///
+    /// # fn main() -> Result<(), Box<dyn Error + Sync + Send>> {
+    /// let running = Arc::new(AtomicBool::new(true));
+    /// # running.store(true, Ordering::SeqCst);
+    /// let r = running.clone();
+    ///
+    /// ctrlc::set_handler(move || {
+    ///     r.store(false, Ordering::SeqCst);
+    /// }).expect("Error setting Ctrl-C handler");
+    ///
+    /// let (connection, io_threads) = Connection::stdio();
+    ///
+    /// let server_capabilities = serde_json::to_value(&ServerCapabilities::default()).unwrap();
+    /// let initialization_params = connection.initialize_while(
+    ///     server_capabilities,
+    ///     || running.load(Ordering::SeqCst)
+    /// );
+    ///
+    /// # assert!(initialization_params.is_err());
+    /// # Ok(())
+    /// # }
+    /// ```
+    pub fn initialize_while<C>(
+        &self,
+        server_capabilities: serde_json::Value,
+        running: C,
+    ) -> Result<serde_json::Value, ProtocolError>
+    where
+        C: Fn() -> bool,
+    {
+        let (id, params) = self.initialize_start_while(&running)?;
+
+        let initialize_data = serde_json::json!({
+            "capabilities": server_capabilities,
+        });
+
+        self.initialize_finish_while(id, initialize_data, running)?;
+
+        Ok(params)
+    }
+
     /// If `req` is `Shutdown`, respond to it and return `true`, otherwise return `false`
     pub fn handle_shutdown(&self, req: &Request) -> Result<bool, ProtocolError> {
         if !req.is_shutdown() {
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index fa941e6146a..60e0e007b1d 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -1933,7 +1933,7 @@ fn rewrite_unary_op(
     shape: Shape,
 ) -> Option<String> {
     // For some reason, an UnOp is not spanned like BinOp!
-    rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
+    rewrite_unary_prefix(context, op.as_str(), expr, shape)
 }
 
 pub(crate) enum RhsAssignKind<'ast> {
diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs
index 07c05193739..bfc2ffed383 100644
--- a/src/tools/rustfmt/src/pairs.rs
+++ b/src/tools/rustfmt/src/pairs.rs
@@ -339,7 +339,7 @@ impl FlattenPair for ast::Expr {
                     if let Some(pop) = stack.pop() {
                         match pop.kind {
                             ast::ExprKind::Binary(op, _, ref rhs) => {
-                                separators.push(op.node.to_string());
+                                separators.push(op.node.as_str());
                                 node = rhs;
                             }
                             _ => unreachable!(),
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 33f3b4b8a21..8504999b8ff 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -40,7 +40,9 @@ pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
 
 fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
     match pat.kind {
-        ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
+        ast::PatKind::Rest | ast::PatKind::Never | ast::PatKind::Wild | ast::PatKind::Lit(_) => {
+            true
+        }
         ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
         ast::PatKind::Struct(..)
         | ast::PatKind::MacCall(..)
@@ -193,6 +195,7 @@ impl Rewrite for Pat {
                     None
                 }
             }
+            PatKind::Never => None,
             PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
                 let infix = match end_kind.node {
                     RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index f36893bfb94..1f8edd7937b 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -129,7 +129,6 @@ const EXCEPTIONS_CARGO: ExceptionList = &[
 const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[
     // tidy-alphabetical-start
     ("dissimilar", "Apache-2.0"),
-    ("instant", "BSD-3-Clause"),
     ("notify", "CC0-1.0"),
     ("pulldown-cmark-to-cmark", "Apache-2.0"),
     ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0