about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorBen Kimock <kimockb@gmail.com>2024-11-15 06:29:30 +0000
committerGitHub <noreply@github.com>2024-11-15 06:29:30 +0000
commit3e71ed157037d9f77ff5ca73b015fe14e2b48792 (patch)
tree3efe043e15a6bd9518d8d833eaac2c8f73649f39 /src
parent7213a278eb67190fbceac4b4d948906ab49ff635 (diff)
parentb9116571ff44029f457bf6a60c7866fb28267a83 (diff)
Merge pull request #4034 from rust-lang/rustup-2024-11-15
Automatic Rustup
Diffstat (limited to 'src')
-rw-r--r--src/bootstrap/Cargo.toml2
-rw-r--r--src/bootstrap/bootstrap_test.py47
-rw-r--r--src/bootstrap/defaults/config.compiler.toml1
-rw-r--r--src/bootstrap/defaults/config.library.toml1
-rw-r--r--src/bootstrap/src/core/build_steps/clean.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/clippy.rs130
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs4
-rw-r--r--src/bootstrap/src/core/builder/cargo.rs9
-rw-r--r--src/bootstrap/src/core/builder/mod.rs1
-rw-r--r--src/bootstrap/src/core/config/config.rs80
-rw-r--r--src/bootstrap/src/core/config/tests.rs42
-rw-r--r--src/bootstrap/src/lib.rs6
-rw-r--r--src/bootstrap/src/utils/change_tracker.rs5
-rw-r--r--src/bootstrap/src/utils/helpers.rs2
-rw-r--r--src/build_helper/Cargo.toml (renamed from src/tools/build_helper/Cargo.toml)0
-rw-r--r--src/build_helper/README.md (renamed from src/tools/build_helper/README.md)0
-rw-r--r--src/build_helper/src/ci.rs (renamed from src/tools/build_helper/src/ci.rs)0
-rw-r--r--src/build_helper/src/drop_bomb/mod.rs (renamed from src/tools/build_helper/src/drop_bomb/mod.rs)0
-rw-r--r--src/build_helper/src/drop_bomb/tests.rs (renamed from src/tools/build_helper/src/drop_bomb/tests.rs)0
-rw-r--r--src/build_helper/src/git.rs (renamed from src/tools/build_helper/src/git.rs)0
-rw-r--r--src/build_helper/src/lib.rs (renamed from src/tools/build_helper/src/lib.rs)0
-rw-r--r--src/build_helper/src/metrics.rs (renamed from src/tools/build_helper/src/metrics.rs)0
-rw-r--r--src/build_helper/src/stage0_parser.rs (renamed from src/tools/build_helper/src/stage0_parser.rs)2
-rw-r--r--src/build_helper/src/util.rs (renamed from src/tools/build_helper/src/util.rs)0
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile4
-rwxr-xr-xsrc/ci/docker/run.sh4
-rwxr-xr-xsrc/ci/run.sh12
m---------src/doc/rust-by-example0
-rw-r--r--src/doc/rustdoc/src/read-documentation/search.md12
-rw-r--r--src/doc/unstable-book/src/language-features/asm-experimental-arch.md32
-rw-r--r--src/librustdoc/Cargo.toml2
-rw-r--r--src/librustdoc/clean/inline.rs18
-rw-r--r--src/librustdoc/clean/mod.rs15
-rw-r--r--src/librustdoc/clean/types.rs2
-rw-r--r--src/librustdoc/clean/utils.rs55
-rw-r--r--src/librustdoc/core.rs9
-rw-r--r--src/librustdoc/doctest.rs5
-rw-r--r--src/librustdoc/html/format.rs41
-rw-r--r--src/librustdoc/html/highlight.rs7
-rw-r--r--src/librustdoc/html/markdown.rs46
-rw-r--r--src/librustdoc/html/markdown/footnotes.rs77
-rw-r--r--src/librustdoc/html/render/context.rs4
-rw-r--r--src/librustdoc/html/render/mod.rs5
-rw-r--r--src/librustdoc/html/render/print_item.rs9
-rw-r--r--src/librustdoc/html/render/search_index.rs119
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css21
-rw-r--r--src/librustdoc/html/static/js/externs.js7
-rw-r--r--src/librustdoc/html/static/js/search.js1938
-rw-r--r--src/librustdoc/lib.rs2
-rw-r--r--src/tools/bump-stage0/Cargo.toml2
-rw-r--r--src/tools/clippy/CHANGELOG.md1
-rw-r--r--src/tools/clippy/clippy_dev/src/setup/vscode.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs/utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/comparison_chain.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/copies.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs1
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/doc/missing_headers.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/large_const_arrays.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/large_include_file.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/utils.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/try_err.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_next.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs131
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/useless_asref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs190
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs172
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/types/borrowed_box.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs6
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs31
-rw-r--r--src/tools/clippy/clippy_utils/src/numeric_literal.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs12
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs10
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed1
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs1
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr30
-rw-r--r--src/tools/clippy/tests/ui-toml/large_include_file/empty.txt0
-rw-r--r--src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs6
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed1
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs1
-rw-r--r--src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr12
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr20
-rw-r--r--src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr18
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes.stderr10
-rw-r--r--src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr2
-rw-r--r--src/tools/clippy/tests/ui/identity_op.fixed46
-rw-r--r--src/tools/clippy/tests/ui/identity_op.rs44
-rw-r--r--src/tools/clippy/tests/ui/identity_op.stderr70
-rw-r--r--src/tools/clippy/tests/ui/question_mark.fixed56
-rw-r--r--src/tools/clippy/tests/ui/question_mark.rs71
-rw-r--r--src/tools/clippy/tests/ui/question_mark.stderr63
-rw-r--r--src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr2
-rw-r--r--src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.fixed64
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.rs67
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_map_or.stderr99
-rw-r--r--src/tools/compiletest/Cargo.toml2
-rw-r--r--src/tools/compiletest/src/directive-list.rs3
-rw-r--r--src/tools/compiletest/src/header.rs27
-rw-r--r--src/tools/compiletest/src/header/tests.rs24
-rw-r--r--src/tools/miri/rust-version2
-rw-r--r--src/tools/miri/src/diagnostics.rs2
-rw-r--r--src/tools/opt-dist/Cargo.toml2
-rw-r--r--src/tools/run-make-support/Cargo.toml2
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs23
-rw-r--r--src/tools/run-make-support/src/lib.rs2
-rw-r--r--src/tools/run-make-support/src/targets.rs6
-rw-r--r--src/tools/rust-analyzer/.github/workflows/autopublish.yaml1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs97
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs144
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/utils.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs59
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs18
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs30
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs10
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md2
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md2
-rw-r--r--src/tools/rust-analyzer/editors/code/package-lock.json44
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json16
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts2
-rw-r--r--src/tools/rust-analyzer/triagebot.toml2
-rw-r--r--src/tools/rustbook/.gitignore1
-rw-r--r--src/tools/rustbook/Cargo.lock291
-rw-r--r--src/tools/rustdoc-gui-test/Cargo.toml2
-rw-r--r--src/tools/rustdoc-js/tester.js55
-rw-r--r--src/tools/suggest-tests/Cargo.toml2
-rw-r--r--src/tools/tidy/Cargo.toml2
-rw-r--r--src/tools/tidy/src/deps.rs3
-rw-r--r--src/tools/tidy/src/known_bug.rs18
-rw-r--r--src/tools/unicode-table-generator/src/range_search.rs1
-rw-r--r--src/tools/unicode-table-generator/src/raw_emitter.rs4
198 files changed, 3916 insertions, 1394 deletions
diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml
index ba505089a00..7950f1004a2 100644
--- a/src/bootstrap/Cargo.toml
+++ b/src/bootstrap/Cargo.toml
@@ -40,7 +40,7 @@ test = false
 cc = "=1.1.22"
 cmake = "=0.1.48"
 
-build_helper = { path = "../tools/build_helper" }
+build_helper = { path = "../build_helper" }
 clap = { version = "4.4", default-features = false, features = ["std", "usage", "help", "derive", "error-context"] }
 clap_complete = "4.4"
 fd-lock = "4.0"
diff --git a/src/bootstrap/bootstrap_test.py b/src/bootstrap/bootstrap_test.py
index 706f2c5bf07..70ed12b96e8 100644
--- a/src/bootstrap/bootstrap_test.py
+++ b/src/bootstrap/bootstrap_test.py
@@ -5,6 +5,7 @@ Run these with `x test bootstrap`, or `python -m unittest src/bootstrap/bootstra
 from __future__ import absolute_import, division, print_function
 import os
 import unittest
+from unittest.mock import patch
 import tempfile
 import hashlib
 import sys
@@ -99,6 +100,52 @@ class ProgramOutOfDate(unittest.TestCase):
         self.assertFalse(self.build.program_out_of_date(self.rustc_stamp_path, self.key))
 
 
+class ParseArgsInConfigure(unittest.TestCase):
+    """Test if `parse_args` function in `configure.py` works properly"""
+    @patch("configure.err")
+    def test_unknown_args(self, err):
+        # It should be print an error message if the argument doesn't start with '--'
+        configure.parse_args(["enable-full-tools"])
+        err.assert_called_with("Option 'enable-full-tools' is not recognized")
+        err.reset_mock()
+        # It should be print an error message if the argument is not recognized
+        configure.parse_args(["--some-random-flag"])
+        err.assert_called_with("Option '--some-random-flag' is not recognized")
+
+    @patch("configure.err")
+    def test_need_value_args(self, err):
+        """It should print an error message if a required argument value is missing"""
+        configure.parse_args(["--target"])
+        err.assert_called_with("Option '--target' needs a value (--target=val)")
+
+    @patch("configure.err")
+    def test_option_checking(self, err):
+        # Options should be checked even if `--enable-option-checking` is not passed
+        configure.parse_args(["--target"])
+        err.assert_called_with("Option '--target' needs a value (--target=val)")
+        err.reset_mock()
+        # Options should be checked if `--enable-option-checking` is passed
+        configure.parse_args(["--enable-option-checking", "--target"])
+        err.assert_called_with("Option '--target' needs a value (--target=val)")
+        err.reset_mock()
+        # Options should not be checked if `--disable-option-checking` is passed
+        configure.parse_args(["--disable-option-checking", "--target"])
+        err.assert_not_called()
+
+    @patch("configure.parse_example_config", lambda known_args, _: known_args)
+    def test_known_args(self):
+        # It should contain known and correct arguments
+        known_args = configure.parse_args(["--enable-full-tools"])
+        self.assertTrue(known_args["full-tools"][0][1])
+        known_args = configure.parse_args(["--disable-full-tools"])
+        self.assertFalse(known_args["full-tools"][0][1])
+        # It should contain known arguments and their values
+        known_args = configure.parse_args(["--target=x86_64-unknown-linux-gnu"])
+        self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu")
+        known_args = configure.parse_args(["--target", "x86_64-unknown-linux-gnu"])
+        self.assertEqual(known_args["target"][0][1], "x86_64-unknown-linux-gnu")
+
+
 class GenerateAndParseConfig(unittest.TestCase):
     """Test that we can serialize and deserialize a config.toml file"""
     def test_no_args(self):
diff --git a/src/bootstrap/defaults/config.compiler.toml b/src/bootstrap/defaults/config.compiler.toml
index 147939d2047..57a0ca5a718 100644
--- a/src/bootstrap/defaults/config.compiler.toml
+++ b/src/bootstrap/defaults/config.compiler.toml
@@ -19,6 +19,7 @@ lto = "off"
 # Forces frame pointers to be used with `-Cforce-frame-pointers`.
 # This can be helpful for profiling at a small performance cost.
 frame-pointers = true
+download-rustc = false
 
 [llvm]
 # Having this set to true disrupts compiler development workflows for people who use `llvm.download-ci-llvm = true`
diff --git a/src/bootstrap/defaults/config.library.toml b/src/bootstrap/defaults/config.library.toml
index 5447565a4b0..67ceb220524 100644
--- a/src/bootstrap/defaults/config.library.toml
+++ b/src/bootstrap/defaults/config.library.toml
@@ -10,6 +10,7 @@ bench-stage = 0
 incremental = true
 # Make the compiler and standard library faster to build, at the expense of a ~20% runtime slowdown.
 lto = "off"
+download-rustc = false
 
 [llvm]
 # Will download LLVM from CI if available on your platform.
diff --git a/src/bootstrap/src/core/build_steps/clean.rs b/src/bootstrap/src/core/build_steps/clean.rs
index 040690623a1..d857de96cce 100644
--- a/src/bootstrap/src/core/build_steps/clean.rs
+++ b/src/bootstrap/src/core/build_steps/clean.rs
@@ -226,6 +226,8 @@ where
         Err(ref e) if e.kind() == ErrorKind::PermissionDenied => {
             let m = t!(path.symlink_metadata());
             let mut p = m.permissions();
+            // this os not unix, so clippy gives FP
+            #[expect(clippy::permissions_set_readonly_false)]
             p.set_readonly(false);
             t!(fs::set_permissions(path, p));
             f(path).unwrap_or_else(|e| {
diff --git a/src/bootstrap/src/core/build_steps/clippy.rs b/src/bootstrap/src/core/build_steps/clippy.rs
index cd198c425c0..0884d86cc6d 100644
--- a/src/bootstrap/src/core/build_steps/clippy.rs
+++ b/src/bootstrap/src/core/build_steps/clippy.rs
@@ -20,14 +20,12 @@ const IGNORED_RULES_FOR_STD_AND_RUSTC: &[&str] = &[
     "wrong_self_convention",
 ];
 
-fn lint_args(builder: &Builder<'_>, ignored_rules: &[&str]) -> Vec<String> {
+fn lint_args(builder: &Builder<'_>, config: &LintConfig, ignored_rules: &[&str]) -> Vec<String> {
     fn strings<'a>(arr: &'a [&str]) -> impl Iterator<Item = String> + 'a {
         arr.iter().copied().map(String::from)
     }
 
-    let Subcommand::Clippy { fix, allow_dirty, allow_staged, allow, deny, warn, forbid } =
-        &builder.config.cmd
-    else {
+    let Subcommand::Clippy { fix, allow_dirty, allow_staged, .. } = &builder.config.cmd else {
         unreachable!("clippy::lint_args can only be called from `clippy` subcommands.");
     };
 
@@ -53,12 +51,12 @@ fn lint_args(builder: &Builder<'_>, ignored_rules: &[&str]) -> Vec<String> {
 
     args.extend(strings(&["--"]));
 
-    if deny.is_empty() && forbid.is_empty() {
+    if config.deny.is_empty() && config.forbid.is_empty() {
         args.extend(strings(&["--cap-lints", "warn"]));
     }
 
     let all_args = std::env::args().collect::<Vec<_>>();
-    args.extend(get_clippy_rules_in_order(&all_args, allow, deny, warn, forbid));
+    args.extend(get_clippy_rules_in_order(&all_args, config));
 
     args.extend(ignored_rules.iter().map(|lint| format!("-Aclippy::{}", lint)));
     args.extend(builder.config.free_args.clone());
@@ -68,21 +66,17 @@ fn lint_args(builder: &Builder<'_>, ignored_rules: &[&str]) -> Vec<String> {
 /// We need to keep the order of the given clippy lint rules before passing them.
 /// Since clap doesn't offer any useful interface for this purpose out of the box,
 /// we have to handle it manually.
-pub(crate) fn get_clippy_rules_in_order(
-    all_args: &[String],
-    allow_rules: &[String],
-    deny_rules: &[String],
-    warn_rules: &[String],
-    forbid_rules: &[String],
-) -> Vec<String> {
+pub fn get_clippy_rules_in_order(all_args: &[String], config: &LintConfig) -> Vec<String> {
     let mut result = vec![];
 
     for (prefix, item) in
-        [("-A", allow_rules), ("-D", deny_rules), ("-W", warn_rules), ("-F", forbid_rules)]
+        [("-A", &config.allow), ("-D", &config.deny), ("-W", &config.warn), ("-F", &config.forbid)]
     {
         item.iter().for_each(|v| {
             let rule = format!("{prefix}{v}");
-            let position = all_args.iter().position(|t| t == &rule).unwrap();
+            // Arguments added by bootstrap in LintConfig won't show up in the all_args list, so
+            // put them at the end of the command line.
+            let position = all_args.iter().position(|t| t == &rule || t == v).unwrap_or(usize::MAX);
             result.push((position, rule));
         });
     }
@@ -92,8 +86,41 @@ pub(crate) fn get_clippy_rules_in_order(
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct LintConfig {
+    pub allow: Vec<String>,
+    pub warn: Vec<String>,
+    pub deny: Vec<String>,
+    pub forbid: Vec<String>,
+}
+
+impl LintConfig {
+    fn new(builder: &Builder<'_>) -> Self {
+        match builder.config.cmd.clone() {
+            Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
+                Self { allow, warn, deny, forbid }
+            }
+            _ => unreachable!("LintConfig can only be called from `clippy` subcommands."),
+        }
+    }
+
+    fn merge(&self, other: &Self) -> Self {
+        let merged = |self_attr: &[String], other_attr: &[String]| -> Vec<String> {
+            self_attr.iter().cloned().chain(other_attr.iter().cloned()).collect()
+        };
+        // This is written this way to ensure we get a compiler error if we add a new field.
+        Self {
+            allow: merged(&self.allow, &other.allow),
+            warn: merged(&self.warn, &other.warn),
+            deny: merged(&self.deny, &other.deny),
+            forbid: merged(&self.forbid, &other.forbid),
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Std {
     pub target: TargetSelection,
+    config: LintConfig,
     /// Whether to lint only a subset of crates.
     crates: Vec<String>,
 }
@@ -108,7 +135,8 @@ impl Step for Std {
 
     fn make_run(run: RunConfig<'_>) {
         let crates = std_crates_for_run_make(&run);
-        run.builder.ensure(Std { target: run.target, crates });
+        let config = LintConfig::new(run.builder);
+        run.builder.ensure(Std { target: run.target, config, crates });
     }
 
     fn run(self, builder: &Builder<'_>) {
@@ -138,7 +166,7 @@ impl Step for Std {
         run_cargo(
             builder,
             cargo,
-            lint_args(builder, IGNORED_RULES_FOR_STD_AND_RUSTC),
+            lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
             &libstd_stamp(builder, compiler, target),
             vec![],
             true,
@@ -150,6 +178,7 @@ impl Step for Std {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct Rustc {
     pub target: TargetSelection,
+    config: LintConfig,
     /// Whether to lint only a subset of crates.
     crates: Vec<String>,
 }
@@ -165,7 +194,8 @@ impl Step for Rustc {
 
     fn make_run(run: RunConfig<'_>) {
         let crates = run.make_run_crates(Alias::Compiler);
-        run.builder.ensure(Rustc { target: run.target, crates });
+        let config = LintConfig::new(run.builder);
+        run.builder.ensure(Rustc { target: run.target, config, crates });
     }
 
     /// Lints the compiler.
@@ -212,7 +242,7 @@ impl Step for Rustc {
         run_cargo(
             builder,
             cargo,
-            lint_args(builder, IGNORED_RULES_FOR_STD_AND_RUSTC),
+            lint_args(builder, &self.config, IGNORED_RULES_FOR_STD_AND_RUSTC),
             &librustc_stamp(builder, compiler, target),
             vec![],
             true,
@@ -232,6 +262,7 @@ macro_rules! lint_any {
         #[derive(Debug, Clone, Hash, PartialEq, Eq)]
         pub struct $name {
             pub target: TargetSelection,
+            config: LintConfig,
         }
 
         impl Step for $name {
@@ -243,8 +274,10 @@ macro_rules! lint_any {
             }
 
             fn make_run(run: RunConfig<'_>) {
+                let config = LintConfig::new(run.builder);
                 run.builder.ensure($name {
                     target: run.target,
+                    config,
                 });
             }
 
@@ -281,7 +314,7 @@ macro_rules! lint_any {
                 run_cargo(
                     builder,
                     cargo,
-                    lint_args(builder, &[]),
+                    lint_args(builder, &self.config, &[]),
                     &stamp,
                     vec![],
                     true,
@@ -295,7 +328,7 @@ macro_rules! lint_any {
 
 lint_any!(
     Bootstrap, "src/bootstrap", "bootstrap";
-    BuildHelper, "src/tools/build_helper", "build_helper";
+    BuildHelper, "src/build_helper", "build_helper";
     BuildManifest, "src/tools/build-manifest", "build-manifest";
     CargoMiri, "src/tools/miri/cargo-miri", "cargo-miri";
     Clippy, "src/tools/clippy", "clippy";
@@ -319,3 +352,58 @@ lint_any!(
     Tidy, "src/tools/tidy", "tidy";
     TestFloatParse, "src/etc/test-float-parse", "test-float-parse";
 );
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct CI {
+    target: TargetSelection,
+    config: LintConfig,
+}
+
+impl Step for CI {
+    type Output = ();
+    const DEFAULT: bool = false;
+
+    fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
+        run.alias("ci")
+    }
+
+    fn make_run(run: RunConfig<'_>) {
+        let config = LintConfig::new(run.builder);
+        run.builder.ensure(CI { target: run.target, config });
+    }
+
+    fn run(self, builder: &Builder<'_>) -> Self::Output {
+        builder.ensure(Bootstrap {
+            target: self.target,
+            config: self.config.merge(&LintConfig {
+                allow: vec![],
+                warn: vec![],
+                deny: vec!["warnings".into()],
+                forbid: vec![],
+            }),
+        });
+        let library_clippy_cfg = LintConfig {
+            allow: vec!["clippy::all".into()],
+            warn: vec![],
+            deny: vec!["clippy::correctness".into()],
+            forbid: vec![],
+        };
+        let compiler_clippy_cfg = LintConfig {
+            allow: vec!["clippy::all".into()],
+            warn: vec![],
+            deny: vec!["clippy::correctness".into(), "clippy::clone_on_ref_ptr".into()],
+            forbid: vec![],
+        };
+
+        builder.ensure(Std {
+            target: self.target,
+            config: self.config.merge(&library_clippy_cfg),
+            crates: vec![],
+        });
+        builder.ensure(Rustc {
+            target: self.target,
+            config: self.config.merge(&compiler_clippy_cfg),
+            crates: vec![],
+        });
+    }
+}
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 3394f2a84a0..24be705f481 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -1976,9 +1976,13 @@ impl Step for Assemble {
             }
         }
 
-        {
-            // `llvm-strip` is used by rustc, which is actually just a symlink to `llvm-objcopy`,
-            // so copy and rename `llvm-objcopy`.
+        if builder.config.llvm_enabled(target_compiler.host) && builder.config.llvm_tools_enabled {
+            // `llvm-strip` is used by rustc, which is actually just a symlink to `llvm-objcopy`, so
+            // copy and rename `llvm-objcopy`.
+            //
+            // But only do so if llvm-tools are enabled, as bootstrap compiler might not contain any
+            // LLVM tools, e.g. for cg_clif.
+            // See <https://github.com/rust-lang/rust/issues/132719>.
             let src_exe = exe("llvm-objcopy", target_compiler.host);
             let dst_exe = exe("rust-objcopy", target_compiler.host);
             builder.copy_link(&libdir_bin.join(src_exe), &libdir_bin.join(dst_exe));
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 69ec832a44a..8a9321f8e79 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -1030,7 +1030,7 @@ macro_rules! tool_doc {
 // NOTE: make sure to register these in `Builder::get_step_description`.
 tool_doc!(
     BuildHelper,
-    "src/tools/build_helper",
+    "src/build_helper",
     rustc_tool = false,
     is_library = true,
     crates = ["build_helper"]
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index 2c36d8bab82..532c8f767eb 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -1354,7 +1354,7 @@ impl Step for CrateBuildHelper {
     const ONLY_HOSTS: bool = true;
 
     fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> {
-        run.path("src/tools/build_helper")
+        run.path("src/build_helper")
     }
 
     fn make_run(run: RunConfig<'_>) {
@@ -1372,7 +1372,7 @@ impl Step for CrateBuildHelper {
             Mode::ToolBootstrap,
             host,
             Kind::Test,
-            "src/tools/build_helper",
+            "src/build_helper",
             SourceType::InTree,
             &[],
         );
diff --git a/src/bootstrap/src/core/builder/cargo.rs b/src/bootstrap/src/core/builder/cargo.rs
index 134da5db96d..0688a1d6892 100644
--- a/src/bootstrap/src/core/builder/cargo.rs
+++ b/src/bootstrap/src/core/builder/cargo.rs
@@ -1198,15 +1198,6 @@ impl Builder<'_> {
             rustflags.arg("-Zinline-mir-preserve-debug");
         }
 
-        if self.config.rustc_parallel
-            && matches!(mode, Mode::ToolRustc | Mode::Rustc | Mode::Codegen)
-        {
-            // keep in sync with `bootstrap/lib.rs:Build::rustc_features`
-            // `cfg` option for rustc, `features` option for cargo, for conditional compilation
-            rustflags.arg("--cfg=parallel_compiler");
-            rustdocflags.arg("--cfg=parallel_compiler");
-        }
-
         Cargo {
             command: cargo,
             compiler,
diff --git a/src/bootstrap/src/core/builder/mod.rs b/src/bootstrap/src/core/builder/mod.rs
index f1b3cf6da13..d59e0fa7288 100644
--- a/src/bootstrap/src/core/builder/mod.rs
+++ b/src/bootstrap/src/core/builder/mod.rs
@@ -839,6 +839,7 @@ impl<'a> Builder<'a> {
                 clippy::RustInstaller,
                 clippy::TestFloatParse,
                 clippy::Tidy,
+                clippy::CI,
             ),
             Kind::Check | Kind::Fix => describe!(
                 check::Std,
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index a93038d51d3..95b1303fa71 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -28,6 +28,24 @@ use crate::utils::cache::{INTERNER, Interned};
 use crate::utils::channel::{self, GitInfo};
 use crate::utils::helpers::{self, exe, output, t};
 
+/// Each path in this list is considered "allowed" in the `download-rustc="if-unchanged"` logic.
+/// This means they can be modified and changes to these paths should never trigger a compiler build
+/// when "if-unchanged" is set.
+///
+/// NOTE: Paths must have the ":!" prefix to tell git to ignore changes in those paths during
+/// the diff check.
+///
+/// WARNING: Be cautious when adding paths to this list. If a path that influences the compiler build
+/// is added here, it will cause bootstrap to skip necessary rebuilds, which may lead to risky results.
+/// For example, "src/bootstrap" should never be included in this list as it plays a crucial role in the
+/// final output/compiler, which can be significantly affected by changes made to the bootstrap sources.
+#[rustfmt::skip] // We don't want rustfmt to oneline this list
+pub(crate) const RUSTC_IF_UNCHANGED_ALLOWED_PATHS: &[&str] = &[
+    ":!src/tools",
+    ":!tests",
+    ":!triagebot.toml",
+];
+
 macro_rules! check_ci_llvm {
     ($name:expr) => {
         assert!(
@@ -278,7 +296,6 @@ pub struct Config {
     pub rust_strip: bool,
     pub rust_frame_pointers: bool,
     pub rust_stack_protector: Option<String>,
-    pub rustc_parallel: bool,
     pub rustc_default_linker: Option<String>,
     pub rust_optimize_tests: bool,
     pub rust_dist_src: bool,
@@ -1224,7 +1241,6 @@ impl Config {
             bindir: "bin".into(),
             dist_include_mingw_linker: true,
             dist_compression_profile: "fast".into(),
-            rustc_parallel: true,
 
             stdout_is_tty: std::io::stdout().is_terminal(),
             stderr_is_tty: std::io::stderr().is_terminal(),
@@ -1668,6 +1684,14 @@ impl Config {
         let mut lld_enabled = None;
         let mut std_features = None;
 
+        let is_user_configured_rust_channel =
+            if let Some(channel) = toml.rust.as_ref().and_then(|r| r.channel.clone()) {
+                config.channel = channel;
+                true
+            } else {
+                false
+            };
+
         let default = config.channel == "dev";
         config.omit_git_hash = toml.rust.as_ref().and_then(|r| r.omit_git_hash).unwrap_or(default);
 
@@ -1685,8 +1709,6 @@ impl Config {
         config.in_tree_llvm_info = GitInfo::new(false, &config.src.join("src/llvm-project"));
         config.in_tree_gcc_info = GitInfo::new(false, &config.src.join("src/gcc"));
 
-        let mut is_user_configured_rust_channel = false;
-
         if let Some(rust) = toml.rust {
             let Rust {
                 optimize: optimize_toml,
@@ -1708,7 +1730,7 @@ impl Config {
                 parallel_compiler,
                 randomize_layout,
                 default_linker,
-                channel,
+                channel: _, // already handled above
                 description,
                 musl_root,
                 rpath,
@@ -1745,9 +1767,6 @@ impl Config {
                 std_features: std_features_toml,
             } = rust;
 
-            is_user_configured_rust_channel = channel.is_some();
-            set(&mut config.channel, channel.clone());
-
             config.download_rustc_commit =
                 config.download_ci_rustc_commit(download_rustc, config.llvm_assertions);
 
@@ -1788,8 +1807,14 @@ impl Config {
 
             config.rust_randomize_layout = randomize_layout.unwrap_or_default();
             config.llvm_tools_enabled = llvm_tools.unwrap_or(true);
-            config.rustc_parallel =
-                parallel_compiler.unwrap_or(config.channel == "dev" || config.channel == "nightly");
+
+            // FIXME: Remove this option at the end of 2024.
+            if parallel_compiler.is_some() {
+                println!(
+                    "WARNING: The `rust.parallel-compiler` option is deprecated and does nothing. The parallel compiler (with one thread) is now the default"
+                );
+            }
+
             config.llvm_enzyme =
                 llvm_enzyme.unwrap_or(config.channel == "dev" || config.channel == "nightly");
             config.rustc_default_linker = default_linker;
@@ -2775,32 +2800,33 @@ impl Config {
             }
         };
 
-        let mut files_to_track = vec!["compiler", "src/version", "src/stage0", "src/ci/channel"];
+        // RUSTC_IF_UNCHANGED_ALLOWED_PATHS
+        let mut allowed_paths = RUSTC_IF_UNCHANGED_ALLOWED_PATHS.to_vec();
 
-        // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, ignore
+        // In CI, disable ci-rustc if there are changes in the library tree. But for non-CI, allow
         // these changes to speed up the build process for library developers. This provides consistent
         // functionality for library developers between `download-rustc=true` and `download-rustc="if-unchanged"`
         // options.
-        if CiEnv::is_ci() {
-            files_to_track.push("library");
+        if !CiEnv::is_ci() {
+            allowed_paths.push(":!library");
         }
 
         // Look for a version to compare to based on the current commit.
         // Only commits merged by bors will have CI artifacts.
-        let commit =
-            match self.last_modified_commit(&files_to_track, "download-rustc", if_unchanged) {
-                Some(commit) => commit,
-                None => {
-                    if if_unchanged {
-                        return None;
-                    }
-                    println!("ERROR: could not find commit hash for downloading rustc");
-                    println!("HELP: maybe your repository history is too shallow?");
-                    println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
-                    println!("HELP: or fetch enough history to include one upstream commit");
-                    crate::exit!(1);
+        let commit = match self.last_modified_commit(&allowed_paths, "download-rustc", if_unchanged)
+        {
+            Some(commit) => commit,
+            None => {
+                if if_unchanged {
+                    return None;
                 }
-            };
+                println!("ERROR: could not find commit hash for downloading rustc");
+                println!("HELP: maybe your repository history is too shallow?");
+                println!("HELP: consider setting `rust.download-rustc=false` in config.toml");
+                println!("HELP: or fetch enough history to include one upstream commit");
+                crate::exit!(1);
+            }
+        };
 
         if CiEnv::is_ci() && {
             let head_sha =
diff --git a/src/bootstrap/src/core/config/tests.rs b/src/bootstrap/src/core/config/tests.rs
index b6523a458e2..24f932a1724 100644
--- a/src/bootstrap/src/core/config/tests.rs
+++ b/src/bootstrap/src/core/config/tests.rs
@@ -8,8 +8,8 @@ use clap::CommandFactory;
 use serde::Deserialize;
 
 use super::flags::Flags;
-use super::{ChangeIdWrapper, Config};
-use crate::core::build_steps::clippy::get_clippy_rules_in_order;
+use super::{ChangeIdWrapper, Config, RUSTC_IF_UNCHANGED_ALLOWED_PATHS};
+use crate::core::build_steps::clippy::{LintConfig, get_clippy_rules_in_order};
 use crate::core::build_steps::llvm;
 use crate::core::config::{LldMode, Target, TargetSelection, TomlConfig};
 
@@ -309,9 +309,10 @@ fn order_of_clippy_rules() {
     ];
     let config = Config::parse(Flags::parse(&args));
 
-    let actual = match &config.cmd {
+    let actual = match config.cmd.clone() {
         crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
-            get_clippy_rules_in_order(&args, &allow, &deny, &warn, &forbid)
+            let cfg = LintConfig { allow, deny, warn, forbid };
+            get_clippy_rules_in_order(&args, &cfg)
         }
         _ => panic!("invalid subcommand"),
     };
@@ -327,6 +328,24 @@ fn order_of_clippy_rules() {
 }
 
 #[test]
+fn clippy_rule_separate_prefix() {
+    let args =
+        vec!["clippy".to_string(), "-A clippy:all".to_string(), "-W clippy::style".to_string()];
+    let config = Config::parse(Flags::parse(&args));
+
+    let actual = match config.cmd.clone() {
+        crate::Subcommand::Clippy { allow, deny, warn, forbid, .. } => {
+            let cfg = LintConfig { allow, deny, warn, forbid };
+            get_clippy_rules_in_order(&args, &cfg)
+        }
+        _ => panic!("invalid subcommand"),
+    };
+
+    let expected = vec!["-A clippy:all".to_string(), "-W clippy::style".to_string()];
+    assert_eq!(expected, actual);
+}
+
+#[test]
 fn verbose_tests_default_value() {
     let config = Config::parse(Flags::parse(&["build".into(), "compiler".into()]));
     assert_eq!(config.verbose_tests, false);
@@ -413,3 +432,18 @@ fn jobs_precedence() {
     );
     assert_eq!(config.jobs, Some(123));
 }
+
+#[test]
+fn check_rustc_if_unchanged_paths() {
+    let config = parse("");
+    let normalised_allowed_paths: Vec<_> = RUSTC_IF_UNCHANGED_ALLOWED_PATHS
+        .iter()
+        .map(|t| {
+            t.strip_prefix(":!").expect(&format!("{t} doesn't have ':!' prefix, but it should."))
+        })
+        .collect();
+
+    for p in normalised_allowed_paths {
+        assert!(config.src.join(p).exists(), "{p} doesn't exist.");
+    }
+}
diff --git a/src/bootstrap/src/lib.rs b/src/bootstrap/src/lib.rs
index ba74cabcd30..c384fd6bf43 100644
--- a/src/bootstrap/src/lib.rs
+++ b/src/bootstrap/src/lib.rs
@@ -80,11 +80,8 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &str, Option<&[&'static str]>)] = &[
     (Some(Mode::Rustc), "llvm_enzyme", None),
     (Some(Mode::Codegen), "llvm_enzyme", None),
     (Some(Mode::ToolRustc), "llvm_enzyme", None),
-    (Some(Mode::Rustc), "parallel_compiler", None),
-    (Some(Mode::ToolRustc), "parallel_compiler", None),
     (Some(Mode::ToolRustc), "rust_analyzer", None),
     (Some(Mode::ToolStd), "rust_analyzer", None),
-    (Some(Mode::Codegen), "parallel_compiler", None),
     // Any library specific cfgs like `target_os`, `target_arch` should be put in
     // priority the `[lints.rust.unexpected_cfgs.check-cfg]` table
     // in the appropriate `library/{std,alloc,core}/Cargo.toml`
@@ -695,9 +692,6 @@ impl Build {
             features.push("llvm");
         }
         // keep in sync with `bootstrap/compile.rs:rustc_cargo_env`
-        if self.config.rustc_parallel && check("rustc_use_parallel_compiler") {
-            features.push("rustc_use_parallel_compiler");
-        }
         if self.config.rust_randomize_layout {
             features.push("rustc_randomized_layouts");
         }
diff --git a/src/bootstrap/src/utils/change_tracker.rs b/src/bootstrap/src/utils/change_tracker.rs
index 0915ec15a2f..1d05f94e3be 100644
--- a/src/bootstrap/src/utils/change_tracker.rs
+++ b/src/bootstrap/src/utils/change_tracker.rs
@@ -291,6 +291,11 @@ pub const CONFIG_CHANGE_HISTORY: &[ChangeInfo] = &[
         summary: "New option `llvm.offload` to control whether the llvm offload runtime for GPU support is built. Implicitly enables the openmp runtime as dependency.",
     },
     ChangeInfo {
+        change_id: 132282,
+        severity: ChangeSeverity::Warning,
+        summary: "Deprecated `rust.parallel_compiler` as the compiler now always defaults to being parallel (with 1 thread)",
+    },
+    ChangeInfo {
         change_id: 132494,
         severity: ChangeSeverity::Info,
         summary: "`download-rustc='if-unchanged'` is now a default option for library profile.",
diff --git a/src/bootstrap/src/utils/helpers.rs b/src/bootstrap/src/utils/helpers.rs
index 7162007e9f0..3fb2330469a 100644
--- a/src/bootstrap/src/utils/helpers.rs
+++ b/src/bootstrap/src/utils/helpers.rs
@@ -145,7 +145,7 @@ pub fn symlink_dir(config: &Config, original: &Path, link: &Path) -> io::Result<
 
     #[cfg(windows)]
     fn symlink_dir_inner(target: &Path, junction: &Path) -> io::Result<()> {
-        junction::create(&target, &junction)
+        junction::create(target, junction)
     }
 }
 
diff --git a/src/tools/build_helper/Cargo.toml b/src/build_helper/Cargo.toml
index 66894e1abc4..66894e1abc4 100644
--- a/src/tools/build_helper/Cargo.toml
+++ b/src/build_helper/Cargo.toml
diff --git a/src/tools/build_helper/README.md b/src/build_helper/README.md
index f81b631c3fd..f81b631c3fd 100644
--- a/src/tools/build_helper/README.md
+++ b/src/build_helper/README.md
diff --git a/src/tools/build_helper/src/ci.rs b/src/build_helper/src/ci.rs
index 60f319129a0..60f319129a0 100644
--- a/src/tools/build_helper/src/ci.rs
+++ b/src/build_helper/src/ci.rs
diff --git a/src/tools/build_helper/src/drop_bomb/mod.rs b/src/build_helper/src/drop_bomb/mod.rs
index 0a5bb04b55b..0a5bb04b55b 100644
--- a/src/tools/build_helper/src/drop_bomb/mod.rs
+++ b/src/build_helper/src/drop_bomb/mod.rs
diff --git a/src/tools/build_helper/src/drop_bomb/tests.rs b/src/build_helper/src/drop_bomb/tests.rs
index 4a488c0f670..4a488c0f670 100644
--- a/src/tools/build_helper/src/drop_bomb/tests.rs
+++ b/src/build_helper/src/drop_bomb/tests.rs
diff --git a/src/tools/build_helper/src/git.rs b/src/build_helper/src/git.rs
index 2aad5650fa8..2aad5650fa8 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/build_helper/src/git.rs
diff --git a/src/tools/build_helper/src/lib.rs b/src/build_helper/src/lib.rs
index 4a4f0ca2a9d..4a4f0ca2a9d 100644
--- a/src/tools/build_helper/src/lib.rs
+++ b/src/build_helper/src/lib.rs
diff --git a/src/tools/build_helper/src/metrics.rs b/src/build_helper/src/metrics.rs
index 2d0c66a8f33..2d0c66a8f33 100644
--- a/src/tools/build_helper/src/metrics.rs
+++ b/src/build_helper/src/metrics.rs
diff --git a/src/tools/build_helper/src/stage0_parser.rs b/src/build_helper/src/stage0_parser.rs
index ff05b116989..2a0c12a1c91 100644
--- a/src/tools/build_helper/src/stage0_parser.rs
+++ b/src/build_helper/src/stage0_parser.rs
@@ -25,7 +25,7 @@ pub struct Stage0Config {
 }
 
 pub fn parse_stage0_file() -> Stage0 {
-    let stage0_content = include_str!("../../../stage0");
+    let stage0_content = include_str!("../../stage0");
 
     let mut stage0 = Stage0::default();
     for line in stage0_content.lines() {
diff --git a/src/tools/build_helper/src/util.rs b/src/build_helper/src/util.rs
index 72c05c4c48a..72c05c4c48a 100644
--- a/src/tools/build_helper/src/util.rs
+++ b/src/build_helper/src/util.rs
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index fdc8a7310c8..f0afb570cc4 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -50,9 +50,7 @@ ENV SCRIPT \
            python3 ../x.py check --stage 0 --set build.optimized-compiler-builtins=false core alloc std --target=aarch64-unknown-linux-gnu,i686-pc-windows-msvc,i686-unknown-linux-gnu,x86_64-apple-darwin,x86_64-pc-windows-gnu,x86_64-pc-windows-msvc && \
            /scripts/check-default-config-profiles.sh && \
            python3 ../x.py check --target=i686-pc-windows-gnu --host=i686-pc-windows-gnu && \
-           python3 ../x.py clippy bootstrap -Dwarnings && \
-           python3 ../x.py clippy library -Aclippy::all -Dclippy::correctness && \
-           python3 ../x.py clippy compiler -Aclippy::all -Dclippy::correctness -Dclippy::clone_on_ref_ptr && \
+           python3 ../x.py clippy ci && \
            python3 ../x.py build --stage 0 src/tools/build-manifest && \
            python3 ../x.py test --stage 0 src/tools/compiletest && \
            python3 ../x.py test --stage 0 core alloc std test proc_macro && \
diff --git a/src/ci/docker/run.sh b/src/ci/docker/run.sh
index 28487bce482..d554186df4c 100755
--- a/src/ci/docker/run.sh
+++ b/src/ci/docker/run.sh
@@ -96,7 +96,9 @@ if [ -f "$docker_dir/$image/Dockerfile" ]; then
     docker --version
 
     REGISTRY=ghcr.io
-    REGISTRY_USERNAME=${GITHUB_REPOSITORY_OWNER:-rust-lang-ci}
+    # Hardcode username to reuse cache between auto and pr jobs
+    # FIXME: should be changed after move from rust-lang-ci
+    REGISTRY_USERNAME=rust-lang-ci
     # Tag used to push the final Docker image, so that it can be pulled by e.g. rustup
     IMAGE_TAG=${REGISTRY}/${REGISTRY_USERNAME}/rust-ci:${cksum}
     # Tag used to cache the Docker build
diff --git a/src/ci/run.sh b/src/ci/run.sh
index 8e2f525db68..5690d8edea6 100755
--- a/src/ci/run.sh
+++ b/src/ci/run.sh
@@ -115,14 +115,16 @@ RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --release-channel=$RUST_RELEASE_CHANNE
 if [ "$DEPLOY$DEPLOY_ALT" = "1" ]; then
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-static-stdcpp"
   RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.remap-debuginfo"
-  RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
+
+  if [ "$DEPLOY_ALT" != "" ]; then
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level=2"
+  else
+    RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --debuginfo-level-std=1"
+  fi
 
   if [ "$NO_LLVM_ASSERTIONS" = "1" ]; then
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --disable-llvm-assertions"
   elif [ "$DEPLOY_ALT" != "" ]; then
-    if [ "$ALT_PARALLEL_COMPILER" = "" ]; then
-      RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.parallel-compiler=false"
-    fi
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-llvm-assertions"
     RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --set rust.verify-llvm-ir"
   fi
@@ -261,7 +263,7 @@ fi
 
 if [ "$RUN_CHECK_WITH_PARALLEL_QUERIES" != "" ]; then
   rm -f config.toml
-  $SRC/configure --set change-id=99999999 --set rust.parallel-compiler
+  $SRC/configure --set change-id=99999999
 
   # Save the build metrics before we wipe the directory
   if [ "$HAS_METRICS" = 1 ]; then
diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example
-Subproject 9db78608b17d5f4a6c033b8a3038466b87d6320
+Subproject e1d1f2cdcee4d52b9a01ff7c448be4372a377b7
diff --git a/src/doc/rustdoc/src/read-documentation/search.md b/src/doc/rustdoc/src/read-documentation/search.md
index e912ca0fe5b..718d2201c3a 100644
--- a/src/doc/rustdoc/src/read-documentation/search.md
+++ b/src/doc/rustdoc/src/read-documentation/search.md
@@ -130,29 +130,31 @@ pub trait MyTrait {
 /// This function can be found using the following search queries:
 ///
 ///     MyTrait<First=u8, Second=u32> -> bool
-///     MyTrait<u32, First=u8> -> bool
 ///     MyTrait<Second=u32> -> bool
-///     MyTrait<u32, u8> -> bool
 ///
 /// The following queries, however, will *not* match it:
 ///
 ///     MyTrait<First=u32> -> bool
 ///     MyTrait<u32, u32> -> bool
+///     MyTrait<u32, First=u8> -> bool
+///     MyTrait<u32, u8> -> bool
 pub fn my_fn(x: impl MyTrait<First=u8, Second=u32>) -> bool { true }
 ```
 
-Generics and function parameters are order-agnostic, but sensitive to nesting
+Function parameters are order-agnostic, but sensitive to nesting
 and number of matches. For example, a function with the signature
 `fn read_all(&mut self: impl Read) -> Result<Vec<u8>, Error>`
 will match these queries:
 
 * `&mut Read -> Result<Vec<u8>, Error>`
 * `Read -> Result<Vec<u8>, Error>`
-* `Read -> Result<Error, Vec>`
 * `Read -> Result<Vec<u8>>`
 * `Read -> u8`
 
-But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`.
+But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`,
+because those are nested incorrectly, and it does not match
+`Result<Error, Vec<u8>>` or `Result<Error>`, because those are
+in the wrong order.
 
 To search for a function that accepts a function as a parameter,
 like `Iterator::all`, wrap the nested signature in parenthesis,
diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
index f00a0fe7287..01de12bb90e 100644
--- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
+++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md
@@ -18,7 +18,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 - MSP430
 - M68k
 - CSKY
-- Arm64EC
 - SPARC
 
 ## Register classes
@@ -53,9 +52,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`         | `f[0-31]`                          | `f`                  |
 | SPARC        | `reg`          | `r[2-29]`                          | `r`                  |
 | SPARC        | `yreg`         | `y`                                | Only clobbers        |
-| Arm64EC      | `reg`          | `x[0-12]`, `x[15-22]`, `x[25-27]`, `x30` | `r`            |
-| Arm64EC      | `vreg`         | `v[0-15]`                          | `w`                  |
-| Arm64EC      | `vreg_low16`   | `v[0-15]`                          | `x`                  |
 
 > **Notes**:
 > - NVPTX doesn't have a fixed register set, so named registers are not supported.
@@ -92,8 +88,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | CSKY         | `freg`                          | None           | `f32`,                                  |
 | SPARC        | `reg`                           | None           | `i8`, `i16`, `i32`, `i64` (SPARC64 only) |
 | SPARC        | `yreg`                          | N/A            | Only clobbers                           |
-| Arm64EC      | `reg`                           | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` |
-| Arm64EC      | `vreg`                          | None           | `i8`, `i16`, `i32`, `f32`, `i64`, `f64`, <br> `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2`, `f64x1`, <br> `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4`, `f64x2` |
 
 ## Register aliases
 
@@ -134,12 +128,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | SPARC        | `r[8-15]`     | `o[0-7]`  |
 | SPARC        | `r[16-23]`    | `l[0-7]`  |
 | SPARC        | `r[24-31]`    | `i[0-7]`  |
-| Arm64EC      | `x[0-30]`     | `w[0-30]` |
-| Arm64EC      | `x29`         | `fp`      |
-| Arm64EC      | `x30`         | `lr`      |
-| Arm64EC      | `sp`          | `wsp`     |
-| Arm64EC      | `xzr`         | `wzr`     |
-| Arm64EC      | `v[0-15]`     | `b[0-15]`, `h[0-15]`, `s[0-15]`, `d[0-15]`, `q[0-15]` |
 
 > **Notes**:
 > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed
@@ -150,8 +138,8 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | Architecture | Unsupported register                    | Reason                                                                                                                                                                              |
 | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
 | All          | `sp`, `r14`/`o6` (SPARC)                | The stack pointer must be restored to its original value at the end of an asm code block.                                                                                           |
-| All          | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC), `x29` (Arm64EC) | The frame pointer cannot be used as an input or output.                                            |
-| All          | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC), `x19` (Arm64EC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames.                                                             |
+| All          | `fr` (Hexagon), `fp` (PowerPC), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r30`/`i6` (SPARC) | The frame pointer cannot be used as an input or output.                                                             |
+| All          | `r19` (Hexagon), `r29` (PowerPC), `r30` (PowerPC) | These are used internally by LLVM as "base pointer" for functions with complex stack frames.                                                                              |
 | MIPS         | `$0` or `$zero`                         | This is a constant zero register which can't be modified.                                                                                                                           |
 | MIPS         | `$1` or `$at`                           | Reserved for assembler.                                                                                                                                                             |
 | MIPS         | `$26`/`$k0`, `$27`/`$k1`                | OS-reserved registers.                                                                                                                                                              |
@@ -176,9 +164,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | SPARC        | `r5`/`g5`                               | Reserved for system. (SPARC32 only) |
 | SPARC        | `r6`/`g6`, `r7`/`g7`                    | Reserved for system. |
 | SPARC        | `r31`/`i7`                              | Return address cannot be used as inputs or outputs. |
-| Arm64EC      | `xzr`                                   | This is a constant zero register which can't be modified. |
-| Arm64EC      | `x18`                                   | This is an OS-reserved register. |
-| Arm64EC      | `x13`, `x14`, `x23`, `x24`, `x28`, `v[16-31]` | These are AArch64 registers that are not supported for Arm64EC. |
 
 
 ## Template modifiers
@@ -197,16 +182,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect
 | SPARC        | `reg`          | None     | `%o0`          | None          |
 | CSKY         | `reg`          | None     | `r0`           | None          |
 | CSKY         | `freg`         | None     | `f0`           | None          |
-| Arm64EC      | `reg`          | None     | `x0`           | `x`           |
-| Arm64EC      | `reg`          | `w`      | `w0`           | `w`           |
-| Arm64EC      | `reg`          | `x`      | `x0`           | `x`           |
-| Arm64EC      | `vreg`         | None     | `v0`           | None          |
-| Arm64EC      | `vreg`         | `v`      | `v0`           | None          |
-| Arm64EC      | `vreg`         | `b`      | `b0`           | `b`           |
-| Arm64EC      | `vreg`         | `h`      | `h0`           | `h`           |
-| Arm64EC      | `vreg`         | `s`      | `s0`           | `s`           |
-| Arm64EC      | `vreg`         | `d`      | `d0`           | `d`           |
-| Arm64EC      | `vreg`         | `q`      | `q0`           | `q`           |
 
 # Flags covered by `preserves_flags`
 
@@ -220,6 +195,3 @@ These flags registers must be restored upon exiting the asm block if the `preser
 - SPARC
   - Integer condition codes (`icc` and `xcc`)
   - Floating-point condition codes (`fcc[0-3]`)
-- Arm64EC
-  - Condition flags (`NZCV` register).
-  - Floating-point status (`FPSR` register).
diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml
index 57b6de67ee8..70749f7cb17 100644
--- a/src/librustdoc/Cargo.toml
+++ b/src/librustdoc/Cargo.toml
@@ -13,7 +13,7 @@ rinja = { version = "0.3", default-features = false, features = ["config"] }
 base64 = "0.21.7"
 itertools = "0.12"
 indexmap = "2"
-minifier = "0.3.1"
+minifier = { version = "0.3.2", default-features = false }
 pulldown-cmark-old = { version = "0.9.6", package = "pulldown-cmark", default-features = false }
 regex = "1"
 rustdoc-json-types = { path = "../rustdoc-json-types" }
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 97529e420e3..5ddd6188c2d 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -134,11 +134,7 @@ pub(crate) fn try_inline(
             })
         }
         Res::Def(DefKind::Macro(kind), did) => {
-            let is_doc_hidden = cx.tcx.is_doc_hidden(did)
-                || attrs_without_docs
-                    .map(|(attrs, _)| attrs)
-                    .is_some_and(|attrs| utils::attrs_have_doc_flag(attrs.iter(), sym::hidden));
-            let mac = build_macro(cx, did, name, import_def_id, kind, is_doc_hidden);
+            let mac = build_macro(cx, did, name, kind);
 
             let type_kind = match kind {
                 MacroKind::Bang => ItemType::Macro,
@@ -740,18 +736,14 @@ fn build_macro(
     cx: &mut DocContext<'_>,
     def_id: DefId,
     name: Symbol,
-    import_def_id: Option<LocalDefId>,
     macro_kind: MacroKind,
-    is_doc_hidden: bool,
 ) -> clean::ItemKind {
     match CStore::from_tcx(cx.tcx).load_macro_untracked(def_id, cx.tcx) {
         LoadedMacro::MacroDef { def, .. } => match macro_kind {
-            MacroKind::Bang => {
-                let vis = cx.tcx.visibility(import_def_id.map(|d| d.to_def_id()).unwrap_or(def_id));
-                clean::MacroItem(clean::Macro {
-                    source: utils::display_macro_source(cx, name, &def, def_id, vis, is_doc_hidden),
-                })
-            }
+            MacroKind::Bang => clean::MacroItem(clean::Macro {
+                source: utils::display_macro_source(cx, name, &def),
+                macro_rules: def.macro_rules,
+            }),
             MacroKind::Derive | MacroKind::Attr => {
                 clean::ProcMacroItem(clean::ProcMacro { kind: macro_kind, helpers: Vec::new() })
             }
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 6b6142a6eaa..9e11360cab4 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -2119,7 +2119,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 })
                 .collect::<Vec<_>>();
 
-            let bindings = obj
+            let constraints = obj
                 .projection_bounds()
                 .map(|pb| AssocItemConstraint {
                     assoc: projection_to_path_segment(
@@ -2155,7 +2155,7 @@ pub(crate) fn clean_middle_ty<'tcx>(
                 .collect();
             let late_bound_regions = late_bound_regions.into_iter().collect();
 
-            let path = clean_middle_path(cx, did, false, bindings, args);
+            let path = clean_middle_path(cx, did, false, constraints, args);
             bounds.insert(0, PolyTrait { trait_: path, generic_params: late_bound_regions });
 
             DynTrait(bounds, lifetime)
@@ -2787,13 +2787,10 @@ fn clean_maybe_renamed_item<'tcx>(
                 fields: variant_data.fields().iter().map(|x| clean_field(x, cx)).collect(),
             }),
             ItemKind::Impl(impl_) => return clean_impl(impl_, item.owner_id.def_id, cx),
-            ItemKind::Macro(macro_def, MacroKind::Bang) => {
-                let ty_vis = cx.tcx.visibility(def_id);
-                MacroItem(Macro {
-                    // FIXME this shouldn't be false
-                    source: display_macro_source(cx, name, macro_def, def_id, ty_vis, false),
-                })
-            }
+            ItemKind::Macro(macro_def, MacroKind::Bang) => MacroItem(Macro {
+                source: display_macro_source(cx, name, macro_def),
+                macro_rules: macro_def.macro_rules,
+            }),
             ItemKind::Macro(_, macro_kind) => clean_proc_macro(item, &mut name, macro_kind, cx),
             // proc macros can have a name set by attributes
             ItemKind::Fn(ref sig, generics, body_id) => {
diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs
index e5c9539b5e7..e3a0dbe1a7f 100644
--- a/src/librustdoc/clean/types.rs
+++ b/src/librustdoc/clean/types.rs
@@ -2543,6 +2543,8 @@ pub(crate) struct ImportSource {
 #[derive(Clone, Debug)]
 pub(crate) struct Macro {
     pub(crate) source: String,
+    /// Whether the macro was defined via `macro_rules!` as opposed to `macro`.
+    pub(crate) macro_rules: bool,
 }
 
 #[derive(Clone, Debug)]
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 560831197f0..e551e0170c6 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -24,7 +24,6 @@ use crate::clean::{
     clean_middle_ty, inline,
 };
 use crate::core::DocContext;
-use crate::html::format::visibility_to_src_with_space;
 
 #[cfg(test)]
 mod tests;
@@ -112,7 +111,6 @@ pub(crate) fn clean_middle_generic_args<'tcx>(
             return None;
         }
 
-        // Elide internal host effect args.
         let param = generics.param_at(index, cx.tcx);
         let arg = ty::Binder::bind_with_vars(arg, bound_vars);
 
@@ -201,35 +199,30 @@ fn clean_middle_generic_args_with_constraints<'tcx>(
     cx: &mut DocContext<'tcx>,
     did: DefId,
     has_self: bool,
-    constraints: ThinVec<AssocItemConstraint>,
-    ty_args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
+    mut constraints: ThinVec<AssocItemConstraint>,
+    args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
 ) -> GenericArgs {
-    let args = clean_middle_generic_args(cx, ty_args.map_bound(|args| &args[..]), has_self, did);
-
-    if cx.tcx.is_trait(did) && cx.tcx.trait_def(did).paren_sugar {
-        let ty = ty_args
+    if cx.tcx.is_trait(did)
+        && cx.tcx.trait_def(did).paren_sugar
+        && let ty::Tuple(tys) = args.skip_binder().type_at(has_self as usize).kind()
+    {
+        let inputs = tys
             .iter()
-            .nth(if has_self { 1 } else { 0 })
-            .unwrap()
-            .map_bound(|arg| arg.expect_ty());
-        let inputs =
-            // The trait's first substitution is the one after self, if there is one.
-            match ty.skip_binder().kind() {
-                ty::Tuple(tys) => tys.iter().map(|t| clean_middle_ty(ty.rebind(t), cx, None, None)).collect::<Vec<_>>().into(),
-                _ => return GenericArgs::AngleBracketed { args: args.into(), constraints },
-            };
-        let output = constraints.into_iter().next().and_then(|binding| match binding.kind {
-            AssocItemConstraintKind::Equality { term: Term::Type(ty) }
-                if ty != Type::Tuple(Vec::new()) =>
-            {
+            .map(|ty| clean_middle_ty(args.rebind(ty), cx, None, None))
+            .collect::<Vec<_>>()
+            .into();
+        let output = constraints.pop().and_then(|constraint| match constraint.kind {
+            AssocItemConstraintKind::Equality { term: Term::Type(ty) } if !ty.is_unit() => {
                 Some(Box::new(ty))
             }
             _ => None,
         });
-        GenericArgs::Parenthesized { inputs, output }
-    } else {
-        GenericArgs::AngleBracketed { args: args.into(), constraints }
+        return GenericArgs::Parenthesized { inputs, output };
     }
+
+    let args = clean_middle_generic_args(cx, args.map_bound(|args| &args[..]), has_self, did);
+
+    GenericArgs::AngleBracketed { args: args.into(), constraints }
 }
 
 pub(super) fn clean_middle_path<'tcx>(
@@ -599,7 +592,7 @@ pub(crate) static DOC_CHANNEL: Lazy<&'static str> =
 
 /// Render a sequence of macro arms in a format suitable for displaying to the user
 /// as part of an item declaration.
-pub(super) fn render_macro_arms<'a>(
+fn render_macro_arms<'a>(
     tcx: TyCtxt<'_>,
     matchers: impl Iterator<Item = &'a TokenTree>,
     arm_delim: &str,
@@ -620,9 +613,6 @@ pub(super) fn display_macro_source(
     cx: &mut DocContext<'_>,
     name: Symbol,
     def: &ast::MacroDef,
-    def_id: DefId,
-    vis: ty::Visibility<DefId>,
-    is_doc_hidden: bool,
 ) -> String {
     // Extract the spans of all matchers. They represent the "interface" of the macro.
     let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
@@ -632,18 +622,13 @@ pub(super) fn display_macro_source(
     } else {
         if matchers.len() <= 1 {
             format!(
-                "{vis}macro {name}{matchers} {{\n    ...\n}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
+                "macro {name}{matchers} {{\n    ...\n}}",
                 matchers = matchers
                     .map(|matcher| render_macro_matcher(cx.tcx, matcher))
                     .collect::<String>(),
             )
         } else {
-            format!(
-                "{vis}macro {name} {{\n{arms}}}",
-                vis = visibility_to_src_with_space(Some(vis), cx.tcx, def_id, is_doc_hidden),
-                arms = render_macro_arms(cx.tcx, matchers, ","),
-            )
+            format!("macro {name} {{\n{arms}}}", arms = render_macro_arms(cx.tcx, matchers, ","))
         }
     }
 }
diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs
index 7ba3cfb66bd..d5f6bfe415d 100644
--- a/src/librustdoc/core.rs
+++ b/src/librustdoc/core.rs
@@ -6,7 +6,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
 use rustc_data_structures::sync::Lrc;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::emitter::{DynEmitter, HumanEmitter, stderr_destination};
+use rustc_errors::emitter::{
+    DynEmitter, HumanEmitter, HumanReadableErrorType, OutputTheme, stderr_destination,
+};
 use rustc_errors::json::JsonEmitter;
 use rustc_errors::{ErrorGuaranteed, TerminalUrl};
 use rustc_feature::UnstableFeatures;
@@ -154,6 +156,11 @@ pub(crate) fn new_dcx(
                     .teach(unstable_opts.teach)
                     .diagnostic_width(diagnostic_width)
                     .track_diagnostics(unstable_opts.track_diagnostics)
+                    .theme(if let HumanReadableErrorType::Unicode = kind {
+                        OutputTheme::Unicode
+                    } else {
+                        OutputTheme::Ascii
+                    })
                     .ui_testing(unstable_opts.ui_testing),
             )
         }
diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs
index 11d8f1947d6..25e576e9e63 100644
--- a/src/librustdoc/doctest.rs
+++ b/src/librustdoc/doctest.rs
@@ -15,6 +15,7 @@ pub(crate) use make::DocTestBuilder;
 pub(crate) use markdown::test as test_markdown;
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
+use rustc_errors::emitter::HumanReadableErrorType;
 use rustc_errors::{ColorConfig, DiagCtxtHandle, ErrorGuaranteed, FatalError};
 use rustc_hir::CRATE_HIR_ID;
 use rustc_hir::def_id::LOCAL_CRATE;
@@ -520,10 +521,14 @@ fn run_test(
     });
     if let ErrorOutputType::HumanReadable(kind, color_config) = rustdoc_options.error_format {
         let short = kind.short();
+        let unicode = kind == HumanReadableErrorType::Unicode;
 
         if short {
             compiler.arg("--error-format").arg("short");
         }
+        if unicode {
+            compiler.arg("--error-format").arg("human-unicode");
+        }
 
         match color_config {
             ColorConfig::Never => {
diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs
index e9d5ba2ea57..2f9e7976ca1 100644
--- a/src/librustdoc/html/format.rs
+++ b/src/librustdoc/html/format.rs
@@ -1615,47 +1615,6 @@ pub(crate) fn visibility_print_with_space<'a, 'tcx: 'a>(
     })
 }
 
-/// This function is the same as print_with_space, except that it renders no links.
-/// It's used for macros' rendered source view, which is syntax highlighted and cannot have
-/// any HTML in it.
-pub(crate) fn visibility_to_src_with_space<'a, 'tcx: 'a>(
-    visibility: Option<ty::Visibility<DefId>>,
-    tcx: TyCtxt<'tcx>,
-    item_did: DefId,
-    is_doc_hidden: bool,
-) -> impl Display + 'a + Captures<'tcx> {
-    let vis: Cow<'static, str> = match visibility {
-        None => "".into(),
-        Some(ty::Visibility::Public) => "pub ".into(),
-        Some(ty::Visibility::Restricted(vis_did)) => {
-            // FIXME(camelid): This may not work correctly if `item_did` is a module.
-            //                 However, rustdoc currently never displays a module's
-            //                 visibility, so it shouldn't matter.
-            let parent_module = find_nearest_parent_module(tcx, item_did);
-
-            if vis_did.is_crate_root() {
-                "pub(crate) ".into()
-            } else if parent_module == Some(vis_did) {
-                // `pub(in foo)` where `foo` is the parent module
-                // is the same as no visibility modifier
-                "".into()
-            } else if parent_module.and_then(|parent| find_nearest_parent_module(tcx, parent))
-                == Some(vis_did)
-            {
-                "pub(super) ".into()
-            } else {
-                format!("pub(in {}) ", tcx.def_path_str(vis_did)).into()
-            }
-        }
-    };
-    display_fn(move |f| {
-        if is_doc_hidden {
-            f.write_str("#[doc(hidden)] ")?;
-        }
-        f.write_str(&vis)
-    })
-}
-
 pub(crate) trait PrintWithSpace {
     fn print_with_space(&self) -> &str;
 }
diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs
index b68b7295096..4def80764ea 100644
--- a/src/librustdoc/html/highlight.rs
+++ b/src/librustdoc/html/highlight.rs
@@ -58,13 +58,6 @@ pub(crate) fn render_example_with_highlighting(
     write_footer(out, playground_button);
 }
 
-/// Highlights `src` as an item-decl, returning the HTML output.
-pub(crate) fn render_item_decl_with_highlighting(src: &str, out: &mut Buffer) {
-    write!(out, "<pre class=\"rust item-decl\">");
-    write_code(out, src, None, None);
-    write!(out, "</pre>");
-}
-
 fn write_header(
     out: &mut Buffer,
     class: &str,
diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs
index 7826a5d8394..1d42ec8eec7 100644
--- a/src/librustdoc/html/markdown.rs
+++ b/src/librustdoc/html/markdown.rs
@@ -1333,12 +1333,14 @@ impl Markdown<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, ids, heading_offset);
-        let p = footnotes::Footnotes::new(p);
-        let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
-        let p = TableWrapper::new(p);
-        let p = CodeBlocks::new(p, codes, edition, playground);
-        html::push_html(&mut s, p);
+        ids.handle_footnotes(|ids, existing_footnotes| {
+            let p = HeadingLinks::new(p, None, ids, heading_offset);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
+            let p = LinkReplacer::new(p.map(|(ev, _)| ev), links);
+            let p = TableWrapper::new(p);
+            let p = CodeBlocks::new(p, codes, edition, playground);
+            html::push_html(&mut s, p);
+        });
 
         s
     }
@@ -1367,13 +1369,13 @@ impl MarkdownWithToc<'_> {
 
         let mut toc = TocBuilder::new();
 
-        {
+        ids.handle_footnotes(|ids, existing_footnotes| {
             let p = HeadingLinks::new(p, Some(&mut toc), ids, HeadingOffset::H1);
-            let p = footnotes::Footnotes::new(p);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
             let p = TableWrapper::new(p.map(|(ev, _)| ev));
             let p = CodeBlocks::new(p, codes, edition, playground);
             html::push_html(&mut s, p);
-        }
+        });
 
         (toc.into_toc(), s)
     }
@@ -1401,13 +1403,15 @@ impl MarkdownItemInfo<'_> {
 
         let mut s = String::with_capacity(md.len() * 3 / 2);
 
-        let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
-        let p = footnotes::Footnotes::new(p);
-        let p = TableWrapper::new(p.map(|(ev, _)| ev));
-        let p = p.filter(|event| {
-            !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
+        ids.handle_footnotes(|ids, existing_footnotes| {
+            let p = HeadingLinks::new(p, None, ids, HeadingOffset::H1);
+            let p = footnotes::Footnotes::new(p, existing_footnotes);
+            let p = TableWrapper::new(p.map(|(ev, _)| ev));
+            let p = p.filter(|event| {
+                !matches!(event, Event::Start(Tag::Paragraph) | Event::End(TagEnd::Paragraph))
+            });
+            html::push_html(&mut s, p);
         });
-        html::push_html(&mut s, p);
 
         s
     }
@@ -1882,6 +1886,7 @@ pub(crate) fn rust_code_blocks(md: &str, extra_info: &ExtraInfo<'_>) -> Vec<Rust
 #[derive(Clone, Default, Debug)]
 pub struct IdMap {
     map: FxHashMap<Cow<'static, str>, usize>,
+    existing_footnotes: usize,
 }
 
 // The map is pre-initialized and cloned each time to avoid reinitializing it repeatedly.
@@ -1943,7 +1948,7 @@ fn init_id_map() -> FxHashMap<Cow<'static, str>, usize> {
 
 impl IdMap {
     pub fn new() -> Self {
-        IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone() }
+        IdMap { map: DEFAULT_ID_MAP.get_or_init(init_id_map).clone(), existing_footnotes: 0 }
     }
 
     pub(crate) fn derive<S: AsRef<str> + ToString>(&mut self, candidate: S) -> String {
@@ -1959,4 +1964,13 @@ impl IdMap {
         self.map.insert(id.clone().into(), 1);
         id
     }
+
+    /// Method to handle `existing_footnotes` increment automatically (to prevent forgetting
+    /// about it).
+    pub(crate) fn handle_footnotes<F: FnOnce(&mut Self, &mut usize)>(&mut self, closure: F) {
+        let mut existing_footnotes = self.existing_footnotes;
+
+        closure(self, &mut existing_footnotes);
+        self.existing_footnotes = existing_footnotes;
+    }
 }
diff --git a/src/librustdoc/html/markdown/footnotes.rs b/src/librustdoc/html/markdown/footnotes.rs
index 3f0e586b8e3..fcb8a174a95 100644
--- a/src/librustdoc/html/markdown/footnotes.rs
+++ b/src/librustdoc/html/markdown/footnotes.rs
@@ -1,60 +1,83 @@
 //! Markdown footnote handling.
 use std::fmt::Write as _;
 
-use pulldown_cmark::{Event, Tag, TagEnd, html};
+use pulldown_cmark::{CowStr, Event, Tag, TagEnd, html};
 use rustc_data_structures::fx::FxIndexMap;
 
 use super::SpannedEvent;
 
 /// Moves all footnote definitions to the end and add back links to the
 /// references.
-pub(super) struct Footnotes<'a, I> {
+pub(super) struct Footnotes<'a, 'b, I> {
     inner: I,
     footnotes: FxIndexMap<String, FootnoteDef<'a>>,
+    existing_footnotes: &'b mut usize,
 }
 
 /// The definition of a single footnote.
 struct FootnoteDef<'a> {
     content: Vec<Event<'a>>,
     /// The number that appears in the footnote reference and list.
-    id: u16,
+    id: usize,
 }
 
-impl<'a, I> Footnotes<'a, I> {
-    pub(super) fn new(iter: I) -> Self {
-        Footnotes { inner: iter, footnotes: FxIndexMap::default() }
+impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Footnotes<'a, 'b, I> {
+    pub(super) fn new(iter: I, existing_footnotes: &'b mut usize) -> Self {
+        Footnotes { inner: iter, footnotes: FxIndexMap::default(), existing_footnotes }
     }
 
-    fn get_entry(&mut self, key: &str) -> (&mut Vec<Event<'a>>, u16) {
-        let new_id = self.footnotes.len() + 1;
+    fn get_entry(&mut self, key: &str) -> (&mut Vec<Event<'a>>, usize) {
+        let new_id = self.footnotes.len() + 1 + *self.existing_footnotes;
         let key = key.to_owned();
-        let FootnoteDef { content, id } = self
-            .footnotes
-            .entry(key)
-            .or_insert(FootnoteDef { content: Vec::new(), id: new_id as u16 });
+        let FootnoteDef { content, id } =
+            self.footnotes.entry(key).or_insert(FootnoteDef { content: Vec::new(), id: new_id });
         // Don't allow changing the ID of existing entrys, but allow changing the contents.
         (content, *id)
     }
+
+    fn handle_footnote_reference(&mut self, reference: &CowStr<'a>) -> Event<'a> {
+        // When we see a reference (to a footnote we may not know) the definition of,
+        // reserve a number for it, and emit a link to that number.
+        let (_, id) = self.get_entry(reference);
+        let reference = format!(
+            "<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{1}</a></sup>",
+            id,
+            // Although the ID count is for the whole page, the footnote reference
+            // are local to the item so we make this ID "local" when displayed.
+            id - *self.existing_footnotes
+        );
+        Event::Html(reference.into())
+    }
+
+    fn collect_footnote_def(&mut self) -> Vec<Event<'a>> {
+        let mut content = Vec::new();
+        while let Some((event, _)) = self.inner.next() {
+            match event {
+                Event::End(TagEnd::FootnoteDefinition) => break,
+                Event::FootnoteReference(ref reference) => {
+                    content.push(self.handle_footnote_reference(reference));
+                }
+                event => content.push(event),
+            }
+        }
+        content
+    }
 }
 
-impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
+impl<'a, 'b, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, 'b, I> {
     type Item = SpannedEvent<'a>;
 
     fn next(&mut self) -> Option<Self::Item> {
         loop {
-            match self.inner.next() {
+            let next = self.inner.next();
+            match next {
                 Some((Event::FootnoteReference(ref reference), range)) => {
-                    // When we see a reference (to a footnote we may not know) the definition of,
-                    // reserve a number for it, and emit a link to that number.
-                    let (_, id) = self.get_entry(reference);
-                    let reference =
-                        format!("<sup id=\"fnref{0}\"><a href=\"#fn{0}\">{0}</a></sup>", id);
-                    return Some((Event::Html(reference.into()), range));
+                    return Some((self.handle_footnote_reference(reference), range));
                 }
                 Some((Event::Start(Tag::FootnoteDefinition(def)), _)) => {
                     // When we see a footnote definition, collect the assocated content, and store
                     // that for rendering later.
-                    let content = collect_footnote_def(&mut self.inner);
+                    let content = self.collect_footnote_def();
                     let (entry_content, _) = self.get_entry(&def);
                     *entry_content = content;
                 }
@@ -64,6 +87,7 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
                         // After all the markdown is emmited, emit an <hr> then all the footnotes
                         // in a list.
                         let defs: Vec<_> = self.footnotes.drain(..).map(|(_, x)| x).collect();
+                        *self.existing_footnotes += defs.len();
                         let defs_html = render_footnotes_defs(defs);
                         return Some((Event::Html(defs_html.into()), 0..0));
                     } else {
@@ -75,17 +99,6 @@ impl<'a, I: Iterator<Item = SpannedEvent<'a>>> Iterator for Footnotes<'a, I> {
     }
 }
 
-fn collect_footnote_def<'a>(events: impl Iterator<Item = SpannedEvent<'a>>) -> Vec<Event<'a>> {
-    let mut content = Vec::new();
-    for (event, _) in events {
-        if let Event::End(TagEnd::FootnoteDefinition) = event {
-            break;
-        }
-        content.push(event);
-    }
-    content
-}
-
 fn render_footnotes_defs(mut footnotes: Vec<FootnoteDef<'_>>) -> String {
     let mut ret = String::from("<div class=\"footnotes\"><hr><ol>");
 
diff --git a/src/librustdoc/html/render/context.rs b/src/librustdoc/html/render/context.rs
index dc4d45e592e..5f255c18ec6 100644
--- a/src/librustdoc/html/render/context.rs
+++ b/src/librustdoc/html/render/context.rs
@@ -76,9 +76,9 @@ pub(crate) struct Context<'tcx> {
 
 // `Context` is cloned a lot, so we don't want the size to grow unexpectedly.
 #[cfg(all(not(windows), target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Context<'_>, 184);
-#[cfg(all(windows, target_pointer_width = "64"))]
 rustc_data_structures::static_assert_size!(Context<'_>, 192);
+#[cfg(all(windows, target_pointer_width = "64"))]
+rustc_data_structures::static_assert_size!(Context<'_>, 200);
 
 /// Shared mutable state used in [`Context`] and elsewhere.
 pub(crate) struct SharedContext<'tcx> {
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index 8446235fb18..f11356b44d8 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -204,6 +204,7 @@ pub(crate) struct IndexItemFunctionType {
     inputs: Vec<RenderType>,
     output: Vec<RenderType>,
     where_clause: Vec<Vec<RenderType>>,
+    param_names: Vec<Symbol>,
 }
 
 impl IndexItemFunctionType {
@@ -1010,9 +1011,7 @@ fn render_stability_since_raw_with_extra(
                 // don't display const unstable if entirely unstable
                 None
             } else {
-                let unstable = if let Some(n) = issue
-                    && let Some(feature) = feature
-                {
+                let unstable = if let Some(n) = issue {
                     format!(
                         "<a \
                         href=\"https://github.com/rust-lang/rust/issues/{n}\" \
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index c6a2d87cbd0..d247e90d298 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -35,7 +35,6 @@ use crate::html::format::{
     Buffer, Ending, PrintWithSpace, display_fn, join_with_double_colon, print_abi_with_space,
     print_constness_with_space, print_where_clause, visibility_print_with_space,
 };
-use crate::html::highlight;
 use crate::html::markdown::{HeadingOffset, MarkdownSummaryLine};
 use crate::html::render::{document_full, document_item_info};
 use crate::html::url_parts_builder::UrlPartsBuilder;
@@ -1745,7 +1744,13 @@ fn item_variants(
 }
 
 fn item_macro(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean::Macro) {
-    highlight::render_item_decl_with_highlighting(&t.source, w);
+    wrap_item(w, |w| {
+        // FIXME: Also print `#[doc(hidden)]` for `macro_rules!` if it `is_doc_hidden`.
+        if !t.macro_rules {
+            write!(w, "{}", visibility_print_with_space(it, cx));
+        }
+        write!(w, "{}", Escape(&t.source));
+    });
     write!(w, "{}", document(cx, it, None, HeadingOffset::H2))
 }
 
diff --git a/src/librustdoc/html/render/search_index.rs b/src/librustdoc/html/render/search_index.rs
index d1939adc1a5..f91fdfa1fb5 100644
--- a/src/librustdoc/html/render/search_index.rs
+++ b/src/librustdoc/html/render/search_index.rs
@@ -13,8 +13,8 @@ use serde::ser::{Serialize, SerializeSeq, SerializeStruct, Serializer};
 use thin_vec::ThinVec;
 use tracing::instrument;
 
-use crate::clean;
 use crate::clean::types::{Function, Generics, ItemId, Type, WherePredicate};
+use crate::clean::{self, utils};
 use crate::formats::cache::{Cache, OrphanImplItem};
 use crate::formats::item_type::ItemType;
 use crate::html::format::join_with_double_colon;
@@ -66,7 +66,7 @@ pub(crate) fn build_index<'tcx>(
     let mut associated_types = FxHashMap::default();
 
     // item type, display path, re-exported internal path
-    let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)> = vec![];
+    let mut crate_paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)> = vec![];
 
     // Attach all orphan items to the type's definition if the type
     // has since been learned.
@@ -132,10 +132,11 @@ pub(crate) fn build_index<'tcx>(
             map: &mut FxHashMap<F, isize>,
             itemid: F,
             lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
+            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
             item_type: ItemType,
             path: &[Symbol],
             exact_path: Option<&[Symbol]>,
+            search_unbox: bool,
         ) -> RenderTypeId {
             match map.entry(itemid) {
                 Entry::Occupied(entry) => RenderTypeId::Index(*entry.get()),
@@ -147,6 +148,7 @@ pub(crate) fn build_index<'tcx>(
                         item_type,
                         path.to_vec(),
                         exact_path.map(|path| path.to_vec()),
+                        search_unbox,
                     ));
                     RenderTypeId::Index(pathid)
                 }
@@ -160,9 +162,21 @@ pub(crate) fn build_index<'tcx>(
             primitives: &mut FxHashMap<Symbol, isize>,
             associated_types: &mut FxHashMap<Symbol, isize>,
             lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
+            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
+            tcx: TyCtxt<'_>,
         ) -> Option<RenderTypeId> {
+            use crate::clean::PrimitiveType;
             let Cache { ref paths, ref external_paths, ref exact_paths, .. } = *cache;
+            let search_unbox = match id {
+                RenderTypeId::Mut => false,
+                RenderTypeId::DefId(defid) => utils::has_doc_flag(tcx, defid, sym::search_unbox),
+                RenderTypeId::Primitive(PrimitiveType::Reference | PrimitiveType::Tuple) => true,
+                RenderTypeId::Primitive(..) => false,
+                RenderTypeId::AssociatedType(..) => false,
+                // this bool is only used by `insert_into_map`, so it doesn't matter what we set here
+                // because Index means we've already inserted into the map
+                RenderTypeId::Index(_) => false,
+            };
             match id {
                 RenderTypeId::Mut => Some(insert_into_map(
                     primitives,
@@ -172,6 +186,7 @@ pub(crate) fn build_index<'tcx>(
                     ItemType::Keyword,
                     &[kw::Mut],
                     None,
+                    search_unbox,
                 )),
                 RenderTypeId::DefId(defid) => {
                     if let Some(&(ref fqp, item_type)) =
@@ -195,6 +210,7 @@ pub(crate) fn build_index<'tcx>(
                             item_type,
                             fqp,
                             exact_fqp.map(|x| &x[..]).filter(|exact_fqp| exact_fqp != fqp),
+                            search_unbox,
                         ))
                     } else {
                         None
@@ -210,6 +226,7 @@ pub(crate) fn build_index<'tcx>(
                         ItemType::Primitive,
                         &[sym],
                         None,
+                        search_unbox,
                     ))
                 }
                 RenderTypeId::Index(_) => Some(id),
@@ -221,6 +238,7 @@ pub(crate) fn build_index<'tcx>(
                     ItemType::AssocType,
                     &[sym],
                     None,
+                    search_unbox,
                 )),
             }
         }
@@ -232,7 +250,8 @@ pub(crate) fn build_index<'tcx>(
             primitives: &mut FxHashMap<Symbol, isize>,
             associated_types: &mut FxHashMap<Symbol, isize>,
             lastpathid: &mut isize,
-            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
+            crate_paths: &mut Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
+            tcx: TyCtxt<'_>,
         ) {
             if let Some(generics) = &mut ty.generics {
                 for item in generics {
@@ -244,6 +263,7 @@ pub(crate) fn build_index<'tcx>(
                         associated_types,
                         lastpathid,
                         crate_paths,
+                        tcx,
                     );
                 }
             }
@@ -257,6 +277,7 @@ pub(crate) fn build_index<'tcx>(
                         associated_types,
                         lastpathid,
                         crate_paths,
+                        tcx,
                     );
                     let Some(converted_associated_type) = converted_associated_type else {
                         return false;
@@ -271,6 +292,7 @@ pub(crate) fn build_index<'tcx>(
                             associated_types,
                             lastpathid,
                             crate_paths,
+                            tcx,
                         );
                     }
                     true
@@ -288,6 +310,7 @@ pub(crate) fn build_index<'tcx>(
                 associated_types,
                 lastpathid,
                 crate_paths,
+                tcx,
             );
         }
         if let Some(search_type) = &mut item.search_type {
@@ -300,6 +323,7 @@ pub(crate) fn build_index<'tcx>(
                     &mut associated_types,
                     &mut lastpathid,
                     &mut crate_paths,
+                    tcx,
                 );
             }
             for item in &mut search_type.output {
@@ -311,6 +335,7 @@ pub(crate) fn build_index<'tcx>(
                     &mut associated_types,
                     &mut lastpathid,
                     &mut crate_paths,
+                    tcx,
                 );
             }
             for constraint in &mut search_type.where_clause {
@@ -323,6 +348,7 @@ pub(crate) fn build_index<'tcx>(
                         &mut associated_types,
                         &mut lastpathid,
                         &mut crate_paths,
+                        tcx,
                     );
                 }
             }
@@ -350,7 +376,12 @@ pub(crate) fn build_index<'tcx>(
                                 .filter(|exact_fqp| {
                                     exact_fqp.last() == Some(&item.name) && *exact_fqp != fqp
                                 });
-                            crate_paths.push((short, fqp.clone(), exact_fqp.cloned()));
+                            crate_paths.push((
+                                short,
+                                fqp.clone(),
+                                exact_fqp.cloned(),
+                                utils::has_doc_flag(tcx, defid, sym::search_unbox),
+                            ));
                             Some(pathid)
                         } else {
                             None
@@ -431,7 +462,7 @@ pub(crate) fn build_index<'tcx>(
 
     struct CrateData<'a> {
         items: Vec<&'a IndexItem>,
-        paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>)>,
+        paths: Vec<(ItemType, Vec<Symbol>, Option<Vec<Symbol>>, bool)>,
         // The String is alias name and the vec is the list of the elements with this alias.
         //
         // To be noted: the `usize` elements are indexes to `items`.
@@ -450,6 +481,7 @@ pub(crate) fn build_index<'tcx>(
         name: Symbol,
         path: Option<usize>,
         exact_path: Option<usize>,
+        search_unbox: bool,
     }
 
     impl Serialize for Paths {
@@ -467,6 +499,15 @@ pub(crate) fn build_index<'tcx>(
                 assert!(self.path.is_some());
                 seq.serialize_element(path)?;
             }
+            if self.search_unbox {
+                if self.path.is_none() {
+                    seq.serialize_element(&None::<u8>)?;
+                }
+                if self.exact_path.is_none() {
+                    seq.serialize_element(&None::<u8>)?;
+                }
+                seq.serialize_element(&1)?;
+            }
             seq.end()
         }
     }
@@ -489,9 +530,15 @@ pub(crate) fn build_index<'tcx>(
                 mod_paths.insert(&item.path, index);
             }
             let mut paths = Vec::with_capacity(self.paths.len());
-            for (ty, path, exact) in &self.paths {
+            for &(ty, ref path, ref exact, search_unbox) in &self.paths {
                 if path.len() < 2 {
-                    paths.push(Paths { ty: *ty, name: path[0], path: None, exact_path: None });
+                    paths.push(Paths {
+                        ty,
+                        name: path[0],
+                        path: None,
+                        exact_path: None,
+                        search_unbox,
+                    });
                     continue;
                 }
                 let full_path = join_with_double_colon(&path[..path.len() - 1]);
@@ -517,10 +564,11 @@ pub(crate) fn build_index<'tcx>(
                 });
                 if let Some(index) = mod_paths.get(&full_path) {
                     paths.push(Paths {
-                        ty: *ty,
+                        ty,
                         name: *path.last().unwrap(),
                         path: Some(*index),
                         exact_path,
+                        search_unbox,
                     });
                     continue;
                 }
@@ -532,10 +580,11 @@ pub(crate) fn build_index<'tcx>(
                 match extra_paths.entry(full_path.clone()) {
                     Entry::Occupied(entry) => {
                         paths.push(Paths {
-                            ty: *ty,
+                            ty,
                             name: *path.last().unwrap(),
                             path: Some(*entry.get()),
                             exact_path,
+                            search_unbox,
                         });
                     }
                     Entry::Vacant(entry) => {
@@ -544,10 +593,11 @@ pub(crate) fn build_index<'tcx>(
                             revert_extra_paths.insert(index, full_path);
                         }
                         paths.push(Paths {
-                            ty: *ty,
+                            ty,
                             name: *path.last().unwrap(),
                             path: Some(index),
                             exact_path,
+                            search_unbox,
                         });
                     }
                 }
@@ -646,9 +696,25 @@ pub(crate) fn build_index<'tcx>(
                 full_paths.push((*index, path));
             }
 
+            let param_names: Vec<(usize, String)> = {
+                let mut prev = Vec::new();
+                let mut result = Vec::new();
+                for (index, item) in self.items.iter().enumerate() {
+                    if let Some(ty) = &item.search_type
+                        && let my =
+                            ty.param_names.iter().map(|sym| sym.as_str()).collect::<Vec<_>>()
+                        && my != prev
+                    {
+                        result.push((index, my.join(",")));
+                        prev = my;
+                    }
+                }
+                result
+            };
+
             let has_aliases = !self.aliases.is_empty();
             let mut crate_data =
-                serializer.serialize_struct("CrateData", if has_aliases { 9 } else { 8 })?;
+                serializer.serialize_struct("CrateData", if has_aliases { 13 } else { 12 })?;
             crate_data.serialize_field("t", &types)?;
             crate_data.serialize_field("n", &names)?;
             crate_data.serialize_field("q", &full_paths)?;
@@ -660,6 +726,7 @@ pub(crate) fn build_index<'tcx>(
             crate_data.serialize_field("b", &self.associated_item_disambiguators)?;
             crate_data.serialize_field("c", &bitmap_to_string(&deprecated))?;
             crate_data.serialize_field("e", &bitmap_to_string(&self.empty_desc))?;
+            crate_data.serialize_field("P", &param_names)?;
             if has_aliases {
                 crate_data.serialize_field("a", &self.aliases)?;
             }
@@ -758,7 +825,7 @@ pub(crate) fn get_function_type_for_search<'tcx>(
             None
         }
     });
-    let (mut inputs, mut output, where_clause) = match item.kind {
+    let (mut inputs, mut output, param_names, where_clause) = match item.kind {
         clean::ForeignFunctionItem(ref f, _)
         | clean::FunctionItem(ref f)
         | clean::MethodItem(ref f, _)
@@ -771,7 +838,7 @@ pub(crate) fn get_function_type_for_search<'tcx>(
     inputs.retain(|a| a.id.is_some() || a.generics.is_some());
     output.retain(|a| a.id.is_some() || a.generics.is_some());
 
-    Some(IndexItemFunctionType { inputs, output, where_clause })
+    Some(IndexItemFunctionType { inputs, output, where_clause, param_names })
 }
 
 fn get_index_type(
@@ -1285,7 +1352,7 @@ fn get_fn_inputs_and_outputs<'tcx>(
     tcx: TyCtxt<'tcx>,
     impl_or_trait_generics: Option<&(clean::Type, clean::Generics)>,
     cache: &Cache,
-) -> (Vec<RenderType>, Vec<RenderType>, Vec<Vec<RenderType>>) {
+) -> (Vec<RenderType>, Vec<RenderType>, Vec<Symbol>, Vec<Vec<RenderType>>) {
     let decl = &func.decl;
 
     let mut rgen: FxIndexMap<SimplifiedParam, (isize, Vec<RenderType>)> = Default::default();
@@ -1331,7 +1398,21 @@ fn get_fn_inputs_and_outputs<'tcx>(
     let mut ret_types = Vec::new();
     simplify_fn_type(self_, generics, &decl.output, tcx, 0, &mut ret_types, &mut rgen, true, cache);
 
-    let mut simplified_params = rgen.into_values().collect::<Vec<_>>();
-    simplified_params.sort_by_key(|(idx, _)| -idx);
-    (arg_types, ret_types, simplified_params.into_iter().map(|(_idx, traits)| traits).collect())
+    let mut simplified_params = rgen.into_iter().collect::<Vec<_>>();
+    simplified_params.sort_by_key(|(_, (idx, _))| -idx);
+    (
+        arg_types,
+        ret_types,
+        simplified_params
+            .iter()
+            .map(|(name, (_idx, _traits))| match name {
+                SimplifiedParam::Symbol(name) => *name,
+                SimplifiedParam::Anonymous(_) => kw::Empty,
+                SimplifiedParam::AssociatedType(def_id, name) => {
+                    Symbol::intern(&format!("{}::{}", tcx.item_name(*def_id), name))
+                }
+            })
+            .collect(),
+        simplified_params.into_iter().map(|(_name, (_idx, traits))| traits).collect(),
+    )
 }
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 1042d254749..66a8a198928 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -264,6 +264,7 @@ a.anchor,
 .mobile-topbar h2 a,
 h1 a,
 .search-results a,
+.search-results li,
 .stab,
 .result-name i {
 	color: var(--main-color);
@@ -379,7 +380,7 @@ details:not(.toggle) summary {
 	margin-bottom: .6em;
 }
 
-code, pre, .code-header {
+code, pre, .code-header, .type-signature {
 	font-family: "Source Code Pro", monospace;
 }
 .docblock code, .docblock-short code {
@@ -1205,22 +1206,28 @@ so that we can apply CSS-filters to change the arrow color in themes */
 
 .search-results.active {
 	display: block;
+	margin: 0;
+	padding: 0;
 }
 
 .search-results > a {
-	display: flex;
+	display: grid;
+	grid-template-areas:
+		"search-result-name search-result-desc"
+		"search-result-type-signature search-result-type-signature";
+	grid-template-columns: .6fr .4fr;
 	/* A little margin ensures the browser's outlining of focused links has room to display. */
 	margin-left: 2px;
 	margin-right: 2px;
 	border-bottom: 1px solid var(--search-result-border-color);
-	gap: 1em;
+	column-gap: 1em;
 }
 
 .search-results > a > div.desc {
 	white-space: nowrap;
 	text-overflow: ellipsis;
 	overflow: hidden;
-	flex: 2;
+	grid-area: search-result-desc;
 }
 
 .search-results a:hover,
@@ -1232,7 +1239,7 @@ so that we can apply CSS-filters to change the arrow color in themes */
 	display: flex;
 	align-items: center;
 	justify-content: start;
-	flex: 3;
+	grid-area: search-result-name;
 }
 .search-results .result-name .alias {
 	color: var(--search-results-alias-color);
@@ -1253,6 +1260,10 @@ so that we can apply CSS-filters to change the arrow color in themes */
 .search-results .result-name .path > * {
 	display: inline;
 }
+.search-results .type-signature {
+	grid-area: search-result-type-signature;
+	white-space: pre-wrap;
+}
 
 .popover {
 	position: absolute;
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
index 3d3e0a8f838..c4faca1c0c3 100644
--- a/src/librustdoc/html/static/js/externs.js
+++ b/src/librustdoc/html/static/js/externs.js
@@ -9,12 +9,12 @@ function initSearch(searchIndex){}
 /**
  * @typedef {{
  *     name: string,
- *     id: integer|null,
+ *     id: number|null,
  *     fullPath: Array<string>,
  *     pathWithoutLast: Array<string>,
  *     pathLast: string,
  *     generics: Array<QueryElement>,
- *     bindings: Map<integer, Array<QueryElement>>,
+ *     bindings: Map<number, Array<QueryElement>>,
  * }}
  */
 let QueryElement;
@@ -92,6 +92,9 @@ let Results;
  *     parent: (Object|undefined),
  *     path: string,
  *     ty: number,
+ *     type: FunctionSearchType?,
+ *     displayType: Promise<Array<Array<string>>>|null,
+ *     displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
  * }}
  */
 let ResultObject;
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index eed64d024c0..6d118ae5784 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -15,7 +15,16 @@ if (!Array.prototype.toSpliced) {
     };
 }
 
-(function() {
+function onEachBtwn(arr, func, funcBtwn) {
+    let skipped = true;
+    for (const value of arr) {
+        if (!skipped) {
+            funcBtwn(value);
+        }
+        skipped = func(value);
+    }
+}
+
 // ==================== Core search logic begin ====================
 // This mapping table should match the discriminants of
 // `rustdoc::formats::item_type::ItemType` type in Rust.
@@ -50,8 +59,10 @@ const itemTypes = [
 ];
 
 // used for special search precedence
+const TY_PRIMITIVE = itemTypes.indexOf("primitive");
 const TY_GENERIC = itemTypes.indexOf("generic");
 const TY_IMPORT = itemTypes.indexOf("import");
+const TY_TRAIT = itemTypes.indexOf("trait");
 const ROOT_PATH = typeof window !== "undefined" ? window.rootPath : "../";
 
 // Hard limit on how deep to recurse into generics when doing type-driven search.
@@ -276,7 +287,7 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) {
         // The type filter doesn't count as an element since it's a modifier.
         const typeFilterElem = elems.pop();
         checkExtraTypeFilterCharacters(start, parserState);
-        parserState.typeFilter = typeFilterElem.name;
+        parserState.typeFilter = typeFilterElem.normalizedPathLast;
         parserState.pos += 1;
         parserState.totalElems -= 1;
         query.literalSearch = false;
@@ -686,7 +697,7 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
     } else if (quadcolon !== null) {
         throw ["Unexpected ", quadcolon[0]];
     }
-    const pathSegments = path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/);
+    const pathSegments = path.split(/(?:::\s*)|(?:\s+(?:::\s*)?)/).map(x => x.toLowerCase());
     // In case we only have something like `<p>`, there is no name.
     if (pathSegments.length === 0
         || (pathSegments.length === 1 && pathSegments[0] === "")) {
@@ -726,7 +737,10 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
                 if (gen.name !== null) {
                     gen.bindingName.generics.unshift(gen);
                 }
-                bindings.set(gen.bindingName.name, gen.bindingName.generics);
+                bindings.set(
+                    gen.bindingName.name.toLowerCase().replace(/_/g, ""),
+                    gen.bindingName.generics,
+                );
                 return false;
             }
             return true;
@@ -1092,6 +1106,153 @@ class RoaringBitmapBits {
     }
 }
 
+/**
+ * A prefix tree, used for name-based search.
+ *
+ * This data structure is used to drive prefix matches,
+ * such as matching the query "link" to `LinkedList`,
+ * and Lev-distance matches, such as matching the
+ * query "hahsmap" to `HashMap`. Substring matches,
+ * such as "list" to `LinkedList`, are done with a
+ * tailTable that deep-links into this trie.
+ *
+ * children
+ * : A [sparse array] of subtrees. The array index
+ *   is a charCode.
+ *
+ *   [sparse array]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/
+ *     Indexed_collections#sparse_arrays
+ *
+ * matches
+ * : A list of search index IDs for this node.
+ *
+ * @typedef {{
+ *     children: [NameTrie],
+ *     matches: [number],
+ * }}
+ */
+class NameTrie {
+    constructor() {
+        this.children = [];
+        this.matches = [];
+    }
+    insert(name, id, tailTable) {
+        this.insertSubstring(name, 0, id, tailTable);
+    }
+    insertSubstring(name, substart, id, tailTable) {
+        const l = name.length;
+        if (substart === l) {
+            this.matches.push(id);
+        } else {
+            const sb = name.charCodeAt(substart);
+            let child;
+            if (this.children[sb] !== undefined) {
+                child = this.children[sb];
+            } else {
+                child = new NameTrie();
+                this.children[sb] = child;
+                let sste;
+                if (substart >= 2) {
+                    const tail = name.substring(substart - 2, substart + 1);
+                    if (tailTable.has(tail)) {
+                        sste = tailTable.get(tail);
+                    } else {
+                        sste = [];
+                        tailTable.set(tail, sste);
+                    }
+                    sste.push(child);
+                }
+            }
+            child.insertSubstring(name, substart + 1, id, tailTable);
+        }
+    }
+    search(name, tailTable) {
+        const results = new Set();
+        this.searchSubstringPrefix(name, 0, results);
+        if (results.size < MAX_RESULTS && name.length >= 3) {
+            const levParams = name.length >= 6 ?
+                new Lev2TParametricDescription(name.length) :
+                new Lev1TParametricDescription(name.length);
+            this.searchLev(name, 0, levParams, results);
+            const tail = name.substring(0, 3);
+            if (tailTable.has(tail)) {
+                for (const entry of tailTable.get(tail)) {
+                    entry.searchSubstringPrefix(name, 3, results);
+                }
+            }
+        }
+        return [...results];
+    }
+    searchSubstringPrefix(name, substart, results) {
+        const l = name.length;
+        if (substart === l) {
+            for (const match of this.matches) {
+                results.add(match);
+            }
+            // breadth-first traversal orders prefix matches by length
+            let unprocessedChildren = [];
+            for (const child of this.children) {
+                if (child) {
+                    unprocessedChildren.push(child);
+                }
+            }
+            let nextSet = [];
+            while (unprocessedChildren.length !== 0) {
+                const next = unprocessedChildren.pop();
+                for (const child of next.children) {
+                    if (child) {
+                        nextSet.push(child);
+                    }
+                }
+                for (const match of next.matches) {
+                    results.add(match);
+                }
+                if (unprocessedChildren.length === 0) {
+                    const tmp = unprocessedChildren;
+                    unprocessedChildren = nextSet;
+                    nextSet = tmp;
+                }
+            }
+        } else {
+            const sb = name.charCodeAt(substart);
+            if (this.children[sb] !== undefined) {
+                this.children[sb].searchSubstringPrefix(name, substart + 1, results);
+            }
+        }
+    }
+    searchLev(name, substart, levParams, results) {
+        const stack = [[this, 0]];
+        const n = levParams.n;
+        while (stack.length !== 0) {
+            const [trie, levState] = stack.pop();
+            for (const [charCode, child] of trie.children.entries()) {
+                if (!child) {
+                    continue;
+                }
+                const levPos = levParams.getPosition(levState);
+                const vector = levParams.getVector(
+                    name,
+                    charCode,
+                    levPos,
+                    Math.min(name.length, levPos + (2 * n) + 1),
+                );
+                const newLevState = levParams.transition(
+                    levState,
+                    levPos,
+                    vector,
+                );
+                if (newLevState >= 0) {
+                    stack.push([child, newLevState]);
+                    if (levParams.isAccept(newLevState)) {
+                        for (const match of child.matches) {
+                            results.add(match);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
 
 class DocSearch {
     constructor(rawSearchIndex, rootPath, searchState) {
@@ -1114,6 +1275,13 @@ class DocSearch {
          * @type {Map<string, {id: integer, assocOnly: boolean}>}
          */
         this.typeNameIdMap = new Map();
+        /**
+         * Map from type ID to associated type name. Used for display,
+         * not for search.
+         *
+         * @type {Map<integer, string>}
+         */
+        this.assocTypeIdNameMap = new Map();
         this.ALIASES = new Map();
         this.rootPath = rootPath;
         this.searchState = searchState;
@@ -1158,6 +1326,14 @@ class DocSearch {
          * Special type name IDs for searching higher order functions (`->` syntax).
          */
         this.typeNameIdOfHof = this.buildTypeMapIndex("->");
+        /**
+         * Special type name IDs the output assoc type.
+         */
+        this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
+        /**
+         * Special type name IDs for searching by reference.
+         */
+        this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
 
         /**
          * Empty, immutable map used in item search types with no bindings.
@@ -1182,6 +1358,20 @@ class DocSearch {
         this.TYPES_POOL = new Map();
 
         /**
+         * A trie for finding items by name.
+         * This is used for edit distance and prefix finding.
+         *
+         * @type {NameTrie}
+         */
+        this.nameTrie = new NameTrie();
+
+        /**
+         * Find items by 3-substring. This is a map from three-char
+         * prefixes into lists of subtries.
+         */
+        this.tailTable = new Map();
+
+        /**
          *  @type {Array<Row>}
          */
         this.searchIndex = this.buildIndex(rawSearchIndex);
@@ -1234,9 +1424,9 @@ class DocSearch {
      *
      * @return {Array<FunctionSearchType>}
      */
-    buildItemSearchTypeAll(types, lowercasePaths) {
+    buildItemSearchTypeAll(types, paths, lowercasePaths) {
         return types.length > 0 ?
-            types.map(type => this.buildItemSearchType(type, lowercasePaths)) :
+            types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) :
             this.EMPTY_GENERICS_ARRAY;
     }
 
@@ -1245,7 +1435,7 @@ class DocSearch {
      *
      * @param {RawFunctionType} type
      */
-    buildItemSearchType(type, lowercasePaths, isAssocType) {
+    buildItemSearchType(type, paths, lowercasePaths, isAssocType) {
         const PATH_INDEX_DATA = 0;
         const GENERICS_DATA = 1;
         const BINDINGS_DATA = 2;
@@ -1258,6 +1448,7 @@ class DocSearch {
             pathIndex = type[PATH_INDEX_DATA];
             generics = this.buildItemSearchTypeAll(
                 type[GENERICS_DATA],
+                paths,
                 lowercasePaths,
             );
             if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
@@ -1274,8 +1465,8 @@ class DocSearch {
                     //
                     // As a result, the key should never have generics on it.
                     return [
-                        this.buildItemSearchType(assocType, lowercasePaths, true).id,
-                        this.buildItemSearchTypeAll(constraints, lowercasePaths),
+                        this.buildItemSearchType(assocType, paths, lowercasePaths, true).id,
+                        this.buildItemSearchTypeAll(constraints, paths, lowercasePaths),
                     ];
                 }));
             } else {
@@ -1291,31 +1482,41 @@ class DocSearch {
             // the actual names of generic parameters aren't stored, since they aren't API
             result = {
                 id: pathIndex,
+                name: "",
                 ty: TY_GENERIC,
                 path: null,
                 exactPath: null,
                 generics,
                 bindings,
+                unboxFlag: true,
             };
         } else if (pathIndex === 0) {
             // `0` is used as a sentinel because it's fewer bytes than `null`
             result = {
                 id: null,
+                name: "",
                 ty: null,
                 path: null,
                 exactPath: null,
                 generics,
                 bindings,
+                unboxFlag: true,
             };
         } else {
             const item = lowercasePaths[pathIndex - 1];
+            const id = this.buildTypeMapIndex(item.name, isAssocType);
+            if (isAssocType) {
+                this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
+            }
             result = {
-                id: this.buildTypeMapIndex(item.name, isAssocType),
+                id,
+                name: paths[pathIndex - 1].name,
                 ty: item.ty,
                 path: item.path,
                 exactPath: item.exactPath,
                 generics,
                 bindings,
+                unboxFlag: item.unboxFlag,
             };
         }
         const cr = this.TYPES_POOL.get(result.id);
@@ -1352,7 +1553,8 @@ class DocSearch {
             }
             if (cr.ty === result.ty && cr.path === result.path
                 && cr.bindings === result.bindings && cr.generics === result.generics
-                && cr.ty === result.ty
+                && cr.ty === result.ty && cr.name === result.name
+                && cr.unboxFlag === result.unboxFlag
             ) {
                 return cr;
             }
@@ -1371,7 +1573,7 @@ class DocSearch {
      *   query fingerprint. If any bits are set in the query but not in the function, it can't
      *   match.
      *
-     * - The fourth section has the number of distinct items in the set.
+     * - The fourth section has the number of items in the set.
      *   This is the distance function, used for filtering and for sorting.
      *
      * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
@@ -1379,9 +1581,8 @@ class DocSearch {
      *
      * @param {FunctionType|QueryElement} type - a single type
      * @param {Uint32Array} output - write the fingerprint to this data structure: uses 128 bits
-     * @param {Set<number>} fps - Set of distinct items
      */
-    buildFunctionTypeFingerprint(type, output, fps) {
+    buildFunctionTypeFingerprint(type, output) {
         let input = type.id;
         // All forms of `[]`/`()`/`->` get collapsed down to one thing in the bloom filter.
         // Differentiating between arrays and slices, if the user asks for it, is
@@ -1427,10 +1628,11 @@ class DocSearch {
             output[0] |= (1 << (h0a % 32)) | (1 << (h1b % 32));
             output[1] |= (1 << (h1a % 32)) | (1 << (h2b % 32));
             output[2] |= (1 << (h2a % 32)) | (1 << (h0b % 32));
-            fps.add(input);
+            // output[3] is the total number of items in the type signature
+            output[3] += 1;
         }
         for (const g of type.generics) {
-            this.buildFunctionTypeFingerprint(g, output, fps);
+            this.buildFunctionTypeFingerprint(g, output);
         }
         const fb = {
             id: null,
@@ -1441,9 +1643,8 @@ class DocSearch {
         for (const [k, v] of type.bindings.entries()) {
             fb.id = k;
             fb.generics = v;
-            this.buildFunctionTypeFingerprint(fb, output, fps);
+            this.buildFunctionTypeFingerprint(fb, output);
         }
-        output[3] = fps.size;
     }
 
     /**
@@ -1463,11 +1664,12 @@ class DocSearch {
          * The raw function search type format is generated using serde in
          * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
          *
+         * @param {Array<{name: string, ty: number}>} paths
          * @param {Array<{name: string, ty: number}>} lowercasePaths
          *
          * @return {null|FunctionSearchType}
          */
-        const buildFunctionSearchTypeCallback = lowercasePaths => {
+        const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => {
             return functionSearchType => {
                 if (functionSearchType === 0) {
                     return null;
@@ -1477,11 +1679,16 @@ class DocSearch {
                 let inputs, output;
                 if (typeof functionSearchType[INPUTS_DATA] === "number") {
                     inputs = [
-                        this.buildItemSearchType(functionSearchType[INPUTS_DATA], lowercasePaths),
+                        this.buildItemSearchType(
+                            functionSearchType[INPUTS_DATA],
+                            paths,
+                            lowercasePaths,
+                        ),
                     ];
                 } else {
                     inputs = this.buildItemSearchTypeAll(
                         functionSearchType[INPUTS_DATA],
+                        paths,
                         lowercasePaths,
                     );
                 }
@@ -1490,12 +1697,14 @@ class DocSearch {
                         output = [
                             this.buildItemSearchType(
                                 functionSearchType[OUTPUT_DATA],
+                                paths,
                                 lowercasePaths,
                             ),
                         ];
                     } else {
                         output = this.buildItemSearchTypeAll(
                             functionSearchType[OUTPUT_DATA],
+                            paths,
                             lowercasePaths,
                         );
                     }
@@ -1506,8 +1715,12 @@ class DocSearch {
                 const l = functionSearchType.length;
                 for (let i = 2; i < l; ++i) {
                     where_clause.push(typeof functionSearchType[i] === "number"
-                        ? [this.buildItemSearchType(functionSearchType[i], lowercasePaths)]
-                        : this.buildItemSearchTypeAll(functionSearchType[i], lowercasePaths));
+                        ? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)]
+                        : this.buildItemSearchTypeAll(
+                            functionSearchType[i],
+                            paths,
+                            lowercasePaths,
+                        ));
                 }
                 return {
                     inputs, output, where_clause,
@@ -1551,9 +1764,17 @@ class DocSearch {
             this.searchIndexEmptyDesc.set(crate, new RoaringBitmap(crateCorpus.e));
             let descIndex = 0;
 
+            /**
+             * List of generic function type parameter names.
+             * Used for display, not for searching.
+             * @type {[string]}
+             */
+            let lastParamNames = [];
+
             // This object should have exactly the same set of fields as the "row"
             // object defined below. Your JavaScript runtime will thank you.
             // https://mathiasbynens.be/notes/shapes-ics
+            let normalizedName = crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, "");
             const crateRow = {
                 crate,
                 ty: 3, // == ExternCrate
@@ -1565,12 +1786,14 @@ class DocSearch {
                 desc: crateCorpus.doc,
                 parent: undefined,
                 type: null,
+                paramNames: lastParamNames,
                 id,
                 word: crate,
-                normalizedName: crate.indexOf("_") === -1 ? crate : crate.replace(/_/g, ""),
+                normalizedName,
                 bitIndex: 0,
                 implDisambiguator: null,
             };
+            this.nameTrie.insert(normalizedName, id, this.tailTable);
             id += 1;
             searchIndex.push(crateRow);
             currentIndex += 1;
@@ -1601,6 +1824,10 @@ class DocSearch {
             // an array of [(String) alias name
             //             [Number] index to items]
             const aliases = crateCorpus.a;
+            // an array of [(Number) item index,
+            //              (String) comma-separated list of function generic param names]
+            // an item whose index is not present will fall back to the previous present path
+            const itemParamNames = new Map(crateCorpus.P);
 
             // an array of [{name: String, ty: Number}]
             const lowercasePaths = [];
@@ -1608,7 +1835,7 @@ class DocSearch {
             // a string representing the list of function types
             const itemFunctionDecoder = new VlqHexDecoder(
                 crateCorpus.f,
-                buildFunctionSearchTypeCallback(lowercasePaths),
+                buildFunctionSearchTypeCallback(paths, lowercasePaths),
             );
 
             // convert `rawPaths` entries into object form
@@ -1620,14 +1847,17 @@ class DocSearch {
                 const ty = elem[0];
                 const name = elem[1];
                 let path = null;
-                if (elem.length > 2) {
+                if (elem.length > 2 && elem[2] !== null) {
                     path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
                     lastPath = path;
                 }
-                const exactPath = elem.length > 3 ? itemPaths.get(elem[3]) : path;
+                const exactPath = elem.length > 3 && elem[3] !== null ?
+                    itemPaths.get(elem[3]) :
+                    path;
+                const unboxFlag = elem.length > 4 && !!elem[4];
 
-                lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath });
-                paths[i] = { ty, name, path, exactPath };
+                lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag });
+                paths[i] = { ty, name, path, exactPath, unboxFlag };
             }
 
             // convert `item*` into an object form, and construct word indices.
@@ -1659,20 +1889,22 @@ class DocSearch {
                 const name = itemNames[i] === "" ? lastName : itemNames[i];
                 const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase();
                 const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
+                const paramNames = itemParamNames.has(i) ?
+                    itemParamNames.get(i).split(",") :
+                    lastParamNames;
                 const type = itemFunctionDecoder.next();
                 if (type !== null) {
                     if (type) {
                         const fp = this.functionTypeFingerprint.subarray(id * 4, (id + 1) * 4);
-                        const fps = new Set();
                         for (const t of type.inputs) {
-                            this.buildFunctionTypeFingerprint(t, fp, fps);
+                            this.buildFunctionTypeFingerprint(t, fp);
                         }
                         for (const t of type.output) {
-                            this.buildFunctionTypeFingerprint(t, fp, fps);
+                            this.buildFunctionTypeFingerprint(t, fp);
                         }
                         for (const w of type.where_clause) {
                             for (const t of w) {
-                                this.buildFunctionTypeFingerprint(t, fp, fps);
+                                this.buildFunctionTypeFingerprint(t, fp);
                             }
                         }
                     }
@@ -1680,6 +1912,7 @@ class DocSearch {
                 // This object should have exactly the same set of fields as the "crateRow"
                 // object defined above.
                 const itemParentIdx = itemParentIdxDecoder.next();
+                normalizedName = word.indexOf("_") === -1 ? word : word.replace(/_/g, "");
                 const row = {
                     crate,
                     ty: itemTypes.charCodeAt(i) - 65, // 65 = "A"
@@ -1691,16 +1924,19 @@ class DocSearch {
                         itemPaths.get(itemReexports.get(i)) : path,
                     parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined,
                     type,
+                    paramNames,
                     id,
                     word,
-                    normalizedName: word.indexOf("_") === -1 ? word : word.replace(/_/g, ""),
+                    normalizedName,
                     bitIndex,
                     implDisambiguator: implDisambiguator.has(i) ?
                         implDisambiguator.get(i) : null,
                 };
+                this.nameTrie.insert(normalizedName, id, this.tailTable);
                 id += 1;
                 searchIndex.push(row);
                 lastPath = row.path;
+                lastParamNames = row.paramNames;
                 if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
                     descIndex += 1;
                 }
@@ -1786,8 +2022,7 @@ class DocSearch {
          */
         function newParsedQuery(userQuery) {
             return {
-                original: userQuery,
-                userQuery: userQuery.toLowerCase(),
+                userQuery,
                 elems: [],
                 returned: [],
                 // Total number of "top" elements (does not include generics).
@@ -1909,7 +2144,7 @@ class DocSearch {
             genericsElems: 0,
             typeFilter: null,
             isInBinding: null,
-            userQuery: userQuery.toLowerCase(),
+            userQuery,
         };
         let query = newParsedQuery(userQuery);
 
@@ -1990,6 +2225,7 @@ class DocSearch {
                     "/index.html#reexport." + name;
             } else if (type === "primitive" || type === "keyword") {
                 displayPath = "";
+                exactPath = "";
                 href = this.rootPath + path.replace(/::/g, "/") +
                     "/" + type + "." + name + ".html";
             } else if (type === "externcrate") {
@@ -2005,6 +2241,7 @@ class DocSearch {
 
                 if (parentType === "primitive") {
                     displayPath = myparent.name + "::";
+                    exactPath = myparent.name;
                 } else if (type === "structfield" && parentType === "variant") {
                     // Structfields belonging to variants are special: the
                     // final path element is the enum name.
@@ -2046,18 +2283,21 @@ class DocSearch {
          * marked for removal.
          *
          * @param {[ResultObject]} results
+         * @param {"sig"|"elems"|"returned"|null} typeInfo
+         * @param {ParsedQuery} query
          * @returns {[ResultObject]}
          */
-        const transformResults = results => {
+        const transformResults = (results, typeInfo) => {
             const duplicates = new Set();
             const out = [];
 
             for (const result of results) {
                 if (result.id !== -1) {
-                    const obj = this.searchIndex[result.id];
-                    obj.dist = result.dist;
-                    const res = buildHrefAndPath(obj);
-                    obj.displayPath = pathSplitter(res[0]);
+                    const res = buildHrefAndPath(this.searchIndex[result.id]);
+                    const obj = Object.assign({
+                        dist: result.dist,
+                        displayPath: pathSplitter(res[0]),
+                    }, this.searchIndex[result.id]);
 
                     // To be sure than it some items aren't considered as duplicate.
                     obj.fullPath = res[2] + "|" + obj.ty;
@@ -2076,6 +2316,11 @@ class DocSearch {
                     duplicates.add(obj.fullPath);
                     duplicates.add(res[2]);
 
+                    if (typeInfo !== null) {
+                        obj.displayTypeSignature =
+                            this.formatDisplayTypeSignature(obj, typeInfo);
+                    }
+
                     obj.href = res[1];
                     out.push(obj);
                     if (out.length >= MAX_RESULTS) {
@@ -2087,6 +2332,330 @@ class DocSearch {
         };
 
         /**
+         * Add extra data to result objects, and filter items that have been
+         * marked for removal.
+         *
+         * The output is formatted as an array of hunks, where odd numbered
+         * hunks are highlighted and even numbered ones are not.
+         *
+         * @param {ResultObject} obj
+         * @param {"sig"|"elems"|"returned"|null} typeInfo
+         * @param {ParsedQuery} query
+         * @returns Promise<
+         *   "type": Array<string>,
+         *   "mappedNames": Map<string, string>,
+         *   "whereClause": Map<string, Array<string>>,
+         * >
+         */
+        this.formatDisplayTypeSignature = async(obj, typeInfo) => {
+            let fnInputs = null;
+            let fnOutput = null;
+            let mgens = null;
+            if (typeInfo !== "elems" && typeInfo !== "returned") {
+                fnInputs = unifyFunctionTypes(
+                    obj.type.inputs,
+                    parsedQuery.elems,
+                    obj.type.where_clause,
+                    null,
+                    mgensScratch => {
+                        fnOutput = unifyFunctionTypes(
+                            obj.type.output,
+                            parsedQuery.returned,
+                            obj.type.where_clause,
+                            mgensScratch,
+                            mgensOut => {
+                                mgens = mgensOut;
+                                return true;
+                            },
+                            0,
+                        );
+                        return !!fnOutput;
+                    },
+                    0,
+                );
+            } else {
+                const arr = typeInfo === "elems" ? obj.type.inputs : obj.type.output;
+                const highlighted = unifyFunctionTypes(
+                    arr,
+                    parsedQuery.elems,
+                    obj.type.where_clause,
+                    null,
+                    mgensOut => {
+                        mgens = mgensOut;
+                        return true;
+                    },
+                    0,
+                );
+                if (typeInfo === "elems") {
+                    fnInputs = highlighted;
+                } else {
+                    fnOutput = highlighted;
+                }
+            }
+            if (!fnInputs) {
+                fnInputs = obj.type.inputs;
+            }
+            if (!fnOutput) {
+                fnOutput = obj.type.output;
+            }
+            const mappedNames = new Map();
+            const whereClause = new Map();
+
+            const fnParamNames = obj.paramNames;
+            const queryParamNames = [];
+            /**
+             * Recursively writes a map of IDs to query generic names,
+             * which are later used to map query generic names to function generic names.
+             * For example, when the user writes `X -> Option<X>` and the function
+             * is actually written as `T -> Option<T>`, this function stores the
+             * mapping `(-1, "X")`, and the writeFn function looks up the entry
+             * for -1 to form the final, user-visible mapping of "X is T".
+             *
+             * @param {QueryElement} queryElem
+             */
+            const remapQuery = queryElem => {
+                if (queryElem.id < 0) {
+                    queryParamNames[-1 - queryElem.id] = queryElem.name;
+                }
+                if (queryElem.generics.length > 0) {
+                    queryElem.generics.forEach(remapQuery);
+                }
+                if (queryElem.bindings.size > 0) {
+                    [...queryElem.bindings.values()].flat().forEach(remapQuery);
+                }
+            };
+
+            parsedQuery.elems.forEach(remapQuery);
+            parsedQuery.returned.forEach(remapQuery);
+
+            /**
+             * Write text to a highlighting array.
+             * Index 0 is not highlighted, index 1 is highlighted,
+             * index 2 is not highlighted, etc.
+             *
+             * @param {{name: string, highlighted: bool|undefined}} fnType - input
+             * @param {[string]} result
+             */
+            const pushText = (fnType, result) => {
+                // If !!(result.length % 2) == false, then pushing a new slot starts an even
+                // numbered slot. Even numbered slots are not highlighted.
+                //
+                // `highlighted` will not be defined if an entire subtree is not highlighted,
+                // so `!!` is used to coerce it to boolean. `result.length % 2` is used to
+                // check if the number is even, but it evaluates to a number, so it also
+                // needs coerced to a boolean.
+                if (!!(result.length % 2) === !!fnType.highlighted) {
+                    result.push("");
+                } else if (result.length === 0 && !!fnType.highlighted) {
+                    result.push("");
+                    result.push("");
+                }
+
+                result[result.length - 1] += fnType.name;
+            };
+
+            /**
+             * Write a higher order function type: either a function pointer
+             * or a trait bound on Fn, FnMut, or FnOnce.
+             *
+             * @param {FunctionType} fnType - input
+             * @param {[string]} result
+             */
+            const writeHof = (fnType, result) => {
+                const hofOutput = fnType.bindings.get(this.typeNameIdOfOutput) || [];
+                const hofInputs = fnType.generics;
+                pushText(fnType, result);
+                pushText({name: " (", highlighted: false}, result);
+                let needsComma = false;
+                for (const fnType of hofInputs) {
+                    if (needsComma) {
+                        pushText({ name: ", ", highlighted: false }, result);
+                    }
+                    needsComma = true;
+                    writeFn(fnType, result);
+                }
+                pushText({
+                    name: hofOutput.length === 0 ? ")" : ") -> ",
+                    highlighted: false,
+                }, result);
+                if (hofOutput.length > 1) {
+                    pushText({name: "(", highlighted: false}, result);
+                }
+                needsComma = false;
+                for (const fnType of hofOutput) {
+                    if (needsComma) {
+                        pushText({ name: ", ", highlighted: false }, result);
+                    }
+                    needsComma = true;
+                    writeFn(fnType, result);
+                }
+                if (hofOutput.length > 1) {
+                    pushText({name: ")", highlighted: false}, result);
+                }
+            };
+
+            /**
+             * Write a primitive type with special syntax, like `!` or `[T]`.
+             * Returns `false` if the supplied type isn't special.
+             *
+             * @param {FunctionType} fnType
+             * @param {[string]} result
+             */
+            const writeSpecialPrimitive = (fnType, result) => {
+                if (fnType.id === this.typeNameIdOfArray || fnType.id === this.typeNameIdOfSlice ||
+                    fnType.id === this.typeNameIdOfTuple || fnType.id === this.typeNameIdOfUnit) {
+                    const [ob, sb] =
+                        fnType.id === this.typeNameIdOfArray ||
+                            fnType.id === this.typeNameIdOfSlice ?
+                        ["[", "]"] :
+                        ["(", ")"];
+                    pushText({ name: ob, highlighted: fnType.highlighted }, result);
+                    onEachBtwn(
+                        fnType.generics,
+                        nested => writeFn(nested, result),
+                        () => pushText({ name: ", ", highlighted: false }, result),
+                    );
+                    pushText({ name: sb, highlighted: fnType.highlighted }, result);
+                    return true;
+                } else if (fnType.id === this.typeNameIdOfReference) {
+                    pushText({ name: "&", highlighted: fnType.highlighted }, result);
+                    let prevHighlighted = false;
+                    onEachBtwn(
+                        fnType.generics,
+                        value => {
+                            prevHighlighted = value.highlighted;
+                            writeFn(value, result);
+                        },
+                        value => pushText({
+                            name: " ",
+                            highlighted: prevHighlighted && value.highlighted,
+                        }, result),
+                    );
+                    return true;
+                } else if (fnType.id === this.typeNameIdOfFn) {
+                    writeHof(fnType, result);
+                    return true;
+                }
+                return false;
+            };
+            /**
+             * Write a type. This function checks for special types,
+             * like slices, with their own formatting. It also handles
+             * updating the where clause and generic type param map.
+             *
+             * @param {FunctionType} fnType
+             * @param {[string]} result
+             */
+            const writeFn = (fnType, result) => {
+                if (fnType.id < 0) {
+                    if (fnParamNames[-1 - fnType.id] === "") {
+                        for (const nested of fnType.generics) {
+                            writeFn(nested, result);
+                        }
+                        return;
+                    } else if (mgens) {
+                        for (const [queryId, fnId] of mgens) {
+                            if (fnId === fnType.id) {
+                                mappedNames.set(
+                                    queryParamNames[-1 - queryId],
+                                    fnParamNames[-1 - fnType.id],
+                                );
+                            }
+                        }
+                    }
+                    pushText({
+                        name: fnParamNames[-1 - fnType.id],
+                        highlighted: !!fnType.highlighted,
+                    }, result);
+                    const where = [];
+                    onEachBtwn(
+                        fnType.generics,
+                        nested => writeFn(nested, where),
+                        () => pushText({ name: " + ", highlighted: false }, where),
+                    );
+                    if (where.length > 0) {
+                        whereClause.set(fnParamNames[-1 - fnType.id], where);
+                    }
+                } else {
+                    if (fnType.ty === TY_PRIMITIVE) {
+                        if (writeSpecialPrimitive(fnType, result)) {
+                            return;
+                        }
+                    } else if (fnType.ty === TY_TRAIT && (
+                        fnType.id === this.typeNameIdOfFn ||
+                            fnType.id === this.typeNameIdOfFnMut ||
+                            fnType.id === this.typeNameIdOfFnOnce)) {
+                        writeHof(fnType, result);
+                        return;
+                    }
+                    pushText(fnType, result);
+                    let hasBindings = false;
+                    if (fnType.bindings.size > 0) {
+                        onEachBtwn(
+                            fnType.bindings,
+                            ([key, values]) => {
+                                const name = this.assocTypeIdNameMap.get(key);
+                                if (values.length === 1 && values[0].id < 0 &&
+                                    `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) {
+                                    // the internal `Item=Iterator::Item` type variable should be
+                                    // shown in the where clause and name mapping output, but is
+                                    // redundant in this spot
+                                    for (const value of values) {
+                                        writeFn(value, []);
+                                    }
+                                    return true;
+                                }
+                                if (!hasBindings) {
+                                    hasBindings = true;
+                                    pushText({ name: "<", highlighted: false }, result);
+                                }
+                                pushText({ name, highlighted: false }, result);
+                                pushText({
+                                    name: values.length !== 1 ? "=(" : "=",
+                                    highlighted: false,
+                                }, result);
+                                onEachBtwn(
+                                    values || [],
+                                    value => writeFn(value, result),
+                                    () => pushText({ name: " + ",  highlighted: false }, result),
+                                );
+                                if (values.length !== 1) {
+                                    pushText({ name: ")", highlighted: false }, result);
+                                }
+                            },
+                            () => pushText({ name: ", ",  highlighted: false }, result),
+                        );
+                    }
+                    if (fnType.generics.length > 0) {
+                        pushText({ name: hasBindings ? ", " : "<", highlighted: false }, result);
+                    }
+                    onEachBtwn(
+                        fnType.generics,
+                        value => writeFn(value, result),
+                        () => pushText({ name: ", ",  highlighted: false }, result),
+                    );
+                    if (hasBindings || fnType.generics.length > 0) {
+                        pushText({ name: ">", highlighted: false }, result);
+                    }
+                }
+            };
+            const type = [];
+            onEachBtwn(
+                fnInputs,
+                fnType => writeFn(fnType, type),
+                () => pushText({ name: ", ",  highlighted: false }, type),
+            );
+            pushText({ name: " -> ", highlighted: false }, type);
+            onEachBtwn(
+                fnOutput,
+                fnType => writeFn(fnType, type),
+                () => pushText({ name: ", ",  highlighted: false }, type),
+            );
+
+            return {type, mappedNames, whereClause};
+        };
+
+        /**
          * This function takes a result map, and sorts it by various criteria, including edit
          * distance, substring match, and the crate it comes from.
          *
@@ -2095,9 +2664,10 @@ class DocSearch {
          * @param {string} preferredCrate
          * @returns {Promise<[ResultObject]>}
          */
-        const sortResults = async(results, isType, preferredCrate) => {
+        const sortResults = async(results, typeInfo, preferredCrate) => {
             const userQuery = parsedQuery.userQuery;
-            const casedUserQuery = parsedQuery.original;
+            const normalizedUserQuery = parsedQuery.userQuery.toLowerCase();
+            const isMixedCase = normalizedUserQuery !== userQuery;
             const result_list = [];
             for (const result of results.values()) {
                 result.item = this.searchIndex[result.id];
@@ -2109,15 +2679,17 @@ class DocSearch {
                 let a, b;
 
                 // sort by exact case-sensitive match
-                a = (aaa.item.name !== casedUserQuery);
-                b = (bbb.item.name !== casedUserQuery);
-                if (a !== b) {
-                    return a - b;
+                if (isMixedCase) {
+                    a = (aaa.item.name !== userQuery);
+                    b = (bbb.item.name !== userQuery);
+                    if (a !== b) {
+                        return a - b;
+                    }
                 }
 
                 // sort by exact match with regard to the last word (mismatch goes later)
-                a = (aaa.word !== userQuery);
-                b = (bbb.word !== userQuery);
+                a = (aaa.word !== normalizedUserQuery);
+                b = (bbb.word !== normalizedUserQuery);
                 if (a !== b) {
                     return a - b;
                 }
@@ -2205,30 +2777,30 @@ class DocSearch {
                 return 0;
             });
 
-            return transformResults(result_list);
+            return transformResults(result_list, typeInfo);
         };
 
         /**
          * This function checks if a list of search query `queryElems` can all be found in the
          * search index (`fnTypes`).
          *
-         * This function returns `true` on a match, or `false` if none. If `solutionCb` is
+         * This function returns highlighted results on a match, or `null`. If `solutionCb` is
          * supplied, it will call that function with mgens, and that callback can accept or
-         * reject the result bu returning `true` or `false`. If the callback returns false,
-         * then this function will try with a different solution, or bail with false if it
+         * reject the result by returning `true` or `false`. If the callback returns false,
+         * then this function will try with a different solution, or bail with null if it
          * runs out of candidates.
          *
          * @param {Array<FunctionType>} fnTypesIn - The objects to check.
          * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
-         *     - Map functions generics to query generics (never modified).
-         * @param {null|Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         *     - Map query generics to function generics (never modified).
+         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
-         * @return {boolean} - Returns true if a match, false otherwise.
+         * @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise.
          */
         function unifyFunctionTypes(
             fnTypesIn,
@@ -2239,17 +2811,17 @@ class DocSearch {
             unboxingDepth,
         ) {
             if (unboxingDepth >= UNBOXING_LIMIT) {
-                return false;
+                return null;
             }
             /**
              * @type Map<integer, integer>|null
              */
             const mgens = mgensIn === null ? null : new Map(mgensIn);
             if (queryElems.length === 0) {
-                return !solutionCb || solutionCb(mgens);
+                return solutionCb(mgens) ? fnTypesIn : null;
             }
             if (!fnTypesIn || fnTypesIn.length === 0) {
-                return false;
+                return null;
             }
             const ql = queryElems.length;
             const fl = fnTypesIn.length;
@@ -2258,26 +2830,45 @@ class DocSearch {
             if (ql === 1 && queryElems[0].generics.length === 0
                 && queryElems[0].bindings.size === 0) {
                 const queryElem = queryElems[0];
-                for (const fnType of fnTypesIn) {
+                for (const [i, fnType] of fnTypesIn.entries()) {
                     if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
                         continue;
                     }
                     if (fnType.id < 0 && queryElem.id < 0) {
-                        if (mgens && mgens.has(fnType.id) &&
-                            mgens.get(fnType.id) !== queryElem.id) {
+                        if (mgens && mgens.has(queryElem.id) &&
+                            mgens.get(queryElem.id) !== fnType.id) {
                             continue;
                         }
                         const mgensScratch = new Map(mgens);
-                        mgensScratch.set(fnType.id, queryElem.id);
+                        mgensScratch.set(queryElem.id, fnType.id);
                         if (!solutionCb || solutionCb(mgensScratch)) {
-                            return true;
+                            const highlighted = [...fnTypesIn];
+                            highlighted[i] = Object.assign({
+                                highlighted: true,
+                            }, fnType, {
+                                generics: whereClause[-1 - fnType.id],
+                            });
+                            return highlighted;
                         }
-                    } else if (!solutionCb || solutionCb(mgens ? new Map(mgens) : null)) {
+                    } else if (solutionCb(mgens ? new Map(mgens) : null)) {
                         // unifyFunctionTypeIsMatchCandidate already checks that ids match
-                        return true;
+                        const highlighted = [...fnTypesIn];
+                        highlighted[i] = Object.assign({
+                            highlighted: true,
+                        }, fnType, {
+                            generics: unifyGenericTypes(
+                                fnType.generics,
+                                queryElem.generics,
+                                whereClause,
+                                mgens ? new Map(mgens) : null,
+                                solutionCb,
+                                unboxingDepth,
+                            ) || fnType.generics,
+                        });
+                        return highlighted;
                     }
                 }
-                for (const fnType of fnTypesIn) {
+                for (const [i, fnType] of fnTypesIn.entries()) {
                     if (!unifyFunctionTypeIsUnboxCandidate(
                         fnType,
                         queryElem,
@@ -2288,31 +2879,42 @@ class DocSearch {
                         continue;
                     }
                     if (fnType.id < 0) {
-                        if (mgens && mgens.has(fnType.id) &&
-                            mgens.get(fnType.id) !== 0) {
-                            continue;
-                        }
-                        const mgensScratch = new Map(mgens);
-                        mgensScratch.set(fnType.id, 0);
-                        if (unifyFunctionTypes(
+                        const highlightedGenerics = unifyFunctionTypes(
                             whereClause[(-fnType.id) - 1],
                             queryElems,
                             whereClause,
-                            mgensScratch,
+                            mgens,
                             solutionCb,
                             unboxingDepth + 1,
-                        )) {
-                            return true;
+                        );
+                        if (highlightedGenerics) {
+                            const highlighted = [...fnTypesIn];
+                            highlighted[i] = Object.assign({
+                                highlighted: true,
+                            }, fnType, {
+                                generics: highlightedGenerics,
+                            });
+                            return highlighted;
+                        }
+                    } else {
+                        const highlightedGenerics = unifyFunctionTypes(
+                            [...Array.from(fnType.bindings.values()).flat(), ...fnType.generics],
+                            queryElems,
+                            whereClause,
+                            mgens ? new Map(mgens) : null,
+                            solutionCb,
+                            unboxingDepth + 1,
+                        );
+                        if (highlightedGenerics) {
+                            const highlighted = [...fnTypesIn];
+                            highlighted[i] = Object.assign({}, fnType, {
+                                generics: highlightedGenerics,
+                                bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
+                                    return [k, highlightedGenerics.splice(0, v.length)];
+                                })),
+                            });
+                            return highlighted;
                         }
-                    } else if (unifyFunctionTypes(
-                        [...fnType.generics, ...Array.from(fnType.bindings.values()).flat()],
-                        queryElems,
-                        whereClause,
-                        mgens ? new Map(mgens) : null,
-                        solutionCb,
-                        unboxingDepth + 1,
-                    )) {
-                        return true;
                     }
                 }
                 return false;
@@ -2352,11 +2954,11 @@ class DocSearch {
                 let mgensScratch;
                 if (fnType.id < 0) {
                     mgensScratch = new Map(mgens);
-                    if (mgensScratch.has(fnType.id)
-                        && mgensScratch.get(fnType.id) !== queryElem.id) {
+                    if (mgensScratch.has(queryElem.id)
+                        && mgensScratch.get(queryElem.id) !== fnType.id) {
                         continue;
                     }
-                    mgensScratch.set(fnType.id, queryElem.id);
+                    mgensScratch.set(queryElem.id, fnType.id);
                 } else {
                     mgensScratch = mgens;
                 }
@@ -2369,6 +2971,8 @@ class DocSearch {
                 if (!queryElemsTmp) {
                     queryElemsTmp = queryElems.slice(0, qlast);
                 }
+                let unifiedGenerics = [];
+                let unifiedGenericsMgens = null;
                 const passesUnification = unifyFunctionTypes(
                     fnTypes,
                     queryElemsTmp,
@@ -2377,7 +2981,7 @@ class DocSearch {
                     mgensScratch => {
                         if (fnType.generics.length === 0 && queryElem.generics.length === 0
                             && fnType.bindings.size === 0 && queryElem.bindings.size === 0) {
-                            return !solutionCb || solutionCb(mgensScratch);
+                            return solutionCb(mgensScratch);
                         }
                         const solution = unifyFunctionTypeCheckBindings(
                             fnType,
@@ -2391,7 +2995,7 @@ class DocSearch {
                         }
                         const simplifiedGenerics = solution.simplifiedGenerics;
                         for (const simplifiedMgens of solution.mgens) {
-                            const passesUnification = unifyFunctionTypes(
+                            unifiedGenerics = unifyGenericTypes(
                                 simplifiedGenerics,
                                 queryElem.generics,
                                 whereClause,
@@ -2399,7 +3003,8 @@ class DocSearch {
                                 solutionCb,
                                 unboxingDepth,
                             );
-                            if (passesUnification) {
+                            if (unifiedGenerics !== null) {
+                                unifiedGenericsMgens = simplifiedMgens;
                                 return true;
                             }
                         }
@@ -2408,7 +3013,23 @@ class DocSearch {
                     unboxingDepth,
                 );
                 if (passesUnification) {
-                    return true;
+                    passesUnification.length = fl;
+                    passesUnification[flast] = passesUnification[i];
+                    passesUnification[i] = Object.assign({}, fnType, {
+                        highlighted: true,
+                        generics: unifiedGenerics,
+                        bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
+                            return [k, queryElem.bindings.has(k) ? unifyFunctionTypes(
+                                v,
+                                queryElem.bindings.get(k),
+                                whereClause,
+                                unifiedGenericsMgens,
+                                solutionCb,
+                                unboxingDepth,
+                            ) : unifiedGenerics.splice(0, v.length)];
+                        })),
+                    });
+                    return passesUnification;
                 }
                 // backtrack
                 fnTypes[flast] = fnTypes[i];
@@ -2426,16 +3047,6 @@ class DocSearch {
                 )) {
                     continue;
                 }
-                let mgensScratch;
-                if (fnType.id < 0) {
-                    mgensScratch = new Map(mgens);
-                    if (mgensScratch.has(fnType.id) && mgensScratch.get(fnType.id) !== 0) {
-                        continue;
-                    }
-                    mgensScratch.set(fnType.id, 0);
-                } else {
-                    mgensScratch = mgens;
-                }
                 const generics = fnType.id < 0 ?
                     whereClause[(-fnType.id) - 1] :
                     fnType.generics;
@@ -2443,18 +3054,225 @@ class DocSearch {
                     Array.from(fnType.bindings.values()).flat() :
                     [];
                 const passesUnification = unifyFunctionTypes(
-                    fnTypes.toSpliced(i, 1, ...generics, ...bindings),
+                    fnTypes.toSpliced(i, 1, ...bindings, ...generics),
                     queryElems,
                     whereClause,
-                    mgensScratch,
+                    mgens,
                     solutionCb,
                     unboxingDepth + 1,
                 );
                 if (passesUnification) {
-                    return true;
+                    const highlightedGenerics = passesUnification.slice(
+                        i,
+                        i + generics.length + bindings.length,
+                    );
+                    const highlightedFnType = Object.assign({}, fnType, {
+                        generics: highlightedGenerics,
+                        bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
+                            return [k, highlightedGenerics.splice(0, v.length)];
+                        })),
+                    });
+                    return passesUnification.toSpliced(
+                        i,
+                        generics.length + bindings.length,
+                        highlightedFnType,
+                    );
                 }
             }
-            return false;
+            return null;
+        }
+        /**
+         * This function compares two lists of generics.
+         *
+         * This function behaves very similarly to `unifyFunctionTypes`, except that it
+         * doesn't skip or reorder anything. This is intended to match the behavior of
+         * the ordinary Rust type system, so that `Vec<Allocator>` only matches an actual
+         * `Vec` of `Allocators` and not the implicit `Allocator` parameter that every
+         * `Vec` has.
+         *
+         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
+         * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
+         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {Map<number,number>|null} mgensIn
+         *     - Map functions generics to query generics (never modified).
+         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {number} unboxingDepth
+         *     - Limit checks that Ty matches Vec<Ty>,
+         *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
+         *
+         * @return {[FunctionType]|null} - Returns highlighed results if a match, null otherwise.
+         */
+        function unifyGenericTypes(
+            fnTypesIn,
+            queryElems,
+            whereClause,
+            mgensIn,
+            solutionCb,
+            unboxingDepth,
+        ) {
+            if (unboxingDepth >= UNBOXING_LIMIT) {
+                return null;
+            }
+            /**
+             * @type Map<integer, integer>|null
+             */
+            const mgens = mgensIn === null ? null : new Map(mgensIn);
+            if (queryElems.length === 0) {
+                return solutionCb(mgens) ? fnTypesIn : null;
+            }
+            if (!fnTypesIn || fnTypesIn.length === 0) {
+                return null;
+            }
+            const fnType = fnTypesIn[0];
+            const queryElem = queryElems[0];
+            if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
+                if (fnType.id < 0 && queryElem.id < 0) {
+                    if (!mgens || !mgens.has(queryElem.id) ||
+                        mgens.get(queryElem.id) === fnType.id
+                    ) {
+                        const mgensScratch = new Map(mgens);
+                        mgensScratch.set(queryElem.id, fnType.id);
+                        const fnTypesRemaining = unifyGenericTypes(
+                            fnTypesIn.slice(1),
+                            queryElems.slice(1),
+                            whereClause,
+                            mgensScratch,
+                            solutionCb,
+                            unboxingDepth,
+                        );
+                        if (fnTypesRemaining) {
+                            const highlighted = [fnType, ...fnTypesRemaining];
+                            highlighted[0] = Object.assign({
+                                highlighted: true,
+                            }, fnType, {
+                                generics: whereClause[-1 - fnType.id],
+                            });
+                            return highlighted;
+                        }
+                    }
+                } else {
+                    let unifiedGenerics;
+                    const fnTypesRemaining = unifyGenericTypes(
+                        fnTypesIn.slice(1),
+                        queryElems.slice(1),
+                        whereClause,
+                        mgens,
+                        mgensScratch => {
+                            const solution = unifyFunctionTypeCheckBindings(
+                                fnType,
+                                queryElem,
+                                whereClause,
+                                mgensScratch,
+                                unboxingDepth,
+                            );
+                            if (!solution) {
+                                return false;
+                            }
+                            const simplifiedGenerics = solution.simplifiedGenerics;
+                            for (const simplifiedMgens of solution.mgens) {
+                                unifiedGenerics = unifyGenericTypes(
+                                    simplifiedGenerics,
+                                    queryElem.generics,
+                                    whereClause,
+                                    simplifiedMgens,
+                                    solutionCb,
+                                    unboxingDepth,
+                                );
+                                if (unifiedGenerics !== null) {
+                                    return true;
+                                }
+                            }
+                        },
+                        unboxingDepth,
+                    );
+                    if (fnTypesRemaining) {
+                        const highlighted = [fnType, ...fnTypesRemaining];
+                        highlighted[0] = Object.assign({
+                            highlighted: true,
+                        }, fnType, {
+                            generics: unifiedGenerics || fnType.generics,
+                        });
+                        return highlighted;
+                    }
+                }
+            }
+            if (unifyFunctionTypeIsUnboxCandidate(
+                fnType,
+                queryElem,
+                whereClause,
+                mgens,
+                unboxingDepth + 1,
+            )) {
+                let highlightedRemaining;
+                if (fnType.id < 0) {
+                    // Where clause corresponds to `F: A + B`
+                    //                                 ^^^^^
+                    // The order of the constraints doesn't matter, so
+                    // use order-agnostic matching for it.
+                    const highlightedGenerics = unifyFunctionTypes(
+                        whereClause[(-fnType.id) - 1],
+                        [queryElem],
+                        whereClause,
+                        mgens,
+                        mgensScratch => {
+                            const hl = unifyGenericTypes(
+                                fnTypesIn.slice(1),
+                                queryElems.slice(1),
+                                whereClause,
+                                mgensScratch,
+                                solutionCb,
+                                unboxingDepth,
+                            );
+                            if (hl) {
+                                highlightedRemaining = hl;
+                            }
+                            return hl;
+                        },
+                        unboxingDepth + 1,
+                    );
+                    if (highlightedGenerics) {
+                        return [Object.assign({
+                            highlighted: true,
+                        }, fnType, {
+                            generics: highlightedGenerics,
+                        }), ...highlightedRemaining];
+                    }
+                } else {
+                    const highlightedGenerics = unifyGenericTypes(
+                        [
+                            ...Array.from(fnType.bindings.values()).flat(),
+                            ...fnType.generics,
+                        ],
+                        [queryElem],
+                        whereClause,
+                        mgens,
+                        mgensScratch => {
+                            const hl = unifyGenericTypes(
+                                fnTypesIn.slice(1),
+                                queryElems.slice(1),
+                                whereClause,
+                                mgensScratch,
+                                solutionCb,
+                                unboxingDepth,
+                            );
+                            if (hl) {
+                                highlightedRemaining = hl;
+                            }
+                            return hl;
+                        },
+                        unboxingDepth + 1,
+                    );
+                    if (highlightedGenerics) {
+                        return [Object.assign({}, fnType, {
+                            generics: highlightedGenerics,
+                            bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
+                                return [k, highlightedGenerics.splice(0, v.length)];
+                            })),
+                        }), ...highlightedRemaining];
+                    }
+                }
+            }
+            return null;
         }
         /**
          * Check if this function is a match candidate.
@@ -2467,7 +3285,7 @@ class DocSearch {
          *
          * @param {FunctionType} fnType
          * @param {QueryElement} queryElem
-         * @param {Map<number,number>|null} mgensIn - Map functions generics to query generics.
+         * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          * @returns {boolean}
          */
         const unifyFunctionTypeIsMatchCandidate = (fnType, queryElem, mgensIn) => {
@@ -2477,22 +3295,13 @@ class DocSearch {
             }
             // fnType.id < 0 means generic
             // queryElem.id < 0 does too
-            // mgensIn[fnType.id] = queryElem.id
-            // or, if mgensIn[fnType.id] = 0, then we've matched this generic with a bare trait
-            // and should make that same decision everywhere it appears
+            // mgensIn[queryElem.id] = fnType.id
             if (fnType.id < 0 && queryElem.id < 0) {
-                if (mgensIn) {
-                    if (mgensIn.has(fnType.id) && mgensIn.get(fnType.id) !== queryElem.id) {
-                        return false;
-                    }
-                    for (const [fid, qid] of mgensIn.entries()) {
-                        if (fnType.id !== fid && queryElem.id === qid) {
-                            return false;
-                        }
-                        if (fnType.id === fid && queryElem.id !== qid) {
-                            return false;
-                        }
-                    }
+                if (
+                    mgensIn && mgensIn.has(queryElem.id) &&
+                    mgensIn.get(queryElem.id) !== fnType.id
+                ) {
+                    return false;
                 }
                 return true;
             } else {
@@ -2569,7 +3378,7 @@ class DocSearch {
          * @param {FunctionType} fnType
          * @param {QueryElement} queryElem
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>} mgensIn - Map functions generics to query generics.
+         * @param {Map<number,number>} mgensIn - Map query generics to function generics.
          *                                            Never modified.
          * @param {number} unboxingDepth
          * @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
@@ -2625,7 +3434,7 @@ class DocSearch {
                     }
                 });
                 if (simplifiedGenerics.length > 0) {
-                    simplifiedGenerics = [...simplifiedGenerics, ...binds];
+                    simplifiedGenerics = [...binds, ...simplifiedGenerics];
                 } else {
                     simplifiedGenerics = binds;
                 }
@@ -2637,7 +3446,7 @@ class DocSearch {
          * @param {FunctionType} fnType
          * @param {QueryElement} queryElem
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+         * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          * @param {number} unboxingDepth
          * @returns {boolean}
          */
@@ -2651,19 +3460,10 @@ class DocSearch {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (fnType.id < 0 && queryElem.id >= 0) {
+            if (fnType.id < 0) {
                 if (!whereClause) {
                     return false;
                 }
-                // mgens[fnType.id] === 0 indicates that we committed to unboxing this generic
-                // mgens[fnType.id] === null indicates that we haven't decided yet
-                if (mgens && mgens.has(fnType.id) && mgens.get(fnType.id) !== 0) {
-                    return false;
-                }
-                // Where clauses can represent cyclical data.
-                // `null` prevents it from trying to unbox in an infinite loop
-                const mgensTmp = new Map(mgens);
-                mgensTmp.set(fnType.id, null);
                 // This is only a potential unbox if the search query appears in the where clause
                 // for example, searching `Read -> usize` should find
                 // `fn read_all<R: Read>(R) -> Result<usize>`
@@ -2672,10 +3472,11 @@ class DocSearch {
                     whereClause[(-fnType.id) - 1],
                     queryElem,
                     whereClause,
-                    mgensTmp,
+                    mgens,
                     unboxingDepth,
                 );
-            } else if (fnType.generics.length > 0 || fnType.bindings.size > 0) {
+            } else if (fnType.unboxFlag &&
+                (fnType.generics.length > 0 || fnType.bindings.size > 0)) {
                 const simplifiedGenerics = [
                     ...fnType.generics,
                     ...Array.from(fnType.bindings.values()).flat(),
@@ -2719,7 +3520,7 @@ class DocSearch {
          * @param {Row} row
          * @param {QueryElement} elem          - The element from the parsed query.
          * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
+         * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          *
          * @return {boolean} - Returns true if the type matches, false otherwise.
          */
@@ -2727,33 +3528,42 @@ class DocSearch {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (row.bindings.size === 0 && elem.bindings.size === 0) {
-                if (elem.id < 0 && mgens === null) {
-                    return row.id < 0 || checkIfInList(
-                        row.generics,
-                        elem,
-                        whereClause,
-                        mgens,
-                        unboxingDepth + 1,
-                    );
-                }
-                if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
-                    typePassesFilter(elem.typeFilter, row.ty) && elem.generics.length === 0 &&
-                    // special case
-                    elem.id !== this.typeNameIdOfArrayOrSlice
-                    && elem.id !== this.typeNameIdOfTupleOrUnit
-                    && elem.id !== this.typeNameIdOfHof
-                ) {
-                    return row.id === elem.id || checkIfInList(
-                        row.generics,
-                        elem,
-                        whereClause,
-                        mgens,
-                        unboxingDepth,
-                    );
+            if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
+                row.generics.length === 0 && elem.generics.length === 0 &&
+                row.bindings.size === 0 && elem.bindings.size === 0 &&
+                // special case
+                elem.id !== this.typeNameIdOfArrayOrSlice &&
+                elem.id !== this.typeNameIdOfHof &&
+                elem.id !== this.typeNameIdOfTupleOrUnit
+            ) {
+                return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
+            } else {
+                return unifyFunctionTypes(
+                    [row],
+                    [elem],
+                    whereClause,
+                    mgens,
+                    () => true,
+                    unboxingDepth,
+                );
+            }
+        };
+
+        /**
+         * Check a query solution for conflicting generics.
+         */
+        const checkTypeMgensForConflict = mgens => {
+            if (!mgens) {
+                return true;
+            }
+            const fnTypes = new Set();
+            for (const [_qid, fid] of mgens) {
+                if (fnTypes.has(fid)) {
+                    return false;
                 }
+                fnTypes.add(fid);
             }
-            return unifyFunctionTypes([row], [elem], whereClause, mgens, null, unboxingDepth);
+            return true;
         };
 
         /**
@@ -2949,96 +3759,6 @@ class DocSearch {
         }
 
         /**
-         * This function is called in case the query is only one element (with or without generics).
-         * This element will be compared to arguments' and returned values' items and also to items.
-         *
-         * Other important thing to note: since there is only one element, we use edit
-         * distance for name comparisons.
-         *
-         * @param {Row} row
-         * @param {integer} pos              - Position in the `searchIndex`.
-         * @param {QueryElement} elem        - The element from the parsed query.
-         * @param {Results} results_others   - Unqualified results (not in arguments nor in
-         *                                     returned values).
-         * @param {Results} results_in_args  - Matching arguments results.
-         * @param {Results} results_returned - Matching returned arguments results.
-         */
-        function handleSingleArg(
-            row,
-            pos,
-            elem,
-            results_others,
-            results_in_args,
-            results_returned,
-            maxEditDistance,
-        ) {
-            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
-                return;
-            }
-            let path_dist = 0;
-            const fullId = row.id;
-
-            // fpDist is a minimum possible type distance, where "type distance" is the number of
-            // atoms in the function not present in the query
-            const tfpDist = compareTypeFingerprints(
-                fullId,
-                parsedQuery.typeFingerprint,
-            );
-            if (tfpDist !== null) {
-                const in_args = row.type && row.type.inputs
-                    && checkIfInList(row.type.inputs, elem, row.type.where_clause, null, 0);
-                const returned = row.type && row.type.output
-                    && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
-                if (in_args) {
-                    results_in_args.max_dist = Math.max(results_in_args.max_dist || 0, tfpDist);
-                    const maxDist = results_in_args.size < MAX_RESULTS ?
-                        (tfpDist + 1) :
-                        results_in_args.max_dist;
-                    addIntoResults(results_in_args, fullId, pos, -1, tfpDist, 0, maxDist);
-                }
-                if (returned) {
-                    results_returned.max_dist = Math.max(results_returned.max_dist || 0, tfpDist);
-                    const maxDist = results_returned.size < MAX_RESULTS ?
-                        (tfpDist + 1) :
-                        results_returned.max_dist;
-                    addIntoResults(results_returned, fullId, pos, -1, tfpDist, 0, maxDist);
-                }
-            }
-
-            if (!typePassesFilter(elem.typeFilter, row.ty)) {
-                return;
-            }
-
-            let index = row.word.indexOf(elem.pathLast);
-            const normalizedIndex = row.normalizedName.indexOf(elem.pathLast);
-            if (index === -1 || (index > normalizedIndex && normalizedIndex !== -1)) {
-                index = normalizedIndex;
-            }
-
-            if (elem.fullPath.length > 1) {
-                path_dist = checkPath(elem.pathWithoutLast, row);
-                if (path_dist === null) {
-                    return;
-                }
-            }
-
-            if (parsedQuery.literalSearch) {
-                if (row.word === elem.pathLast) {
-                    addIntoResults(results_others, fullId, pos, index, 0, path_dist);
-                }
-                return;
-            }
-
-            const dist = editDistance(row.normalizedName, elem.normalizedPathLast, maxEditDistance);
-
-            if (index === -1 && dist > maxEditDistance) {
-                return;
-            }
-
-            addIntoResults(results_others, fullId, pos, index, dist, path_dist, maxEditDistance);
-        }
-
-        /**
          * This function is called in case the query has more than one element. In this case, it'll
          * try to match the items which validates all the elements. For `aa -> bb` will look for
          * functions which have a parameter `aa` and has `bb` in its returned values.
@@ -3075,7 +3795,7 @@ class DocSearch {
                         parsedQuery.returned,
                         row.type.where_clause,
                         mgens,
-                        null,
+                        checkTypeMgensForConflict,
                         0, // unboxing depth
                     );
                 },
@@ -3178,21 +3898,25 @@ class DocSearch {
                 if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
                     && elem.generics.length === 0 && elem.bindings.size === 0)
                     || elem.typeFilter === TY_GENERIC) {
-                    if (genericSymbols.has(elem.name)) {
-                        elem.id = genericSymbols.get(elem.name);
+                    if (genericSymbols.has(elem.normalizedPathLast)) {
+                        elem.id = genericSymbols.get(elem.normalizedPathLast);
                     } else {
                         elem.id = -(genericSymbols.size + 1);
-                        genericSymbols.set(elem.name, elem.id);
+                        genericSymbols.set(elem.normalizedPathLast, elem.id);
                     }
-                    if (elem.typeFilter === -1 && elem.name.length >= 3) {
+                    if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
                         // Silly heuristic to catch if the user probably meant
                         // to not write a generic parameter. We don't use it,
                         // just bring it up.
-                        const maxPartDistance = Math.floor(elem.name.length / 3);
+                        const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
                         let matchDist = maxPartDistance + 1;
                         let matchName = "";
                         for (const name of this.typeNameIdMap.keys()) {
-                            const dist = editDistance(name, elem.name, maxPartDistance);
+                            const dist = editDistance(
+                                name,
+                                elem.normalizedPathLast,
+                                maxPartDistance,
+                            );
                             if (dist <= matchDist && dist <= maxPartDistance) {
                                 if (dist === matchDist && matchName > name) {
                                     continue;
@@ -3239,34 +3963,89 @@ class DocSearch {
                 );
             };
 
-            const fps = new Set();
             for (const elem of parsedQuery.elems) {
                 convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint, fps);
+                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
             }
             for (const elem of parsedQuery.returned) {
                 convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint, fps);
+                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
             }
 
             if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
-                if (parsedQuery.elems.length === 1) {
-                    const elem = parsedQuery.elems[0];
-                    const length = this.searchIndex.length;
-                    for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
-                        // It means we want to check for this element everywhere (in names, args and
-                        // returned).
-                        handleSingleArg(
-                            this.searchIndex[i],
-                            i,
-                            elem,
+                const elem = parsedQuery.elems[0];
+                for (const id of this.nameTrie.search(elem.normalizedPathLast, this.tailTable)) {
+                    const row = this.searchIndex[id];
+                    if (!typePassesFilter(elem.typeFilter, row.ty) ||
+                        (filterCrates !== null && row.crate !== filterCrates)) {
+                        continue;
+                    }
+
+                    let pathDist = 0;
+                    if (elem.fullPath.length > 1) {
+                        pathDist = checkPath(elem.pathWithoutLast, row);
+                        if (pathDist === null) {
+                            continue;
+                        }
+                    }
+
+                    if (parsedQuery.literalSearch) {
+                        if (row.word === elem.pathLast) {
+                            addIntoResults(results_others, row.id, id, 0, 0, pathDist);
+                        }
+                    } else {
+                        addIntoResults(
                             results_others,
-                            results_in_args,
-                            results_returned,
+                            row.id,
+                            id,
+                            row.normalizedName.indexOf(elem.normalizedPathLast),
+                            editDistance(
+                                row.normalizedName,
+                                elem.normalizedPathLast,
+                                maxEditDistance,
+                            ),
+                            pathDist,
                             maxEditDistance,
                         );
                     }
                 }
+                const length = this.searchIndex.length;
+                for (let i = 0, nSearchIndex = length; i < nSearchIndex; ++i) {
+                    const row = this.searchIndex[i];
+                    if (filterCrates !== null && row.crate !== filterCrates) {
+                        continue;
+                    }
+                    const tfpDist = compareTypeFingerprints(
+                        row.id,
+                        parsedQuery.typeFingerprint,
+                    );
+                    if (tfpDist !== null) {
+                        const in_args = row.type && row.type.inputs
+                            && checkIfInList(row.type.inputs, elem, row.type.where_clause, null, 0);
+                        const returned = row.type && row.type.output
+                            && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
+                        if (in_args) {
+                            results_in_args.max_dist = Math.max(
+                                results_in_args.max_dist || 0,
+                                tfpDist,
+                            );
+                            const maxDist = results_in_args.size < MAX_RESULTS ?
+                                (tfpDist + 1) :
+                                results_in_args.max_dist;
+                            addIntoResults(results_in_args, row.id, i, -1, tfpDist, 0, maxDist);
+                        }
+                        if (returned) {
+                            results_returned.max_dist = Math.max(
+                                results_returned.max_dist || 0,
+                                tfpDist,
+                            );
+                            const maxDist = results_returned.size < MAX_RESULTS ?
+                                (tfpDist + 1) :
+                                results_returned.max_dist;
+                            addIntoResults(results_returned, row.id, i, -1, tfpDist, 0, maxDist);
+                        }
+                    }
+                }
             } else if (parsedQuery.foundElems > 0) {
                 // Sort input and output so that generic type variables go first and
                 // types with generic parameters go last.
@@ -3294,17 +4073,18 @@ class DocSearch {
             innerRunQuery();
         }
 
+        const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
         const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
-            sortResults(results_in_args, true, currentCrate),
-            sortResults(results_returned, true, currentCrate),
-            sortResults(results_others, false, currentCrate),
+            sortResults(results_in_args, "elems", currentCrate),
+            sortResults(results_returned, "returned", currentCrate),
+            sortResults(results_others, (isType ? "query" : null), currentCrate),
         ]);
         const ret = createQueryResults(
             sorted_in_args,
             sorted_returned,
             sorted_others,
             parsedQuery);
-        await handleAliases(ret, parsedQuery.original.replace(/"/g, ""),
+        await handleAliases(ret, parsedQuery.userQuery.replace(/"/g, ""),
             filterCrates, currentCrate);
         await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => {
             const descs = await Promise.all(list.map(result => {
@@ -3324,6 +4104,7 @@ class DocSearch {
     }
 }
 
+
 // ==================== Core search logic end ====================
 
 let rawSearchIndex;
@@ -3455,15 +4236,18 @@ function focusSearchResult() {
  * @param {Array<?>}    array   - The search results for this tab
  * @param {ParsedQuery} query
  * @param {boolean}     display - True if this is the active tab
+ * @param {"sig"|"elems"|"returned"|null} typeInfo
  */
 async function addTab(array, query, display) {
     const extraClass = display ? " active" : "";
 
-    const output = document.createElement("div");
+    const output = document.createElement(
+        array.length === 0 && query.error === null ? "div" : "ul",
+    );
     if (array.length > 0) {
         output.className = "search-results " + extraClass;
 
-        for (const item of array) {
+        const lis = Promise.all(array.map(async item => {
             const name = item.name;
             const type = itemTypes[item.ty];
             const longType = longItemTypes[item.ty];
@@ -3473,7 +4257,7 @@ async function addTab(array, query, display) {
             link.className = "result-" + type;
             link.href = item.href;
 
-            const resultName = document.createElement("div");
+            const resultName = document.createElement("span");
             resultName.className = "result-name";
 
             resultName.insertAdjacentHTML(
@@ -3496,10 +4280,73 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             const description = document.createElement("div");
             description.className = "desc";
             description.insertAdjacentHTML("beforeend", item.desc);
+            if (item.displayTypeSignature) {
+                const {type, mappedNames, whereClause} = await item.displayTypeSignature;
+                const displayType = document.createElement("div");
+                type.forEach((value, index) => {
+                    if (index % 2 !== 0) {
+                        const highlight = document.createElement("strong");
+                        highlight.appendChild(document.createTextNode(value));
+                        displayType.appendChild(highlight);
+                    } else {
+                        displayType.appendChild(document.createTextNode(value));
+                    }
+                });
+                if (mappedNames.size > 0 || whereClause.size > 0) {
+                    let addWhereLineFn = () => {
+                        const line = document.createElement("div");
+                        line.className = "where";
+                        line.appendChild(document.createTextNode("where"));
+                        displayType.appendChild(line);
+                        addWhereLineFn = () => {};
+                    };
+                    for (const [qname, name] of mappedNames) {
+                        // don't care unless the generic name is different
+                        if (name === qname) {
+                            continue;
+                        }
+                        addWhereLineFn();
+                        const line = document.createElement("div");
+                        line.className = "where";
+                        line.appendChild(document.createTextNode(`    ${qname} matches `));
+                        const lineStrong = document.createElement("strong");
+                        lineStrong.appendChild(document.createTextNode(name));
+                        line.appendChild(lineStrong);
+                        displayType.appendChild(line);
+                    }
+                    for (const [name, innerType] of whereClause) {
+                        // don't care unless there's at least one highlighted entry
+                        if (innerType.length <= 1) {
+                            continue;
+                        }
+                        addWhereLineFn();
+                        const line = document.createElement("div");
+                        line.className = "where";
+                        line.appendChild(document.createTextNode(`    ${name}: `));
+                        innerType.forEach((value, index) => {
+                            if (index % 2 !== 0) {
+                                const highlight = document.createElement("strong");
+                                highlight.appendChild(document.createTextNode(value));
+                                line.appendChild(highlight);
+                            } else {
+                                line.appendChild(document.createTextNode(value));
+                            }
+                        });
+                        displayType.appendChild(line);
+                    }
+                }
+                displayType.className = "type-signature";
+                link.appendChild(displayType);
+            }
 
             link.appendChild(description);
-            output.appendChild(link);
-        }
+            return link;
+        }));
+        lis.then(lis => {
+            for (const li of lis) {
+                output.appendChild(li);
+            }
+        });
     } else if (query.error === null) {
         output.className = "search-failed" + extraClass;
         output.innerHTML = "No results :(<br/>" +
@@ -3516,7 +4363,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             "href=\"https://docs.rs\">Docs.rs</a> for documentation of crates released on" +
             " <a href=\"https://crates.io/\">crates.io</a>.</li></ul>";
     }
-    return [output, array.length];
+    return output;
 }
 
 function makeTabHeader(tabNb, text, nbElems) {
@@ -3573,24 +4420,18 @@ async function showResults(results, go_to_first, filterCrates) {
 
     currentResults = results.query.userQuery;
 
-    const [ret_others, ret_in_args, ret_returned] = await Promise.all([
-        addTab(results.others, results.query, true),
-        addTab(results.in_args, results.query, false),
-        addTab(results.returned, results.query, false),
-    ]);
-
     // Navigate to the relevant tab if the current tab is empty, like in case users search
     // for "-> String". If they had selected another tab previously, they have to click on
     // it again.
     let currentTab = searchState.currentTab;
-    if ((currentTab === 0 && ret_others[1] === 0) ||
-        (currentTab === 1 && ret_in_args[1] === 0) ||
-        (currentTab === 2 && ret_returned[1] === 0)) {
-        if (ret_others[1] !== 0) {
+    if ((currentTab === 0 && results.others.length === 0) ||
+        (currentTab === 1 && results.in_args.length === 0) ||
+        (currentTab === 2 && results.returned.length === 0)) {
+        if (results.others.length !== 0) {
             currentTab = 0;
-        } else if (ret_in_args[1] !== 0) {
+        } else if (results.in_args.length) {
             currentTab = 1;
-        } else if (ret_returned[1] !== 0) {
+        } else if (results.returned.length) {
             currentTab = 2;
         }
     }
@@ -3619,14 +4460,14 @@ async function showResults(results, go_to_first, filterCrates) {
         });
         output += `<h3 class="error">Query parser error: "${error.join("")}".</h3>`;
         output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, "In Names", ret_others[1]) +
+            makeTabHeader(0, "In Names", results.others.length) +
             "</div>";
         currentTab = 0;
     } else if (results.query.foundElems <= 1 && results.query.returned.length === 0) {
         output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, "In Names", ret_others[1]) +
-            makeTabHeader(1, "In Parameters", ret_in_args[1]) +
-            makeTabHeader(2, "In Return Types", ret_returned[1]) +
+            makeTabHeader(0, "In Names", results.others.length) +
+            makeTabHeader(1, "In Parameters", results.in_args.length) +
+            makeTabHeader(2, "In Return Types", results.returned.length) +
             "</div>";
     } else {
         const signatureTabTitle =
@@ -3634,7 +4475,7 @@ async function showResults(results, go_to_first, filterCrates) {
                 results.query.returned.length === 0 ? "In Function Parameters" :
                     "In Function Signatures";
         output += "<div id=\"search-tabs\">" +
-            makeTabHeader(0, signatureTabTitle, ret_others[1]) +
+            makeTabHeader(0, signatureTabTitle, results.others.length) +
             "</div>";
         currentTab = 0;
     }
@@ -3656,11 +4497,17 @@ async function showResults(results, go_to_first, filterCrates) {
             `Consider searching for "${targ}" instead.</h3>`;
     }
 
+    const [ret_others, ret_in_args, ret_returned] = await Promise.all([
+        addTab(results.others, results.query, currentTab === 0),
+        addTab(results.in_args, results.query, currentTab === 1),
+        addTab(results.returned, results.query, currentTab === 2),
+    ]);
+
     const resultsElem = document.createElement("div");
     resultsElem.id = "results";
-    resultsElem.appendChild(ret_others[0]);
-    resultsElem.appendChild(ret_in_args[0]);
-    resultsElem.appendChild(ret_returned[0]);
+    resultsElem.appendChild(ret_others);
+    resultsElem.appendChild(ret_in_args);
+    resultsElem.appendChild(ret_returned);
 
     search.innerHTML = output;
     if (searchState.rustdocToolbar) {
@@ -3724,11 +4571,11 @@ async function search(forced) {
     }
 
     // Update document title to maintain a meaningful browser history
-    searchState.title = "\"" + query.original + "\" Search - Rust";
+    searchState.title = "\"" + query.userQuery + "\" Search - Rust";
 
     // Because searching is incremental by character, only the most
     // recent search query is added to the browser history.
-    updateSearchHistory(buildUrl(query.original, filterCrates));
+    updateSearchHistory(buildUrl(query.userQuery, filterCrates));
 
     await showResults(
         await docSearch.execQuery(query, filterCrates, window.currentCrate),
@@ -3942,4 +4789,477 @@ if (typeof window !== "undefined") {
     // exports.
     initSearch(new Map());
 }
-})();
+
+// Parts of this code are based on Lucene, which is licensed under the
+// Apache/2.0 license.
+// More information found here:
+// https://fossies.org/linux/lucene/lucene/core/src/java/org/apache/lucene/util/automaton/
+//   LevenshteinAutomata.java
+class ParametricDescription {
+    constructor(w, n, minErrors) {
+        this.w = w;
+        this.n = n;
+        this.minErrors = minErrors;
+    }
+    isAccept(absState) {
+        const state = Math.floor(absState / (this.w + 1));
+        const offset = absState % (this.w + 1);
+        return this.w - offset + this.minErrors[state] <= this.n;
+    }
+    getPosition(absState) {
+        return absState % (this.w + 1);
+    }
+    getVector(name, charCode, pos, end) {
+        let vector = 0;
+        for (let i = pos; i < end; i += 1) {
+            vector = vector << 1;
+            if (name.charCodeAt(i) === charCode) {
+                vector |= 1;
+            }
+        }
+        return vector;
+    }
+    unpack(data, index, bitsPerValue) {
+        const bitLoc = (bitsPerValue * index);
+        const dataLoc = bitLoc >> 5;
+        const bitStart = bitLoc & 31;
+        if (bitStart + bitsPerValue <= 32) {
+            // not split
+            return ((data[dataLoc] >> bitStart) & this.MASKS[bitsPerValue - 1]);
+        } else {
+            // split
+            const part = 32 - bitStart;
+            return ~~(((data[dataLoc] >> bitStart) & this.MASKS[part - 1]) +
+                ((data[1 + dataLoc] & this.MASKS[bitsPerValue - part - 1]) << part));
+        }
+    }
+}
+ParametricDescription.prototype.MASKS = new Int32Array([
+    0x1, 0x3, 0x7, 0xF,
+    0x1F, 0x3F, 0x7F, 0xFF,
+    0x1FF, 0x3F, 0x7FF, 0xFFF,
+    0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF,
+    0x1FFFF, 0x3FFFF, 0x7FFFF, 0xFFFFF,
+    0x1FFFFF, 0x3FFFFF, 0x7FFFFF, 0xFFFFFF,
+    0x1FFFFFF, 0x3FFFFFF, 0x7FFFFFF, 0xFFFFFFF,
+    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF,
+]);
+
+// The following code was generated with the moman/finenight pkg
+// This package is available under the MIT License, see NOTICE.txt
+// for more details.
+// This class is auto-generated, Please do not modify it directly.
+// You should modify the https://gitlab.com/notriddle/createAutomata.py instead.
+// The following code was generated with the moman/finenight pkg
+// This package is available under the MIT License, see NOTICE.txt
+// for more details.
+// This class is auto-generated, Please do not modify it directly.
+// You should modify https://gitlab.com/notriddle/moman-rustdoc instead.
+
+class Lev2TParametricDescription extends ParametricDescription {
+    /**
+     * @param {number} absState
+     * @param {number} position
+     * @param {number} vector
+     * @returns {number}
+    */
+    transition(absState, position, vector) {
+        let state = Math.floor(absState / (this.w + 1));
+        let offset = absState % (this.w + 1);
+
+        if (position === this.w) {
+            if (state < 3) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 3) + state;
+                offset += this.unpack(this.offsetIncrs0, loc, 1);
+                state = this.unpack(this.toStates0, loc, 2) - 1;
+            }
+        } else if (position === this.w - 1) {
+            if (state < 5) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 5) + state;
+                offset += this.unpack(this.offsetIncrs1, loc, 1);
+                state = this.unpack(this.toStates1, loc, 3) - 1;
+            }
+        } else if (position === this.w - 2) {
+            if (state < 13) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 13) + state;
+                offset += this.unpack(this.offsetIncrs2, loc, 2);
+                state = this.unpack(this.toStates2, loc, 4) - 1;
+            }
+        } else if (position === this.w - 3) {
+            if (state < 28) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 28) + state;
+                offset += this.unpack(this.offsetIncrs3, loc, 2);
+                state = this.unpack(this.toStates3, loc, 5) - 1;
+            }
+        } else if (position === this.w - 4) {
+            if (state < 45) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 45) + state;
+                offset += this.unpack(this.offsetIncrs4, loc, 3);
+                state = this.unpack(this.toStates4, loc, 6) - 1;
+            }
+        } else {
+            if (state < 45) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 45) + state;
+                offset += this.unpack(this.offsetIncrs5, loc, 3);
+                state = this.unpack(this.toStates5, loc, 6) - 1;
+            }
+        }
+
+        if (state === -1) {
+            // null state
+            return -1;
+        } else {
+            // translate back to abs
+            return Math.imul(state, this.w + 1) + offset;
+        }
+    }
+
+    // state map
+    //   0 -> [(0, 0)]
+    //   1 -> [(0, 1)]
+    //   2 -> [(0, 2)]
+    //   3 -> [(0, 1), (1, 1)]
+    //   4 -> [(0, 2), (1, 2)]
+    //   5 -> [(0, 1), (1, 1), (2, 1)]
+    //   6 -> [(0, 2), (1, 2), (2, 2)]
+    //   7 -> [(0, 1), (2, 1)]
+    //   8 -> [(0, 1), (2, 2)]
+    //   9 -> [(0, 2), (2, 1)]
+    //   10 -> [(0, 2), (2, 2)]
+    //   11 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
+    //   12 -> [t(0, 2), (0, 2), (1, 2), (2, 2)]
+    //   13 -> [(0, 2), (1, 2), (2, 2), (3, 2)]
+    //   14 -> [(0, 1), (1, 1), (3, 2)]
+    //   15 -> [(0, 1), (2, 2), (3, 2)]
+    //   16 -> [(0, 1), (3, 2)]
+    //   17 -> [(0, 1), t(1, 2), (2, 2), (3, 2)]
+    //   18 -> [(0, 2), (1, 2), (3, 1)]
+    //   19 -> [(0, 2), (1, 2), (3, 2)]
+    //   20 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2)]
+    //   21 -> [(0, 2), (2, 1), (3, 1)]
+    //   22 -> [(0, 2), (2, 2), (3, 2)]
+    //   23 -> [(0, 2), (3, 1)]
+    //   24 -> [(0, 2), (3, 2)]
+    //   25 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2)]
+    //   26 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2)]
+    //   27 -> [t(0, 2), (0, 2), (1, 2), (3, 1)]
+    //   28 -> [(0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   29 -> [(0, 2), (1, 2), (2, 2), (4, 2)]
+    //   30 -> [(0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
+    //   31 -> [(0, 2), (1, 2), (3, 2), (4, 2)]
+    //   32 -> [(0, 2), (1, 2), (4, 2)]
+    //   33 -> [(0, 2), (1, 2), t(1, 2), (2, 2), (3, 2), (4, 2)]
+    //   34 -> [(0, 2), (1, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
+    //   35 -> [(0, 2), (2, 1), (4, 2)]
+    //   36 -> [(0, 2), (2, 2), (3, 2), (4, 2)]
+    //   37 -> [(0, 2), (2, 2), (4, 2)]
+    //   38 -> [(0, 2), (3, 2), (4, 2)]
+    //   39 -> [(0, 2), (4, 2)]
+    //   40 -> [(0, 2), t(1, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   41 -> [(0, 2), t(2, 2), (2, 2), (3, 2), (4, 2)]
+    //   42 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (3, 2), (4, 2)]
+    //   43 -> [t(0, 2), (0, 2), (1, 2), (2, 2), (4, 2)]
+    //   44 -> [t(0, 2), (0, 2), (1, 2), (2, 2), t(2, 2), (3, 2), (4, 2)]
+
+
+    /** @param {number} w - length of word being checked */
+    constructor(w) {
+        super(w, 2, new Int32Array([
+            0,1,2,0,1,-1,0,-1,0,-1,0,-1,0,-1,-1,-1,-1,-1,-2,-1,-1,-2,-1,-2,
+            -1,-1,-1,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,-2,
+        ]));
+    }
+}
+
+Lev2TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
+    0xe,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
+    0x0,
+]);
+
+Lev2TParametricDescription.prototype.toStates1 = /*3 bits per value */ new Int32Array([
+    0x1a688a2c,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
+    0x3e0,
+]);
+
+Lev2TParametricDescription.prototype.toStates2 = /*4 bits per value */ new Int32Array([
+    0x70707054,0xdc07035,0x3dd3a3a,0x2323213a,
+    0x15435223,0x22545432,0x5435,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
+    0x80000,0x55582088,0x55555555,0x55,
+]);
+
+Lev2TParametricDescription.prototype.toStates3 = /*5 bits per value */ new Int32Array([
+    0x1c0380a4,0x700a570,0xca529c0,0x180a00,
+    0xa80af180,0xc5498e60,0x5a546398,0x8c4300e8,
+    0xac18c601,0xd8d43501,0x863500ad,0x51976d6a,
+    0x8ca0180a,0xc3501ac2,0xb0c5be16,0x76dda8a5,
+    0x18c4519,0xc41294a,0xe248d231,0x1086520c,
+    0xce31ac42,0x13946358,0x2d0348c4,0x6732d494,
+    0x1ad224a5,0xd635ad4b,0x520c4139,0xce24948,
+    0x22110a52,0x58ce729d,0xc41394e3,0x941cc520,
+    0x90e732d4,0x4729d224,0x39ce35ad,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
+    0x80000,0xc0c830,0x300f3c30,0x2200fcff,
+    0xcaa00a08,0x3c2200a8,0xa8fea00a,0x55555555,
+    0x55555555,0x55555555,0x55555555,0x55555555,
+    0x55555555,0x55555555,
+]);
+
+Lev2TParametricDescription.prototype.toStates4 = /*6 bits per value */ new Int32Array([
+    0x801c0144,0x1453803,0x14700038,0xc0005145,
+    0x1401,0x14,0x140000,0x0,
+    0x510000,0x6301f007,0x301f00d1,0xa186178,
+    0xc20ca0c3,0xc20c30,0xc30030c,0xc00c00cd,
+    0xf0c00c30,0x4c054014,0xc30944c3,0x55150c34,
+    0x8300550,0x430c0143,0x50c31,0xc30850c,
+    0xc3143000,0x50053c50,0x5130d301,0x850d30c2,
+    0x30a08608,0xc214414,0x43142145,0x21450031,
+    0x1400c314,0x4c143145,0x32832803,0x28014d6c,
+    0xcd34a0c3,0x1c50c76,0x1c314014,0x430c30c3,
+    0x1431,0xc300500,0xca00d303,0xd36d0e40,
+    0x90b0e400,0xcb2abb2c,0x70c20ca1,0x2c32ca2c,
+    0xcd2c70cb,0x31c00c00,0x34c2c32c,0x5583280,
+    0x558309b7,0x6cd6ca14,0x430850c7,0x51c51401,
+    0x1430c714,0xc3087,0x71451450,0xca00d30,
+    0xc26dc156,0xb9071560,0x1cb2abb2,0xc70c2144,
+    0xb1c51ca1,0x1421c70c,0xc51c00c3,0x30811c51,
+    0x24324308,0xc51031c2,0x70820820,0x5c33830d,
+    0xc33850c3,0x30c30c30,0xc30c31c,0x451450c3,
+    0x20c20c20,0xda0920d,0x5145914f,0x36596114,
+    0x51965865,0xd9643653,0x365a6590,0x51964364,
+    0x43081505,0x920b2032,0x2c718b28,0xd7242249,
+    0x35cb28b0,0x2cb3872c,0x972c30d7,0xb0c32cb2,
+    0x4e1c75c,0xc80c90c2,0x62ca2482,0x4504171c,
+    0xd65d9610,0x33976585,0xd95cb5d,0x4b5ca5d7,
+    0x73975c36,0x10308138,0xc2245105,0x41451031,
+    0x14e24208,0xc35c3387,0x51453851,0x1c51c514,
+    0xc70c30c3,0x20451450,0x14f1440c,0x4f0da092,
+    0x4513d41,0x6533944d,0x1350e658,0xe1545055,
+    0x64365a50,0x5519383,0x51030815,0x28920718,
+    0x441c718b,0x714e2422,0x1c35cb28,0x4e1c7387,
+    0xb28e1c51,0x5c70c32c,0xc204e1c7,0x81c61440,
+    0x1c62ca24,0xd04503ce,0x85d63944,0x39338e65,
+    0x8e154387,0x364b5ca3,0x38739738,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs4 = /*3 bits per value */ new Int32Array([
+    0x10000000,0xc00000,0x60061,0x400,
+    0x0,0x80010008,0x249248a4,0x8229048,
+    0x2092,0x6c3603,0xb61b6c30,0x6db6036d,
+    0xdb6c0,0x361b0180,0x91b72000,0xdb11b71b,
+    0x6db6236,0x1008200,0x12480012,0x24924906,
+    0x48200049,0x80410002,0x24000900,0x4924a489,
+    0x10822492,0x20800125,0x48360,0x9241b692,
+    0x6da4924,0x40009268,0x241b010,0x291b4900,
+    0x6d249249,0x49493423,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x2492,
+]);
+
+Lev2TParametricDescription.prototype.toStates5 = /*6 bits per value */ new Int32Array([
+    0x801c0144,0x1453803,0x14700038,0xc0005145,
+    0x1401,0x14,0x140000,0x0,
+    0x510000,0x4e00e007,0xe0051,0x3451451c,
+    0xd015000,0x30cd0000,0xc30c30c,0xc30c30d4,
+    0x40c30c30,0x7c01c014,0xc03458c0,0x185e0c07,
+    0x2830c286,0x830c3083,0xc30030,0x33430c,
+    0x30c3003,0x70051030,0x16301f00,0x8301f00d,
+    0x30a18617,0xc20ca0c,0x431420c3,0xb1450c51,
+    0x14314315,0x4f143145,0x34c05401,0x4c30944c,
+    0x55150c3,0x30830055,0x1430c014,0xc00050c3,
+    0xc30850,0xc314300,0x150053c5,0x25130d30,
+    0x5430d30c,0xc0354154,0x300d0c90,0x1cb2cd0c,
+    0xc91cb0c3,0x72c30cb2,0x14f1cb2c,0xc34c0540,
+    0x34c30944,0x82182214,0x851050c2,0x50851430,
+    0x1400c50c,0x30c5085,0x50c51450,0x150053c,
+    0xc25130d3,0x8850d30,0x1430a086,0x450c2144,
+    0x51cb1c21,0x1c91c70c,0xc71c314b,0x34c1cb1,
+    0x6c328328,0xc328014d,0x76cd34a0,0x1401c50c,
+    0xc31c3140,0x31430c30,0x14,0x30c3005,
+    0xa0ca00d3,0x535b0c,0x4d2830ca,0x514369b3,
+    0xc500d01,0x5965965a,0x30d46546,0x6435030c,
+    0x8034c659,0xdb439032,0x2c390034,0xcaaecb24,
+    0x30832872,0xcb28b1c,0x4b1c32cb,0x70030033,
+    0x30b0cb0c,0xe40ca00d,0x400d36d0,0xb2c90b0e,
+    0xca1cb2ab,0xa2c70c20,0x6575d95c,0x4315b5ce,
+    0x95c53831,0x28034c5d,0x9b705583,0xa1455830,
+    0xc76cd6c,0x40143085,0x71451c51,0x871430c,
+    0x450000c3,0xd3071451,0x1560ca00,0x560c26dc,
+    0xb35b2851,0xc914369,0x1a14500d,0x46593945,
+    0xcb2c939,0x94507503,0x328034c3,0x9b70558,
+    0xe41c5583,0x72caaeca,0x1c308510,0xc7147287,
+    0x50871c32,0x1470030c,0xd307147,0xc1560ca0,
+    0x1560c26d,0xabb2b907,0x21441cb2,0x38a1c70c,
+    0x8e657394,0x314b1c93,0x39438738,0x43083081,
+    0x31c22432,0x820c510,0x830d7082,0x50c35c33,
+    0xc30c338,0xc31c30c3,0x50c30c30,0xc204514,
+    0x890c90c2,0x31440c70,0xa8208208,0xea0df0c3,
+    0x8a231430,0xa28a28a2,0x28a28a1e,0x1861868a,
+    0x48308308,0xc3682483,0x14516453,0x4d965845,
+    0xd4659619,0x36590d94,0xd969964,0x546590d9,
+    0x20c20541,0x920d20c,0x5914f0da,0x96114514,
+    0x65865365,0xe89d3519,0x99e7a279,0x9e89e89e,
+    0x81821827,0xb2032430,0x18b28920,0x422492c7,
+    0xb28b0d72,0x3872c35c,0xc30d72cb,0x32cb2972,
+    0x1c75cb0c,0xc90c204e,0xa2482c80,0x24b1c62c,
+    0xc3a89089,0xb0ea2e42,0x9669a31c,0xa4966a28,
+    0x59a8a269,0x8175e7a,0xb203243,0x718b2892,
+    0x4114105c,0x17597658,0x74ce5d96,0x5c36572d,
+    0xd92d7297,0xe1ce5d70,0xc90c204,0xca2482c8,
+    0x4171c62,0x5d961045,0x976585d6,0x79669533,
+    0x964965a2,0x659689e6,0x308175e7,0x24510510,
+    0x451031c2,0xe2420841,0x5c338714,0x453851c3,
+    0x51c51451,0xc30c31c,0x451450c7,0x41440c20,
+    0xc708914,0x82105144,0xf1c58c90,0x1470ea0d,
+    0x61861863,0x8a1e85e8,0x8687a8a2,0x3081861,
+    0x24853c51,0x5053c368,0x1341144f,0x96194ce5,
+    0x1544d439,0x94385514,0xe0d90d96,0x5415464,
+    0x4f1440c2,0xf0da0921,0x4513d414,0x533944d0,
+    0x350e6586,0x86082181,0xe89e981d,0x18277689,
+    0x10308182,0x89207185,0x41c718b2,0x14e24224,
+    0xc35cb287,0xe1c73871,0x28e1c514,0xc70c32cb,
+    0x204e1c75,0x1c61440c,0xc62ca248,0x90891071,
+    0x2e41c58c,0xa31c70ea,0xe86175e7,0xa269a475,
+    0x5e7a57a8,0x51030817,0x28920718,0xf38718b,
+    0xe5134114,0x39961758,0xe1ce4ce,0x728e3855,
+    0x5ce0d92d,0xc204e1ce,0x81c61440,0x1c62ca24,
+    0xd04503ce,0x85d63944,0x75338e65,0x5d86075e,
+    0x89e69647,0x75e76576,
+]);
+Lev2TParametricDescription.prototype.offsetIncrs5 = /*3 bits per value */ new Int32Array([
+    0x10000000,0xc00000,0x60061,0x400,
+    0x0,0x60000008,0x6b003080,0xdb6ab6db,
+    0x2db6,0x800400,0x49245240,0x11482412,
+    0x104904,0x40020000,0x92292000,0xa4b25924,
+    0x9649658,0xd80c000,0xdb0c001b,0x80db6d86,
+    0x6db01b6d,0xc0600003,0x86000d86,0x6db6c36d,
+    0xddadb6ed,0x300001b6,0x6c360,0xe37236e4,
+    0x46db6236,0xdb6c,0x361b018,0xb91b7200,
+    0x6dbb1b71,0x6db763,0x20100820,0x61248001,
+    0x92492490,0x24820004,0x8041000,0x92400090,
+    0x24924830,0x555b6a49,0x2080012,0x20004804,
+    0x49252449,0x84112492,0x4000928,0x240201,
+    0x92922490,0x58924924,0x49456,0x120d8082,
+    0x6da4800,0x69249249,0x249a01b,0x6c04100,
+    0x6d240009,0x92492483,0x24d5adb4,0x60208001,
+    0x92000483,0x24925236,0x6846da49,0x10400092,
+    0x241b0,0x49291b49,0x636d2492,0x92494935,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,0x49249249,
+    0x92492492,0x24924924,0x49249249,0x92492492,
+    0x24924924,0x49249249,0x92492492,0x24924924,
+    0x49249249,0x92492492,0x24924924,
+]);
+
+class Lev1TParametricDescription extends ParametricDescription {
+    /**
+     * @param {number} absState
+     * @param {number} position
+     * @param {number} vector
+     * @returns {number}
+    */
+    transition(absState, position, vector) {
+        let state = Math.floor(absState / (this.w + 1));
+        let offset = absState % (this.w + 1);
+
+        if (position === this.w) {
+            if (state < 2) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 2) + state;
+                offset += this.unpack(this.offsetIncrs0, loc, 1);
+                state = this.unpack(this.toStates0, loc, 2) - 1;
+            }
+        } else if (position === this.w - 1) {
+            if (state < 3) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 3) + state;
+                offset += this.unpack(this.offsetIncrs1, loc, 1);
+                state = this.unpack(this.toStates1, loc, 2) - 1;
+            }
+        } else if (position === this.w - 2) {
+            if (state < 6) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 6) + state;
+                offset += this.unpack(this.offsetIncrs2, loc, 2);
+                state = this.unpack(this.toStates2, loc, 3) - 1;
+            }
+        } else {
+            if (state < 6) { // eslint-disable-line no-lonely-if
+                const loc = Math.imul(vector, 6) + state;
+                offset += this.unpack(this.offsetIncrs3, loc, 2);
+                state = this.unpack(this.toStates3, loc, 3) - 1;
+            }
+        }
+
+        if (state === -1) {
+            // null state
+            return -1;
+        } else {
+            // translate back to abs
+            return Math.imul(state, this.w + 1) + offset;
+        }
+    }
+
+    // state map
+    //   0 -> [(0, 0)]
+    //   1 -> [(0, 1)]
+    //   2 -> [(0, 1), (1, 1)]
+    //   3 -> [(0, 1), (1, 1), (2, 1)]
+    //   4 -> [(0, 1), (2, 1)]
+    //   5 -> [t(0, 1), (0, 1), (1, 1), (2, 1)]
+
+
+    /** @param {number} w - length of word being checked */
+    constructor(w) {
+        super(w, 1, new Int32Array([0,1,0,-1,-1,-1]));
+    }
+}
+
+Lev1TParametricDescription.prototype.toStates0 = /*2 bits per value */ new Int32Array([
+    0x2,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs0 = /*1 bits per value */ new Int32Array([
+    0x0,
+]);
+
+Lev1TParametricDescription.prototype.toStates1 = /*2 bits per value */ new Int32Array([
+    0xa43,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs1 = /*1 bits per value */ new Int32Array([
+    0x38,
+]);
+
+Lev1TParametricDescription.prototype.toStates2 = /*3 bits per value */ new Int32Array([
+    0x12180003,0xb45a4914,0x69,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs2 = /*2 bits per value */ new Int32Array([
+    0x558a0000,0x5555,
+]);
+
+Lev1TParametricDescription.prototype.toStates3 = /*3 bits per value */ new Int32Array([
+    0x900c0003,0xa1904864,0x45a49169,0x5a6d196a,
+    0x9634,
+]);
+Lev1TParametricDescription.prototype.offsetIncrs3 = /*2 bits per value */ new Int32Array([
+    0xa0fc0000,0x5555ba08,0x55555555,
+]);
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index 78dc0b8e2f9..436d36d899e 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -206,7 +206,7 @@ fn init_logging(early_dcx: &EarlyDiagCtxt) {
         .with_verbose_exit(true)
         .with_verbose_entry(true)
         .with_indent_amount(2);
-    #[cfg(all(parallel_compiler, debug_assertions))]
+    #[cfg(debug_assertions)]
     let layer = layer.with_thread_ids(true).with_thread_names(true);
 
     use tracing_subscriber::layer::SubscriberExt;
diff --git a/src/tools/bump-stage0/Cargo.toml b/src/tools/bump-stage0/Cargo.toml
index de5d821133d..6ee7a831839 100644
--- a/src/tools/bump-stage0/Cargo.toml
+++ b/src/tools/bump-stage0/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0.34"
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 curl = "0.4.38"
 indexmap = { version = "2.0.0", features = ["serde"] }
 serde = { version = "1.0.125", features = ["derive"] }
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 161fa630ed4..dd3124ee9a3 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6071,6 +6071,7 @@ Released 2018-09-13
 [`unnecessary_literal_bound`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_bound
 [`unnecessary_literal_unwrap`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_literal_unwrap
 [`unnecessary_map_on_constructor`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_on_constructor
+[`unnecessary_map_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_map_or
 [`unnecessary_min_or_max`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_min_or_max
 [`unnecessary_mut_passed`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed
 [`unnecessary_operation`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_operation
diff --git a/src/tools/clippy/clippy_dev/src/setup/vscode.rs b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
index 204f4af2cf1..a37c873eed4 100644
--- a/src/tools/clippy/clippy_dev/src/setup/vscode.rs
+++ b/src/tools/clippy/clippy_dev/src/setup/vscode.rs
@@ -84,7 +84,7 @@ fn delete_vs_task_file(path: &Path) -> bool {
 /// It may fail silently.
 fn try_delete_vs_directory_if_empty() {
     let path = Path::new(VSCODE_DIR);
-    if path.read_dir().map_or(false, |mut iter| iter.next().is_none()) {
+    if path.read_dir().is_ok_and(|mut iter| iter.next().is_none()) {
         // The directory is empty. We just try to delete it but allow a silence
         // fail as an empty `.vscode` directory is still valid
         let _silence_result = fs::remove_dir(path);
diff --git a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
index dc5a6857089..e21853598c3 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/useless_attribute.rs
@@ -16,7 +16,7 @@ pub(super) fn check(cx: &EarlyContext<'_>, item: &Item, attrs: &[Attribute]) {
             return;
         }
         if let Some(lint_list) = &attr.meta_item_list() {
-            if attr.ident().map_or(false, |ident| is_lint_level(ident.name, attr.id)) {
+            if attr.ident().is_some_and(|ident| is_lint_level(ident.name, attr.id)) {
                 for lint in lint_list {
                     match item.kind {
                         ItemKind::Use(..) => {
diff --git a/src/tools/clippy/clippy_lints/src/attrs/utils.rs b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
index 9b10ae83651..3bb02688bf2 100644
--- a/src/tools/clippy/clippy_lints/src/attrs/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs/utils.rs
@@ -50,7 +50,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
         block
             .expr
             .as_ref()
-            .map_or(false, |e| is_relevant_expr(cx, typeck_results, e)),
+            .is_some_and(|e| is_relevant_expr(cx, typeck_results, e)),
         |stmt| match &stmt.kind {
             StmtKind::Let(_) => true,
             StmtKind::Expr(expr) | StmtKind::Semi(expr) => is_relevant_expr(cx, typeck_results, expr),
@@ -60,7 +60,7 @@ fn is_relevant_block(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_
 }
 
 fn is_relevant_expr(cx: &LateContext<'_>, typeck_results: &ty::TypeckResults<'_>, expr: &Expr<'_>) -> bool {
-    if macro_backtrace(expr.span).last().map_or(false, |macro_call| {
+    if macro_backtrace(expr.span).last().is_some_and(|macro_call| {
         is_panic(cx, macro_call.def_id) || cx.tcx.item_name(macro_call.def_id) == sym::unreachable
     }) {
         return false;
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index db5792188dd..7d89195eeca 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -60,8 +60,8 @@ fn is_impl_not_trait_with_bool_out<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -
                 trait_id,
             )
         })
-        .map_or(false, |assoc_item| {
-            let proj = Ty::new_projection_from_args(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
+        .is_some_and(|assoc_item| {
+            let proj = Ty::new_projection(cx.tcx, assoc_item.def_id, cx.tcx.mk_args_trait(ty, []));
             let nty = cx.tcx.normalize_erasing_regions(cx.param_env, proj);
 
             nty.is_bool()
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 26a20bc99a0..896bd5fd03d 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -667,5 +667,5 @@ fn implements_ord(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     let ty = cx.typeck_results().expr_ty(expr);
     cx.tcx
         .get_diagnostic_item(sym::Ord)
-        .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+        .is_some_and(|id| implements_trait(cx, ty, id, &[]))
 }
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index bf1d077fec2..a1ca23e65ff 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -45,7 +45,7 @@ impl LateLintPass<'_> for BoxDefault {
             // And that method is `new`
             && seg.ident.name == sym::new
             // And the call is that of a `Box` method
-            && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box())
+            && path_def_id(cx, ty).is_some_and(|id| Some(id) == cx.tcx.lang_items().owned_box())
             // And the single argument to the call is another function call
             // This is the `T::default()` (or default equivalent) of `Box::new(T::default())`
             && let ExprKind::Call(arg_path, _) = arg.kind
@@ -83,9 +83,9 @@ fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
 }
 
 fn is_local_vec_expn(cx: &LateContext<'_>, expr: &Expr<'_>, ref_expr: &Expr<'_>) -> bool {
-    macro_backtrace(expr.span).next().map_or(false, |call| {
-        cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span)
-    })
+    macro_backtrace(expr.span)
+        .next()
+        .is_some_and(|call| cx.tcx.is_diagnostic_item(sym::vec_macro, call.def_id) && call.span.eq_ctxt(ref_expr.span))
 }
 
 #[derive(Default)]
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index abd80abffe6..332e897def7 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -159,8 +159,7 @@ pub(super) fn check<'tcx>(
         // The same is true if the expression encompassing the cast expression is a unary
         // expression or an addressof expression.
         let needs_block = matches!(cast_expr.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..))
-            || get_parent_expr(cx, expr)
-                .map_or(false, |e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
+            || get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Unary(..) | ExprKind::AddrOf(..)));
 
         span_lint_and_sugg(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/comparison_chain.rs b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
index b9baf9af248..c85e3500ebd 100644
--- a/src/tools/clippy/clippy_lints/src/comparison_chain.rs
+++ b/src/tools/clippy/clippy_lints/src/comparison_chain.rs
@@ -110,7 +110,7 @@ impl<'tcx> LateLintPass<'tcx> for ComparisonChain {
                 let is_ord = cx
                     .tcx
                     .get_diagnostic_item(sym::Ord)
-                    .map_or(false, |id| implements_trait(cx, ty, id, &[]));
+                    .is_some_and(|id| implements_trait(cx, ty, id, &[]));
 
                 if !is_ord {
                     return;
diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs
index c4afdc757d8..3ecd36d3711 100644
--- a/src/tools/clippy/clippy_lints/src/copies.rs
+++ b/src/tools/clippy/clippy_lints/src/copies.rs
@@ -345,7 +345,7 @@ fn eq_binding_names(s: &Stmt<'_>, names: &[(HirId, Symbol)]) -> bool {
         let mut i = 0usize;
         let mut res = true;
         l.pat.each_binding_or_first(&mut |_, _, _, name| {
-            if names.get(i).map_or(false, |&(_, n)| n == name.name) {
+            if names.get(i).is_some_and(|&(_, n)| n == name.name) {
                 i += 1;
             } else {
                 res = false;
@@ -389,12 +389,10 @@ fn eq_stmts(
         let new_bindings = &moved_bindings[old_count..];
         blocks
             .iter()
-            .all(|b| get_stmt(b).map_or(false, |s| eq_binding_names(s, new_bindings)))
+            .all(|b| get_stmt(b).is_some_and(|s| eq_binding_names(s, new_bindings)))
     } else {
         true
-    }) && blocks
-        .iter()
-        .all(|b| get_stmt(b).map_or(false, |s| eq.eq_stmt(s, stmt)))
+    }) && blocks.iter().all(|b| get_stmt(b).is_some_and(|s| eq.eq_stmt(s, stmt)))
 }
 
 #[expect(clippy::too_many_lines)]
@@ -451,9 +449,7 @@ fn scan_block_for_eq<'tcx>(
     //     x + 50
     let expr_hash_eq = if let Some(e) = block.expr {
         let hash = hash_expr(cx, e);
-        blocks
-            .iter()
-            .all(|b| b.expr.map_or(false, |e| hash_expr(cx, e) == hash))
+        blocks.iter().all(|b| b.expr.is_some_and(|e| hash_expr(cx, e) == hash))
     } else {
         blocks.iter().all(|b| b.expr.is_none())
     };
@@ -514,7 +510,7 @@ fn scan_block_for_eq<'tcx>(
         });
     if let Some(e) = block.expr {
         for block in blocks {
-            if block.expr.map_or(false, |expr| !eq.eq_expr(expr, e)) {
+            if block.expr.is_some_and(|expr| !eq.eq_expr(expr, e)) {
                 moved_locals.truncate(moved_locals_at_start);
                 return BlockEq {
                     start_end_eq,
@@ -533,7 +529,7 @@ fn scan_block_for_eq<'tcx>(
 }
 
 fn check_for_warn_of_moved_symbol(cx: &LateContext<'_>, symbols: &[(HirId, Symbol)], if_expr: &Expr<'_>) -> bool {
-    get_enclosing_block(cx, if_expr.hir_id).map_or(false, |block| {
+    get_enclosing_block(cx, if_expr.hir_id).is_some_and(|block| {
         let ignore_span = block.span.shrink_to_lo().to(if_expr.span);
 
         symbols
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index edb52851e0c..dff60f76b74 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -481,6 +481,7 @@ pub static LINTS: &[&crate::LintInfo] = &[
     crate::methods::UNNECESSARY_JOIN_INFO,
     crate::methods::UNNECESSARY_LAZY_EVALUATIONS_INFO,
     crate::methods::UNNECESSARY_LITERAL_UNWRAP_INFO,
+    crate::methods::UNNECESSARY_MAP_OR_INFO,
     crate::methods::UNNECESSARY_MIN_OR_MAX_INFO,
     crate::methods::UNNECESSARY_RESULT_MAP_OR_ELSE_INFO,
     crate::methods::UNNECESSARY_SORT_BY_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index 4808c372754..ef6b141920d 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -253,6 +253,6 @@ impl<'tcx> From<Ty<'tcx>> for ExplicitTyBound {
 
 impl<'tcx> From<Option<Ty<'tcx>>> for ExplicitTyBound {
     fn from(v: Option<Ty<'tcx>>) -> Self {
-        Self(v.map_or(false, Ty::is_numeric))
+        Self(v.is_some_and(Ty::is_numeric))
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index 2b6bfafe695..767dda552bc 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -81,7 +81,7 @@ fn is_path_self(e: &Expr<'_>) -> bool {
 fn contains_trait_object(ty: Ty<'_>) -> bool {
     match ty.kind() {
         ty::Ref(_, ty, _) => contains_trait_object(*ty),
-        ty::Adt(def, args) => def.is_box() && args[0].as_type().map_or(false, contains_trait_object),
+        ty::Adt(def, args) => def.is_box() && args[0].as_type().is_some_and(contains_trait_object),
         ty::Dynamic(..) => true,
         _ => false,
     }
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index e569c4dc786..0db6a822ec0 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -327,7 +327,7 @@ fn check_copy_clone<'tcx>(cx: &LateContext<'tcx>, item: &Item<'_>, trait_ref: &h
     // there's a Copy impl for any instance of the adt.
     if !is_copy(cx, ty) {
         if ty_subs.non_erasable_generics().next().is_some() {
-            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).map_or(false, |impls| {
+            let has_copy_impl = cx.tcx.all_local_trait_impls(()).get(&copy_id).is_some_and(|impls| {
                 impls.iter().any(|&id| {
                     matches!(cx.tcx.type_of(id).instantiate_identity().kind(), ty::Adt(adt, _)
                                         if ty_adt.did() == adt.did())
diff --git a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
index c9173030a55..40377dd841e 100644
--- a/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
+++ b/src/tools/clippy/clippy_lints/src/doc/missing_headers.rs
@@ -47,7 +47,7 @@ pub fn check(
         ),
         _ => (),
     }
-    if !headers.panics && panic_info.map_or(false, |el| !el.1) {
+    if !headers.panics && panic_info.is_some_and(|el| !el.1) {
         span_lint_and_note(
             cx,
             MISSING_PANICS_DOC,
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index c7dd7292a14..55afdbf22e1 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
                             MEM_FORGET,
                             Cow::Owned(format!(
                                 "usage of `mem::forget` on {}",
-                                if arg_ty.ty_adt_def().map_or(false, |def| def.has_dtor(cx.tcx)) {
+                                if arg_ty.ty_adt_def().is_some_and(|def| def.has_dtor(cx.tcx)) {
                                     "`Drop` type"
                                 } else {
                                     "type with `Drop` fields"
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index de10b7bf533..6c87a05ace3 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -196,7 +196,7 @@ fn check_clousure<'tcx>(cx: &LateContext<'tcx>, outer_receiver: Option<&Expr<'tc
             {
                 span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
                     if let Some(mut snippet) = snippet_opt(cx, callee.span) {
-                        if path_to_local(callee).map_or(false, |l| {
+                        if path_to_local(callee).is_some_and(|l| {
                             // FIXME: Do we really need this `local_used_in` check?
                             // Isn't it checking something like... `callee(callee)`?
                             // If somehow this check is needed, add some test for it,
diff --git a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
index c2b40ae01d4..4986a311eba 100644
--- a/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/not_unsafe_ptr_arg_deref.rs
@@ -87,7 +87,7 @@ fn raw_ptr_arg(cx: &LateContext<'_>, arg: &hir::Param<'_>) -> Option<HirId> {
 }
 
 fn check_arg(cx: &LateContext<'_>, raw_ptrs: &HirIdSet, arg: &hir::Expr<'_>) {
-    if path_to_local(arg).map_or(false, |id| raw_ptrs.contains(&id)) {
+    if path_to_local(arg).is_some_and(|id| raw_ptrs.contains(&id)) {
         span_lint(
             cx,
             NOT_UNSAFE_PTR_ARG_DEREF,
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index 48874d6064b..d3aade31f14 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -171,13 +171,13 @@ fn is_infinite(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
             if let ExprKind::Path(ref qpath) = path.kind {
                 cx.qpath_res(qpath, path.hir_id)
                     .opt_def_id()
-                    .map_or(false, |id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id))
+                    .is_some_and(|id| cx.tcx.is_diagnostic_item(sym::iter_repeat, id))
                     .into()
             } else {
                 Finite
             }
         },
-        ExprKind::Struct(..) => higher::Range::hir(expr).map_or(false, |r| r.end.is_none()).into(),
+        ExprKind::Struct(..) => higher::Range::hir(expr).is_some_and(|r| r.end.is_none()).into(),
         _ => Finite,
     }
 }
@@ -228,9 +228,7 @@ fn complete_infinite_iter(cx: &LateContext<'_>, expr: &Expr<'_>) -> Finiteness {
                 let not_double_ended = cx
                     .tcx
                     .get_diagnostic_item(sym::DoubleEndedIterator)
-                    .map_or(false, |id| {
-                        !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[])
-                    });
+                    .is_some_and(|id| !implements_trait(cx, cx.typeck_results().expr_ty(receiver), id, &[]));
                 if not_double_ended {
                     return is_infinite(cx, receiver);
                 }
diff --git a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index dd90e2a6e94..6363f717a5c 100644
--- a/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -309,8 +309,8 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>
     let item_name_chars = item_name.chars().count();
 
     if count_match_start(item_name, name).char_count == item_name_chars
-        && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase())
-        && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric())
+        && name.chars().nth(item_name_chars).is_some_and(|c| !c.is_lowercase())
+        && name.chars().nth(item_name_chars + 1).is_some_and(|c| !c.is_numeric())
     {
         span_lint_hir(
             cx,
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index b19b348c743..25105817ad9 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -75,7 +75,7 @@ fn check_sig(cx: &LateContext<'_>, name: Symbol, sig: &FnSig<'_>, fn_id: LocalDe
         if cx
             .tcx
             .get_diagnostic_item(sym::Iterator)
-            .map_or(false, |iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
+            .is_some_and(|iter_id| !implements_trait(cx, ret_ty, iter_id, &[]))
         {
             span_lint(
                 cx,
diff --git a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
index aa8b4d88d2f..c5a2760234f 100644
--- a/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_const_arrays.rs
@@ -56,7 +56,8 @@ impl<'tcx> LateLintPass<'tcx> for LargeConstArrays {
             && !item.span.from_expansion()
             && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
             && let ty::Array(element_type, cst) = ty.kind()
-            && let Ok((_, ty::ValTree::Leaf(element_count))) = cst.eval_valtree(cx.tcx, ParamEnv::empty(), item.span)
+            && let Some((ty::ValTree::Leaf(element_count), _)) = cx.tcx
+                .try_normalize_erasing_regions(ParamEnv::empty(), *cst).unwrap_or(*cst).try_to_valtree()
             && let element_count = element_count.to_target_usize(cx.tcx)
             && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
             && u128::from(self.maximum_allowed_size) < u128::from(element_count) * u128::from(element_size)
diff --git a/src/tools/clippy/clippy_lints/src/large_include_file.rs b/src/tools/clippy/clippy_lints/src/large_include_file.rs
index ab3d19f89c3..4f22931a4de 100644
--- a/src/tools/clippy/clippy_lints/src/large_include_file.rs
+++ b/src/tools/clippy/clippy_lints/src/large_include_file.rs
@@ -94,6 +94,8 @@ impl LateLintPass<'_> for LargeIncludeFile {
             // Currently, rustc limits the usage of macro at the top-level of attributes,
             // so we don't need to recurse into each level.
             && let AttrKind::Normal(ref normal) = attr.kind
+            && let Some(doc) = attr.doc_str()
+            && doc.as_str().len() as u64 > self.max_file_size
             && let AttrArgs::Eq(_, AttrArgsEq::Hir(ref meta)) = normal.item.args
             && !attr.span.contains(meta.span)
             // Since the `include_str` is already expanded at this point, we can only take the
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index b7887ef76a5..3ea758e176f 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -622,7 +622,7 @@ fn has_is_empty(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
     let ty = &cx.typeck_results().expr_ty(expr).peel_refs();
     match ty.kind() {
-        ty::Dynamic(tt, ..) => tt.principal().map_or(false, |principal| {
+        ty::Dynamic(tt, ..) => tt.principal().is_some_and(|principal| {
             let is_empty = sym!(is_empty);
             cx.tcx
                 .associated_items(principal.def_id())
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index d55be2b036a..ce0e1a24a7b 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -737,7 +737,7 @@ fn elision_suggestions(
     suggestions.extend(
         usages
             .iter()
-            .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
+            .filter(|usage| named_lifetime(usage).is_some_and(|id| elidable_lts.contains(&id)))
             .map(|usage| {
                 match cx.tcx.parent_hir_node(usage.hir_id) {
                     Node::Ty(Ty {
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index bfe2e68b5d1..1721f569541 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(
             .tcx
             .lang_items()
             .copy_trait()
-            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+            .is_some_and(|id| implements_trait(cx, ty, id, &[]))
         {
             snippet.push_str(
                 &format!(
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
index af089451759..701567a7d84 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs
@@ -416,7 +416,7 @@ fn get_assignments<'a, 'tcx>(
         .chain(*expr)
         .filter(move |e| {
             if let ExprKind::AssignOp(_, place, _) = e.kind {
-                path_to_local(place).map_or(false, |id| {
+                path_to_local(place).is_some_and(|id| {
                     !loop_counters
                         .iter()
                         // skip the first item which should be `StartKind::Range`
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index 094b1947324..39e5e140b7a 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -126,7 +126,7 @@ impl BreakAfterExprVisitor {
             break_after_expr: false,
         };
 
-        get_enclosing_block(cx, hir_id).map_or(false, |block| {
+        get_enclosing_block(cx, hir_id).is_some_and(|block| {
             visitor.visit_block(block);
             visitor.break_after_expr
         })
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index d255fea3af2..951ebc9caef 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -50,7 +50,7 @@ pub(super) fn check<'tcx>(
             .tcx
             .lang_items()
             .clone_trait()
-            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+            .is_some_and(|id| implements_trait(cx, ty, id, &[]))
     {
         // Make sure that the push does not involve possibly mutating values
         match pushed_item.kind {
diff --git a/src/tools/clippy/clippy_lints/src/loops/utils.rs b/src/tools/clippy/clippy_lints/src/loops/utils.rs
index c4c504e1ae4..51fde5288ab 100644
--- a/src/tools/clippy/clippy_lints/src/loops/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/utils.rs
@@ -256,9 +256,10 @@ fn is_conditional(expr: &Expr<'_>) -> bool {
 /// If `arg` was the argument to a `for` loop, return the "cleanest" way of writing the
 /// actual `Iterator` that the loop uses.
 pub(super) fn make_iterator_snippet(cx: &LateContext<'_>, arg: &Expr<'_>, applic_ref: &mut Applicability) -> String {
-    let impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
-        implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[])
-    });
+    let impls_iterator = cx
+        .tcx
+        .get_diagnostic_item(sym::Iterator)
+        .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(arg), id, &[]));
     if impls_iterator {
         format!(
             "{}",
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index fd66cacdfe9..016ec7320a6 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -226,7 +226,7 @@ impl TypeClampability {
         } else if cx
             .tcx
             .get_diagnostic_item(sym::Ord)
-            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+            .is_some_and(|id| implements_trait(cx, ty, id, &[]))
         {
             Some(TypeClampability::Ord)
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 828c5a3f6ff..3f401eff6bd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -162,9 +162,9 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t
         ..
     }) = expr.kind
     {
-        constant_length(cx, pattern).map_or(false, |length| *n == length)
+        constant_length(cx, pattern).is_some_and(|length| *n == length)
     } else {
-        len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg))
+        len_arg(cx, expr).is_some_and(|arg| eq_expr_value(cx, pattern, arg))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
index 6d62b530ae7..47472ab831f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs
@@ -74,7 +74,7 @@ where
         && b0 != b1
         && (first_guard.is_none() || iter.len() == 0)
         && first_attrs.is_empty()
-        && iter.all(|arm| find_bool_lit(&arm.2.kind).map_or(false, |b| b == b0) && arm.3.is_none() && arm.0.is_empty())
+        && iter.all(|arm| find_bool_lit(&arm.2.kind).is_some_and(|b| b == b0) && arm.3.is_none() && arm.0.is_empty())
     {
         if let Some(last_pat) = last_pat_opt {
             if !is_wild(last_pat) {
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index ca45ed6ea59..264458a86ef 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -447,7 +447,7 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte
             .tcx
             .lang_items()
             .get(expected_lang_item)
-            .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id),
+            .is_some_and(|expected_id| cx.tcx.parent(id) == expected_id),
         Item::Diag(expected_ty, expected_variant) => {
             let ty = cx.typeck_results().pat_ty(pat);
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 2aea25b5f12..95a4bf6f60d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -175,7 +175,7 @@ impl<'tcx> Visitor<'tcx> for PatVisitor<'tcx> {
         if matches!(pat.kind, PatKind::Binding(..)) {
             ControlFlow::Break(())
         } else {
-            self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().map_or(false, AdtDef::is_enum);
+            self.has_enum |= self.typeck.pat_ty(pat).ty_adt_def().is_some_and(AdtDef::is_enum);
             walk_pat(self, pat)
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/matches/try_err.rs b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
index c7e1b70d19e..6c02207af49 100644
--- a/src/tools/clippy/clippy_lints/src/matches/try_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/try_err.rs
@@ -58,7 +58,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, scrutine
                 let span = hygiene::walk_chain(err_arg.span, try_arg.span.ctxt());
                 let mut applicability = Applicability::MachineApplicable;
                 let origin_snippet = snippet_with_applicability(cx, span, "_", &mut applicability);
-                let ret_prefix = if get_parent_expr(cx, expr).map_or(false, |e| matches!(e.kind, ExprKind::Ret(_))) {
+                let ret_prefix = if get_parent_expr(cx, expr).is_some_and(|e| matches!(e.kind, ExprKind::Ret(_))) {
                     "" // already returns
                 } else {
                     "return "
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index c288dbdabe9..6dc48c26ba9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -83,7 +83,7 @@ pub(super) fn check<'tcx>(
             hir::ExprKind::MethodCall(..) => {
                 cx.typeck_results()
                     .type_dependent_def_id(arg.hir_id)
-                    .map_or(false, |method_id| {
+                    .is_some_and(|method_id| {
                         matches!(
                             cx.tcx.fn_sig(method_id).instantiate_identity().output().skip_binder().kind(),
                             ty::Ref(re, ..) if re.is_static()
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
index e697ba656f5..6c1a14fc882 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_next.rs
@@ -32,9 +32,10 @@ pub(super) fn check<'tcx>(
     filter_arg: &'tcx hir::Expr<'_>,
 ) {
     // lint if caller of `.filter().next()` is an Iterator
-    let recv_impls_iterator = cx.tcx.get_diagnostic_item(sym::Iterator).map_or(false, |id| {
-        implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[])
-    });
+    let recv_impls_iterator = cx
+        .tcx
+        .get_diagnostic_item(sym::Iterator)
+        .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(recv), id, &[]));
     if recv_impls_iterator {
         let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
                    `.find(..)` instead";
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
index 5f3fec53827..9a03559b223 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs
@@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(
     if cx
         .tcx
         .get_diagnostic_item(sym::DoubleEndedIterator)
-        .map_or(false, |double_ended_iterator| {
-            implements_trait(cx, rev_recv_ty, double_ended_iterator, &[])
-        })
+        .is_some_and(|double_ended_iterator| implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]))
         && is_trait_method(cx, rev_call, sym::Iterator)
         && is_trait_method(cx, expr, sym::Iterator)
     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
index 61e74369cb0..098721dc046 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_str_repeat.rs
@@ -36,8 +36,8 @@ fn parse_repeat_arg(cx: &LateContext<'_>, e: &Expr<'_>) -> Option<RepeatKind> {
     } else {
         let ty = cx.typeck_results().expr_ty(e);
         if is_type_lang_item(cx, ty, LangItem::String)
-            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).map_or(false, Ty::is_str))
-            || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).map_or(false, Ty::is_str))
+            || (is_type_lang_item(cx, ty, LangItem::OwnedBox) && get_ty_param(ty).is_some_and(Ty::is_str))
+            || (is_type_diagnostic_item(cx, ty, sym::Cow) && get_ty_param(ty).is_some_and(Ty::is_str))
         {
             Some(RepeatKind::String)
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 515d4a11ed5..d5594b21db5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -70,7 +70,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &hir::Expr<'_>, recv: &hir::Expr<'_
                                 if ident_eq(name, obj) && method.ident.name == sym::clone
                                 && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
                                 && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
-                                && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
+                                && cx.tcx.lang_items().clone_trait() == Some(trait_id)
                                 // no autoderefs
                                 && !cx.typeck_results().expr_adjustments(obj).iter()
                                     .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index b1809796355..795e041ffd9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -121,6 +121,7 @@ mod unnecessary_iter_cloned;
 mod unnecessary_join;
 mod unnecessary_lazy_eval;
 mod unnecessary_literal_unwrap;
+mod unnecessary_map_or;
 mod unnecessary_min_or_max;
 mod unnecessary_result_map_or_else;
 mod unnecessary_sort_by;
@@ -4101,6 +4102,33 @@ declare_clippy_lint! {
 
 declare_clippy_lint! {
     /// ### What it does
+    /// Converts some constructs mapping an Enum value for equality comparison.
+    ///
+    /// ### Why is this bad?
+    /// Calls such as `opt.map_or(false, |val| val == 5)` are needlessly long and cumbersome,
+    /// and can be reduced to, for example, `opt == Some(5)` assuming `opt` implements `PartialEq`.
+    /// This lint offers readability and conciseness improvements.
+    ///
+    /// ### Example
+    /// ```no_run
+    /// pub fn a(x: Option<i32>) -> bool {
+    ///     x.map_or(false, |n| n == 5)
+    /// }
+    /// ```
+    /// Use instead:
+    /// ```no_run
+    /// pub fn a(x: Option<i32>) -> bool {
+    ///     x == Some(5)
+    /// }
+    /// ```
+    #[clippy::version = "1.75.0"]
+    pub UNNECESSARY_MAP_OR,
+    style,
+    "reduce unnecessary pattern matching for constructs that implement `PartialEq`"
+}
+
+declare_clippy_lint! {
+    /// ### What it does
     /// Checks if an iterator is used to check if a string is ascii.
     ///
     /// ### Why is this bad?
@@ -4417,6 +4445,7 @@ impl_lint_pass!(Methods => [
     NEEDLESS_AS_BYTES,
     MAP_ALL_ANY_IDENTITY,
     MAP_WITH_UNUSED_ARGUMENT_OVER_RANGES,
+    UNNECESSARY_MAP_OR,
 ]);
 
 /// Extracts a method call name, args, and `Span` of the method name.
@@ -4950,6 +4979,7 @@ impl Methods {
                     option_map_or_none::check(cx, expr, recv, def, map);
                     manual_ok_or::check(cx, expr, recv, def, map);
                     option_map_or_err_ok::check(cx, expr, recv, def, map);
+                    unnecessary_map_or::check(cx, expr, recv, def, map, &self.msrv);
                 },
                 ("map_or_else", [def, map]) => {
                     result_map_or_else_none::check(cx, expr, recv, def, map);
@@ -5343,7 +5373,7 @@ impl SelfKind {
                 boxed_ty == parent_ty
             } else if is_type_diagnostic_item(cx, ty, sym::Rc) || is_type_diagnostic_item(cx, ty, sym::Arc) {
                 if let ty::Adt(_, args) = ty.kind() {
-                    args.types().next().map_or(false, |t| t == parent_ty)
+                    args.types().next() == Some(parent_ty)
                 } else {
                     false
                 }
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index 055107068ae..9c41528e647 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -193,7 +193,7 @@ fn check_collect_into_intoiterator<'tcx>(
 
 /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool`
 fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
-    cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| {
+    cx.typeck_results().type_dependent_def_id(call_id).is_some_and(|id| {
         let sig = cx.tcx.fn_sig(id).instantiate_identity().skip_binder();
         sig.inputs().len() == 1 && sig.output().is_bool()
     })
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 389e02056b2..998bdee0157 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -45,7 +45,7 @@ pub(super) fn check(
         hir::ExprKind::Path(ref expr_qpath) => {
             cx.qpath_res(expr_qpath, map_arg.hir_id)
                 .opt_def_id()
-                .map_or(false, |fun_def_id| {
+                .is_some_and(|fun_def_id| {
                     cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
                         || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id)
                         || deref_aliases
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index b685a466b72..6b39b753885 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -59,9 +59,7 @@ pub(super) fn check<'tcx>(
                 let output_ty = cx.tcx.fn_sig(def_id).instantiate(cx.tcx, args).skip_binder().output();
                 cx.tcx
                     .get_diagnostic_item(sym::Default)
-                    .map_or(false, |default_trait_id| {
-                        implements_trait(cx, output_ty, default_trait_id, &[])
-                    })
+                    .is_some_and(|default_trait_id| implements_trait(cx, output_ty, default_trait_id, &[]))
             } else {
                 false
             }
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index a2a7de905ca..1cee28e1986 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -348,7 +348,7 @@ fn parse_iter_usage<'tcx>(
                     && cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| is_diag_item_method(cx, id, sym::Option)) =>
+                        .is_some_and(|id| is_diag_item_method(cx, id, sym::Option)) =>
             {
                 (Some(UnwrapKind::Unwrap), e.span)
             },
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
new file mode 100644
index 00000000000..adc27cd437f
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_map_or.rs
@@ -0,0 +1,131 @@
+use std::borrow::Cow;
+
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::eager_or_lazy::switch_to_eager_eval;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::sugg::{Sugg, make_binop};
+use clippy_utils::ty::{get_type_diagnostic_name, implements_trait};
+use clippy_utils::visitors::is_local_used;
+use clippy_utils::{is_from_proc_macro, path_to_local_id};
+use rustc_ast::LitKind::Bool;
+use rustc_errors::Applicability;
+use rustc_hir::{BinOpKind, Expr, ExprKind, PatKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::UNNECESSARY_MAP_OR;
+
+pub(super) enum Variant {
+    Ok,
+    Some,
+}
+impl Variant {
+    pub fn variant_name(&self) -> &'static str {
+        match self {
+            Variant::Ok => "Ok",
+            Variant::Some => "Some",
+        }
+    }
+
+    pub fn method_name(&self) -> &'static str {
+        match self {
+            Variant::Ok => "is_ok_and",
+            Variant::Some => "is_some_and",
+        }
+    }
+}
+
+pub(super) fn check<'a>(
+    cx: &LateContext<'a>,
+    expr: &Expr<'a>,
+    recv: &Expr<'_>,
+    def: &Expr<'_>,
+    map: &Expr<'_>,
+    msrv: &Msrv,
+) {
+    let ExprKind::Lit(def_kind) = def.kind else {
+        return;
+    };
+
+    let recv_ty = cx.typeck_results().expr_ty(recv);
+
+    let Bool(def_bool) = def_kind.node else {
+        return;
+    };
+
+    let variant = match get_type_diagnostic_name(cx, recv_ty) {
+        Some(sym::Option) => Variant::Some,
+        Some(sym::Result) => Variant::Ok,
+        Some(_) | None => return,
+    };
+
+    let (sugg, method) = if let ExprKind::Closure(map_closure) = map.kind
+            && let closure_body = cx.tcx.hir().body(map_closure.body)
+            && let closure_body_value = closure_body.value.peel_blocks()
+            && let ExprKind::Binary(op, l, r) = closure_body_value.kind
+            && let Some(param) = closure_body.params.first()
+            && let PatKind::Binding(_, hir_id, _, _) = param.pat.kind
+            // checking that map_or is one of the following:
+            // .map_or(false, |x| x == y)
+            // .map_or(false, |x| y == x) - swapped comparison
+            // .map_or(true, |x| x != y)
+            // .map_or(true, |x| y != x) - swapped comparison
+            && ((BinOpKind::Eq == op.node && !def_bool) || (BinOpKind::Ne == op.node && def_bool))
+            && let non_binding_location = if path_to_local_id(l, hir_id) { r } else { l }
+            && switch_to_eager_eval(cx, non_binding_location)
+            // xor, because if its both then thats a strange edge case and
+            // we can just ignore it, since by default clippy will error on this
+            && (path_to_local_id(l, hir_id) ^ path_to_local_id(r, hir_id))
+            && !is_local_used(cx, non_binding_location, hir_id)
+            && let typeck_results = cx.typeck_results()
+            && typeck_results.expr_ty(l) == typeck_results.expr_ty(r)
+            && let Some(partial_eq) = cx.tcx.get_diagnostic_item(sym::PartialEq)
+            && implements_trait(cx, recv_ty, partial_eq, &[recv_ty.into()])
+    {
+        let wrap = variant.variant_name();
+
+        // we may need to add parens around the suggestion
+        // in case the parent expression has additional method calls,
+        // since for example `Some(5).map_or(false, |x| x == 5).then(|| 1)`
+        // being converted to `Some(5) == Some(5).then(|| 1)` isnt
+        // the same thing
+
+        let inner_non_binding = Sugg::NonParen(Cow::Owned(format!(
+            "{wrap}({})",
+            Sugg::hir(cx, non_binding_location, "")
+        )));
+
+        let binop = make_binop(op.node, &Sugg::hir(cx, recv, ".."), &inner_non_binding)
+            .maybe_par()
+            .into_string();
+
+        (binop, "a standard comparison")
+    } else if !def_bool
+        && msrv.meets(msrvs::OPTION_RESULT_IS_VARIANT_AND)
+        && let Some(recv_callsite) = snippet_opt(cx, recv.span.source_callsite())
+        && let Some(span_callsite) = snippet_opt(cx, map.span.source_callsite())
+    {
+        let suggested_name = variant.method_name();
+        (
+            format!("{recv_callsite}.{suggested_name}({span_callsite})",),
+            suggested_name,
+        )
+    } else {
+        return;
+    };
+
+    if is_from_proc_macro(cx, expr) {
+        return;
+    }
+
+    span_lint_and_sugg(
+        cx,
+        UNNECESSARY_MAP_OR,
+        expr.span,
+        "this `map_or` is redundant",
+        format!("use {method} instead"),
+        sugg,
+        Applicability::MaybeIncorrect,
+    );
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
index 6911da69b94..603916e06c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_sort_by.rs
@@ -166,9 +166,10 @@ fn detect_lint(cx: &LateContext<'_>, expr: &Expr<'_>, recv: &Expr<'_>, arg: &Exp
             },
         )) = &left_expr.kind
             && left_name == left_ident
-            && cx.tcx.get_diagnostic_item(sym::Ord).map_or(false, |id| {
-                implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[])
-            })
+            && cx
+                .tcx
+                .get_diagnostic_item(sym::Ord)
+                .is_some_and(|id| implements_trait(cx, cx.typeck_results().expr_ty(left_expr), id, &[]))
         {
             return Some(LintTrigger::Sort(SortDetection { vec_name }));
         }
diff --git a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
index c309e778116..82313257e5c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/useless_asref.rs
@@ -124,7 +124,7 @@ fn is_calling_clone(cx: &LateContext<'_>, arg: &hir::Expr<'_>) -> bool {
                         && let Some(fn_id) = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id)
                         && let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
                         // We check it's the `Clone` trait.
-                        && cx.tcx.lang_items().clone_trait().map_or(false, |id| id == trait_id)
+                        && cx.tcx.lang_items().clone_trait().is_some_and(|id| id == trait_id)
                         // no autoderefs
                         && !cx.typeck_results().expr_adjustments(obj).iter()
                             .any(|a| matches!(a.kind, Adjust::Deref(Some(..))))
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index 4cba13a05c2..37d7427f9a5 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -427,7 +427,7 @@ impl MiscEarlyLints {
         // See <https://github.com/rust-lang/rust-clippy/issues/4507> for a regression.
         // FIXME: Find a better way to detect those cases.
         let lit_snip = match snippet_opt(cx, span) {
-            Some(snip) if snip.chars().next().map_or(false, |c| c.is_ascii_digit()) => snip,
+            Some(snip) if snip.chars().next().is_some_and(|c| c.is_ascii_digit()) => snip,
             _ => return,
         };
 
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index f7fa31d83aa..c1424b9f1dc 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -134,9 +134,11 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
     }
 
     fn check_body_post(&mut self, cx: &LateContext<'tcx>, body: &Body<'_>) {
-        if self.possible_borrowers.last().map_or(false, |&(local_def_id, _)| {
-            local_def_id == cx.tcx.hir().body_owner_def_id(body.id())
-        }) {
+        if self
+            .possible_borrowers
+            .last()
+            .is_some_and(|&(local_def_id, _)| local_def_id == cx.tcx.hir().body_owner_def_id(body.id()))
+        {
             self.possible_borrowers.pop();
         }
     }
@@ -232,7 +234,7 @@ fn needless_borrow_count<'tcx>(
     let mut check_reference_and_referent = |reference: &Expr<'tcx>, referent: &Expr<'tcx>| {
         if let ExprKind::Field(base, _) = &referent.kind {
             let base_ty = cx.typeck_results().expr_ty(base);
-            if drop_trait_def_id.map_or(false, |id| implements_trait(cx, base_ty, id, &[])) {
+            if drop_trait_def_id.is_some_and(|id| implements_trait(cx, base_ty, id, &[])) {
                 return false;
             }
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index c4836772933..c48232f9905 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -153,7 +153,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
 }
 
 fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
-    block.stmts.first().map_or(false, |stmt| match stmt.kind {
+    block.stmts.first().is_some_and(|stmt| match stmt.kind {
         ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
             if let ast::ExprKind::Continue(ref l) = e.kind {
                 compare_labels(label, l.as_ref())
@@ -390,7 +390,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
 #[must_use]
 fn erode_from_back(s: &str) -> String {
     let mut ret = s.to_string();
-    while ret.pop().map_or(false, |c| c != '}') {}
+    while ret.pop().is_some_and(|c| c != '}') {}
     while let Some(c) = ret.pop() {
         if !c.is_whitespace() {
             ret.push(c);
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index a13391a5945..83f7d931969 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -88,7 +88,7 @@ fn is_offending_macro(cx: &EarlyContext<'_>, span: Span, mac_braces: &MacroBrace
             || span
                 .macro_backtrace()
                 .last()
-                .map_or(false, |e| e.macro_def_id.map_or(false, DefId::is_local))
+                .is_some_and(|e| e.macro_def_id.is_some_and(DefId::is_local))
     };
     let span_call_site = span.ctxt().outer_expn_data().call_site;
     if let ExpnKind::Macro(MacroKind::Bang, mac_name) = span.ctxt().outer_expn_data().kind
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 372128ac16f..13b3d240700 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -290,7 +290,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                     Some((Node::Expr(parent), child_id)) => match parent.kind {
                         // Recursive call. Track which index the parameter is used in.
                         ExprKind::Call(callee, args)
-                            if path_def_id(cx, callee).map_or(false, |id| {
+                            if path_def_id(cx, callee).is_some_and(|id| {
                                 id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
                             }) =>
                         {
@@ -300,7 +300,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
                             return;
                         },
                         ExprKind::MethodCall(_, receiver, args, _)
-                            if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
+                            if typeck.type_dependent_def_id(parent.hir_id).is_some_and(|id| {
                                 id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id))
                             }) =>
                         {
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index 8b9f899d82d..65ef56fd211 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -325,7 +325,7 @@ impl ArithmeticSideEffects {
     fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool {
         is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
             || self.expr_span.is_some()
-            || self.const_span.map_or(false, |sp| sp.contains(expr.span))
+            || self.const_span.is_some_and(|sp| sp.contains(expr.span))
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index 208b20a7a06..b0d872e98fd 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -42,14 +42,12 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
             if typeck
                 .type_dependent_def_id(expr.hir_id)
                 .and_then(|id| cx.tcx.trait_of_item(id))
-                .map_or(false, |id| {
-                    matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))
-                }) =>
+                .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ToString | sym::ToOwned))) =>
         {
             (arg, arg.span)
         },
         ExprKind::Call(path, [arg])
-            if path_def_id(cx, path).map_or(false, |did| {
+            if path_def_id(cx, path).is_some_and(|did| {
                 if cx.tcx.is_diagnostic_item(sym::from_str_method, did) {
                     true
                 } else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 830be50c8ba..1c2d6e90fc9 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -42,83 +42,43 @@ pub(crate) fn check<'tcx>(
 
     match op {
         BinOpKind::Add | BinOpKind::BitOr | BinOpKind::BitXor => {
-            let _ = check_op(
-                cx,
-                left,
-                0,
-                expr.span,
-                peeled_right_span,
-                needs_parenthesis(cx, expr, right),
-                right_is_coerced_to_value,
-            ) || check_op(
-                cx,
-                right,
-                0,
-                expr.span,
-                peeled_left_span,
-                Parens::Unneeded,
-                left_is_coerced_to_value,
-            );
+            if is_redundant_op(cx, left, 0) {
+                let paren = needs_parenthesis(cx, expr, right);
+                span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value);
+            } else if is_redundant_op(cx, right, 0) {
+                let paren = needs_parenthesis(cx, expr, left);
+                span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value);
+            }
         },
         BinOpKind::Shl | BinOpKind::Shr | BinOpKind::Sub => {
-            let _ = check_op(
-                cx,
-                right,
-                0,
-                expr.span,
-                peeled_left_span,
-                Parens::Unneeded,
-                left_is_coerced_to_value,
-            );
+            if is_redundant_op(cx, right, 0) {
+                let paren = needs_parenthesis(cx, expr, left);
+                span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value);
+            }
         },
         BinOpKind::Mul => {
-            let _ = check_op(
-                cx,
-                left,
-                1,
-                expr.span,
-                peeled_right_span,
-                needs_parenthesis(cx, expr, right),
-                right_is_coerced_to_value,
-            ) || check_op(
-                cx,
-                right,
-                1,
-                expr.span,
-                peeled_left_span,
-                Parens::Unneeded,
-                left_is_coerced_to_value,
-            );
+            if is_redundant_op(cx, left, 1) {
+                let paren = needs_parenthesis(cx, expr, right);
+                span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value);
+            } else if is_redundant_op(cx, right, 1) {
+                let paren = needs_parenthesis(cx, expr, left);
+                span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value);
+            }
         },
         BinOpKind::Div => {
-            let _ = check_op(
-                cx,
-                right,
-                1,
-                expr.span,
-                peeled_left_span,
-                Parens::Unneeded,
-                left_is_coerced_to_value,
-            );
+            if is_redundant_op(cx, right, 1) {
+                let paren = needs_parenthesis(cx, expr, left);
+                span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value);
+            }
         },
         BinOpKind::BitAnd => {
-            let _ = check_op(
-                cx,
-                left,
-                -1,
-                expr.span,
-                peeled_right_span,
-                needs_parenthesis(cx, expr, right),
-                right_is_coerced_to_value,
-            ) || check_op(
-                cx,
-                right,
-                -1,
-                expr.span,
-                peeled_left_span,
-                Parens::Unneeded,
-                left_is_coerced_to_value,
-            );
+            if is_redundant_op(cx, left, -1) {
+                let paren = needs_parenthesis(cx, expr, right);
+                span_ineffective_operation(cx, expr.span, peeled_right_span, paren, right_is_coerced_to_value);
+            } else if is_redundant_op(cx, right, -1) {
+                let paren = needs_parenthesis(cx, expr, left);
+                span_ineffective_operation(cx, expr.span, peeled_left_span, paren, left_is_coerced_to_value);
+            }
         },
         BinOpKind::Rem => check_remainder(cx, left, right, expr.span, left.span),
         _ => (),
@@ -138,43 +98,70 @@ enum Parens {
     Unneeded,
 }
 
-/// Checks if `left op right` needs parenthesis when reduced to `right`
+/// Checks if a binary expression needs parenthesis when reduced to just its
+/// right or left child.
+///
+/// e.g. `-(x + y + 0)` cannot be reduced to `-x + y`, as the behavior changes silently.
+/// e.g. `1u64 + ((x + y + 0i32) as u64)` cannot be reduced to `1u64 + x + y as u64`, since
+/// the the cast expression will not apply to the same expression.
 /// e.g. `0 + if b { 1 } else { 2 } + if b { 3 } else { 4 }` cannot be reduced
 /// to `if b { 1 } else { 2 } + if b { 3 } else { 4 }` where the `if` could be
-/// interpreted as a statement
+/// interpreted as a statement. The same behavior happens for `match`, `loop`,
+/// and blocks.
+/// e.g.  `2 * (0 + { a })` can be reduced to `2 * { a }` without the need for parenthesis,
+/// but `1 * ({ a } + 4)` cannot be reduced to `{ a } + 4`, as a block at the start of a line
+/// will be interpreted as a statement instead of an expression.
 ///
-/// See #8724
-fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, right: &Expr<'_>) -> Parens {
-    match right.kind {
+/// See #8724, #13470
+fn needs_parenthesis(cx: &LateContext<'_>, binary: &Expr<'_>, child: &Expr<'_>) -> Parens {
+    match child.kind {
         ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) => {
-            // ensure we're checking against the leftmost expression of `right`
-            //
-            //     ~~~ `lhs`
-            // 0 + {4} * 2
-            //     ~~~~~~~ `right`
-            return needs_parenthesis(cx, binary, lhs);
+            // For casts and binary expressions, we want to add parenthesis if
+            // the parent HIR node is an expression, or if the parent HIR node
+            // is a Block or Stmt, and the new left hand side would need
+            // parenthesis be treated as a statement rather than an expression.
+            if let Some((_, parent)) = cx.tcx.hir().parent_iter(binary.hir_id).next() {
+                match parent {
+                    Node::Expr(_) => return Parens::Needed,
+                    Node::Block(_) | Node::Stmt(_) => {
+                        // ensure we're checking against the leftmost expression of `child`
+                        //
+                        // ~~~~~~~~~~~ `binary`
+                        //     ~~~ `lhs`
+                        // 0 + {4} * 2
+                        //     ~~~~~~~ `child`
+                        return needs_parenthesis(cx, binary, lhs);
+                    },
+                    _ => return Parens::Unneeded,
+                }
+            }
+        },
+        ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {
+            // For if, match, block, and loop expressions, we want to add parenthesis if
+            // the closest ancestor node that is not an expression is a block or statement.
+            // This would mean that the rustfix suggestion will appear at the start of a line, which causes
+            // these expressions to be interpreted as statements if they do not have parenthesis.
+            let mut prev_id = binary.hir_id;
+            for (_, parent) in cx.tcx.hir().parent_iter(binary.hir_id) {
+                if let Node::Expr(expr) = parent
+                    && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) | ExprKind::Unary(_, lhs) = expr.kind
+                    && lhs.hir_id == prev_id
+                {
+                    // keep going until we find a node that encompasses left of `binary`
+                    prev_id = expr.hir_id;
+                    continue;
+                }
+
+                match parent {
+                    Node::Block(_) | Node::Stmt(_) => return Parens::Needed,
+                    _ => return Parens::Unneeded,
+                };
+            }
+        },
+        _ => {
+            return Parens::Unneeded;
         },
-        ExprKind::If(..) | ExprKind::Match(..) | ExprKind::Block(..) | ExprKind::Loop(..) => {},
-        _ => return Parens::Unneeded,
-    }
-
-    let mut prev_id = binary.hir_id;
-    for (_, node) in cx.tcx.hir().parent_iter(binary.hir_id) {
-        if let Node::Expr(expr) = node
-            && let ExprKind::Binary(_, lhs, _) | ExprKind::Cast(lhs, _) = expr.kind
-            && lhs.hir_id == prev_id
-        {
-            // keep going until we find a node that encompasses left of `binary`
-            prev_id = expr.hir_id;
-            continue;
-        }
-
-        match node {
-            Node::Block(_) | Node::Stmt(_) => break,
-            _ => return Parens::Unneeded,
-        };
     }
-
     Parens::Needed
 }
 
@@ -199,7 +186,7 @@ fn check_remainder(cx: &LateContext<'_>, left: &Expr<'_>, right: &Expr<'_>, span
     }
 }
 
-fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, parens: Parens, is_erased: bool) -> bool {
+fn is_redundant_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8) -> bool {
     if let Some(Constant::Int(v)) = ConstEvalCtxt::new(cx).eval_simple(e).map(Constant::peel_refs) {
         let check = match *cx.typeck_results().expr_ty(e).peel_refs().kind() {
             ty::Int(ity) => unsext(cx.tcx, -1_i128, ity),
@@ -212,7 +199,6 @@ fn check_op(cx: &LateContext<'_>, e: &Expr<'_>, m: i8, span: Span, arg: Span, pa
             1 => v == 1,
             _ => unreachable!(),
         } {
-            span_ineffective_operation(cx, span, arg, parens, is_erased);
             return true;
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 565294bb40a..d369978b8be 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -14,7 +14,7 @@ pub struct Context {
 }
 impl Context {
     fn skip_expr(&mut self, e: &hir::Expr<'_>) -> bool {
-        self.expr_id.is_some() || self.const_span.map_or(false, |span| span.contains(e.span))
+        self.expr_id.is_some() || self.const_span.is_some_and(|span| span.contains(e.span))
     }
 
     pub fn check_binary<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 1bddfab39c6..b2089487a9f 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -192,7 +192,7 @@ impl PassByRefOrValue {
                                 continue;
                             }
                         }
-                        let value_type = if fn_body.and_then(|body| body.params.get(index)).map_or(false, is_self) {
+                        let value_type = if fn_body.and_then(|body| body.params.get(index)).is_some_and(is_self) {
                             "self".into()
                         } else {
                             snippet(cx, decl_ty.span, "_").into()
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index a548c6ef3b1..ecc095f3859 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -727,9 +727,8 @@ fn get_ref_lm<'tcx>(ty: &'tcx hir::Ty<'tcx>) -> Option<(&'tcx Lifetime, Mutabili
 
 fn is_null_path(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     if let ExprKind::Call(pathexp, []) = expr.kind {
-        path_def_id(cx, pathexp).map_or(false, |id| {
-            matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut))
-        })
+        path_def_id(cx, pathexp)
+            .is_some_and(|id| matches!(cx.tcx.get_diagnostic_name(id), Some(sym::ptr_null | sym::ptr_null_mut)))
     } else {
         false
     }
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index cb374fcf20e..a00fd01a62e 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -8,18 +8,18 @@ use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::ty::{implements_trait, is_type_diagnostic_item};
 use clippy_utils::{
     eq_expr_value, higher, is_else_clause, is_in_const_context, is_lint_allowed, is_path_lang_item, is_res_lang_ctor,
-    pat_and_expr_can_be_question_mark, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
-    span_contains_comment,
+    pat_and_expr_can_be_question_mark, path_res, path_to_local, path_to_local_id, peel_blocks, peel_blocks_with_stmt,
+    span_contains_cfg, span_contains_comment,
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::Res;
 use rustc_hir::{
-    BindingMode, Block, Body, ByRef, Expr, ExprKind, LetStmt, Mutability, Node, PatKind, PathSegment, QPath, Stmt,
-    StmtKind,
+    Arm, BindingMode, Block, Body, ByRef, Expr, ExprKind, FnRetTy, HirId, LetStmt, MatchSource, Mutability, Node, Pat,
+    PatKind, PathSegment, QPath, Stmt, StmtKind,
 };
 use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, Ty};
 use rustc_session::impl_lint_pass;
 use rustc_span::sym;
 use rustc_span::symbol::Symbol;
@@ -58,6 +58,9 @@ pub struct QuestionMark {
     /// if it is greater than zero.
     /// As for why we need this in the first place: <https://github.com/rust-lang/rust-clippy/issues/8628>
     try_block_depth_stack: Vec<u32>,
+    /// Keeps track of the number of inferred return type closures we are inside, to avoid problems
+    /// with the `Err(x.into())` expansion being ambiguious.
+    inferred_ret_closure_stack: u16,
 }
 
 impl_lint_pass!(QuestionMark => [QUESTION_MARK, MANUAL_LET_ELSE]);
@@ -68,6 +71,7 @@ impl QuestionMark {
             msrv: conf.msrv.clone(),
             matches_behaviour: conf.matches_for_let_else,
             try_block_depth_stack: Vec::new(),
+            inferred_ret_closure_stack: 0,
         }
     }
 }
@@ -125,7 +129,7 @@ fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
         cx.tcx
             .lang_items()
             .try_trait()
-            .map_or(false, |did| implements_trait(cx, init_ty, did, &[]))
+            .is_some_and(|did| implements_trait(cx, init_ty, did, &[]))
     }
 
     if let StmtKind::Let(LetStmt {
@@ -271,6 +275,135 @@ fn check_is_none_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Ex
     }
 }
 
+#[derive(Clone, Copy, Debug)]
+enum TryMode {
+    Result,
+    Option,
+}
+
+fn find_try_mode<'tcx>(cx: &LateContext<'tcx>, scrutinee: &Expr<'tcx>) -> Option<TryMode> {
+    let scrutinee_ty = cx.typeck_results().expr_ty_adjusted(scrutinee);
+    let ty::Adt(scrutinee_adt_def, _) = scrutinee_ty.kind() else {
+        return None;
+    };
+
+    match cx.tcx.get_diagnostic_name(scrutinee_adt_def.did())? {
+        sym::Result => Some(TryMode::Result),
+        sym::Option => Some(TryMode::Option),
+        _ => None,
+    }
+}
+
+// Check that `pat` is `{ctor_lang_item}(val)`, returning `val`.
+fn extract_ctor_call<'a, 'tcx>(
+    cx: &LateContext<'tcx>,
+    expected_ctor: LangItem,
+    pat: &'a Pat<'tcx>,
+) -> Option<&'a Pat<'tcx>> {
+    if let PatKind::TupleStruct(variant_path, [val_binding], _) = &pat.kind
+        && is_res_lang_ctor(cx, cx.qpath_res(variant_path, pat.hir_id), expected_ctor)
+    {
+        Some(val_binding)
+    } else {
+        None
+    }
+}
+
+// Extracts the local ID of a plain `val` pattern.
+fn extract_binding_pat(pat: &Pat<'_>) -> Option<HirId> {
+    if let PatKind::Binding(BindingMode::NONE, binding, _, None) = pat.kind {
+        Some(binding)
+    } else {
+        None
+    }
+}
+
+fn check_arm_is_some_or_ok<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool {
+    let happy_ctor = match mode {
+        TryMode::Result => ResultOk,
+        TryMode::Option => OptionSome,
+    };
+
+    // Check for `Ok(val)` or `Some(val)`
+    if arm.guard.is_none()
+        && let Some(val_binding) = extract_ctor_call(cx, happy_ctor, arm.pat)
+        // Extract out `val`
+        && let Some(binding) = extract_binding_pat(val_binding)
+        // Check body is just `=> val`
+        && path_to_local_id(peel_blocks(arm.body), binding)
+    {
+        true
+    } else {
+        false
+    }
+}
+
+fn check_arm_is_none_or_err<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm: &Arm<'tcx>) -> bool {
+    if arm.guard.is_some() {
+        return false;
+    }
+
+    let arm_body = peel_blocks(arm.body);
+    match mode {
+        TryMode::Result => {
+            // Check that pat is Err(val)
+            if let Some(ok_pat) = extract_ctor_call(cx, ResultErr, arm.pat)
+                && let Some(ok_val) = extract_binding_pat(ok_pat)
+                // check `=> return Err(...)`
+                && let ExprKind::Ret(Some(wrapped_ret_expr)) = arm_body.kind
+                && let ExprKind::Call(ok_ctor, [ret_expr]) = wrapped_ret_expr.kind
+                && is_res_lang_ctor(cx, path_res(cx, ok_ctor), ResultErr)
+                // check `...` is `val` from binding
+                && path_to_local_id(ret_expr, ok_val)
+            {
+                true
+            } else {
+                false
+            }
+        },
+        TryMode::Option => {
+            // Check the pat is `None`
+            if is_res_lang_ctor(cx, path_res(cx, arm.pat), OptionNone)
+                // Check `=> return None`
+                && let ExprKind::Ret(Some(ret_expr)) = arm_body.kind
+                && is_res_lang_ctor(cx, path_res(cx, ret_expr), OptionNone)
+                && !ret_expr.span.from_expansion()
+            {
+                true
+            } else {
+                false
+            }
+        },
+    }
+}
+
+fn check_arms_are_try<'tcx>(cx: &LateContext<'tcx>, mode: TryMode, arm1: &Arm<'tcx>, arm2: &Arm<'tcx>) -> bool {
+    (check_arm_is_some_or_ok(cx, mode, arm1) && check_arm_is_none_or_err(cx, mode, arm2))
+        || (check_arm_is_some_or_ok(cx, mode, arm2) && check_arm_is_none_or_err(cx, mode, arm1))
+}
+
+fn check_if_try_match<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
+    if let ExprKind::Match(scrutinee, [arm1, arm2], MatchSource::Normal | MatchSource::Postfix) = expr.kind
+        && !expr.span.from_expansion()
+        && let Some(mode) = find_try_mode(cx, scrutinee)
+        && !span_contains_cfg(cx, expr.span)
+        && check_arms_are_try(cx, mode, arm1, arm2)
+    {
+        let mut applicability = Applicability::MachineApplicable;
+        let snippet = snippet_with_applicability(cx, scrutinee.span.source_callsite(), "..", &mut applicability);
+
+        span_lint_and_sugg(
+            cx,
+            QUESTION_MARK,
+            expr.span,
+            "this `match` expression can be replaced with `?`",
+            "try instead",
+            snippet.into_owned() + "?",
+            applicability,
+        );
+    }
+}
+
 fn check_if_let_some_or_err_and_early_return<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
     if let Some(higher::IfLet {
         let_pat,
@@ -339,6 +472,17 @@ fn is_try_block(cx: &LateContext<'_>, bl: &Block<'_>) -> bool {
     }
 }
 
+fn is_inferred_ret_closure(expr: &Expr<'_>) -> bool {
+    let ExprKind::Closure(closure) = expr.kind else {
+        return false;
+    };
+
+    match closure.fn_decl.output {
+        FnRetTy::Return(ret_ty) => ret_ty.is_suggestable_infer_ty(),
+        FnRetTy::DefaultReturn(_) => true,
+    }
+}
+
 impl<'tcx> LateLintPass<'tcx> for QuestionMark {
     fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx Stmt<'_>) {
         if !is_lint_allowed(cx, QUESTION_MARK_USED, stmt.hir_id) {
@@ -350,11 +494,27 @@ impl<'tcx> LateLintPass<'tcx> for QuestionMark {
         }
         self.check_manual_let_else(cx, stmt);
     }
+
     fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
+        if is_inferred_ret_closure(expr) {
+            self.inferred_ret_closure_stack += 1;
+            return;
+        }
+
         if !self.inside_try_block() && !is_in_const_context(cx) && is_lint_allowed(cx, QUESTION_MARK_USED, expr.hir_id)
         {
             check_is_none_or_err_and_early_return(cx, expr);
             check_if_let_some_or_err_and_early_return(cx, expr);
+
+            if self.inferred_ret_closure_stack == 0 {
+                check_if_try_match(cx, expr);
+            }
+        }
+    }
+
+    fn check_expr_post(&mut self, _: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+        if is_inferred_ret_closure(expr) {
+            self.inferred_ret_closure_stack -= 1;
         }
     }
 
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 030df535c35..dc66fb28fa8 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
             let (expr_ty, expr_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(expr));
             let (indexed_ty, indexed_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(indexed));
             let parent_expr = get_parent_expr(cx, expr);
-            let needs_parens_for_prefix = parent_expr.map_or(false, |parent| parent.precedence().order() > PREC_PREFIX);
+            let needs_parens_for_prefix = parent_expr.is_some_and(|parent| parent.precedence().order() > PREC_PREFIX);
 
             if expr_ty == indexed_ty {
                 if expr_ref_count > indexed_ref_count {
@@ -107,7 +107,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantSlicing {
                         kind: ExprKind::AddrOf(BorrowKind::Ref, Mutability::Mut, _),
                         ..
                     })
-                ) || cx.typeck_results().expr_adjustments(expr).first().map_or(false, |a| {
+                ) || cx.typeck_results().expr_adjustments(expr).first().is_some_and(|a| {
                     matches!(
                         a.kind,
                         Adjust::Borrow(AutoBorrow::Ref(AutoBorrowMutability::Mut { .. }))
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 23362506cca..78f0b7d121c 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -412,9 +412,7 @@ impl<'tcx> IndexBinding<'_, 'tcx> {
                 }
                 Self::is_used_slice_indexed(lhs, idx_ident) || Self::is_used_slice_indexed(rhs, idx_ident)
             },
-            ExprKind::Path(QPath::Resolved(_, path)) => {
-                path.segments.first().map_or(false, |idx| idx.ident == idx_ident)
-            },
+            ExprKind::Path(QPath::Resolved(_, path)) => path.segments.first().is_some_and(|idx| idx.ident == idx_ident),
             _ => false,
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
index eb7ffbbe360..bde88ab61ad 100644
--- a/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
+++ b/src/tools/clippy/clippy_lints/src/types/borrowed_box.rs
@@ -51,8 +51,7 @@ pub(super) fn check(cx: &LateContext<'_>, hir_ty: &hir::Ty<'_>, lt: &Lifetime, m
                         format!("&{ltopt}({inner_snippet})")
                     },
                     TyKind::Path(qpath)
-                        if get_bounds_if_impl_trait(cx, qpath, inner.hir_id)
-                            .map_or(false, |bounds| bounds.len() > 1) =>
+                        if get_bounds_if_impl_trait(cx, qpath, inner.hir_id).is_some_and(|bounds| bounds.len() > 1) =>
                     {
                         format!("&{ltopt}({inner_snippet})")
                     },
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index 1a1284ce9c4..6eef582b4b2 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -38,7 +38,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx LetStmt<'_>) {
             return;
         }
 
-        if (local.ty.map_or(false, |ty| !matches!(ty.kind, TyKind::Infer))
+        if (local.ty.is_some_and(|ty| !matches!(ty.kind, TyKind::Infer))
             || matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none()))
             && expr_needs_inferred_result(cx, init)
         {
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 91dff5a9523..cbc6885ae5d 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -98,7 +98,7 @@ impl VecPushSearcher {
                     needs_mut |= cx.typeck_results().expr_ty_adjusted(last_place).ref_mutability()
                         == Some(Mutability::Mut)
                         || get_parent_expr(cx, last_place)
-                            .map_or(false, |e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
+                            .is_some_and(|e| matches!(e.kind, ExprKind::AddrOf(_, Mutability::Mut, _)));
                 },
                 ExprKind::MethodCall(_, recv, ..)
                     if recv.hir_id == e.hir_id
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index 1dd46ed5a89..a42ddcdae35 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -295,7 +295,7 @@ impl<'tcx> LateLintPass<'tcx> for Write {
             .opts
             .crate_name
             .as_ref()
-            .map_or(false, |crate_name| crate_name == "build_script_build");
+            .is_some_and(|crate_name| crate_name == "build_script_build");
 
         let allowed_in_tests = self.allow_print_in_tests && is_in_test(cx.tcx, expr.hir_id);
         match diag_name {
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 75169e05734..3269bf758ac 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -51,7 +51,7 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
         return false;
     };
     let end = span.hi() - pos.sf.start_pos;
-    src.get(pos.pos.0 as usize..end.0 as usize).map_or(false, |s| {
+    src.get(pos.pos.0 as usize..end.0 as usize).is_some_and(|s| {
         // Spans can be wrapped in a mixture or parenthesis, whitespace, and trailing commas.
         let start_str = s.trim_start_matches(|c: char| c.is_whitespace() || c == '(');
         let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
@@ -60,13 +60,13 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
             Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
             Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
             Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
-            Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
+            Pat::Num => start_str.as_bytes().first().is_some_and(u8::is_ascii_digit),
         } && match end_pat {
             Pat::Str(text) => end_str.ends_with(text),
             Pat::MultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
             Pat::OwnedMultiStr(texts) => texts.iter().any(|s| end_str.ends_with(s)),
             Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
-            Pat::Num => end_str.as_bytes().last().map_or(false, u8::is_ascii_hexdigit),
+            Pat::Num => end_str.as_bytes().last().is_some_and(u8::is_ascii_hexdigit),
         })
     })
 }
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index cb69f8e5a0e..c73ab4bfa68 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -258,7 +258,7 @@ impl HirEqInterExpr<'_, '_, '_> {
     }
 
     fn should_ignore(&mut self, expr: &Expr<'_>) -> bool {
-        macro_backtrace(expr.span).last().map_or(false, |macro_call| {
+        macro_backtrace(expr.span).last().is_some_and(|macro_call| {
             matches!(
                 &self.inner.cx.tcx.get_diagnostic_name(macro_call.def_id),
                 Some(sym::todo_macro | sym::unimplemented_macro)
@@ -322,7 +322,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             (&ExprKind::Block(l, _), &ExprKind::Block(r, _)) => self.eq_block(l, r),
             (&ExprKind::Binary(l_op, ll, lr), &ExprKind::Binary(r_op, rl, rr)) => {
                 l_op.node == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
-                    || swap_binop(l_op.node, ll, lr).map_or(false, |(l_op, ll, lr)| {
+                    || swap_binop(l_op.node, ll, lr).is_some_and(|(l_op, ll, lr)| {
                         l_op == r_op.node && self.eq_expr(ll, rl) && self.eq_expr(lr, rr)
                     })
             },
@@ -444,7 +444,7 @@ impl HirEqInterExpr<'_, '_, '_> {
             ) => false,
         };
         (is_eq && (!self.should_ignore(left) || !self.should_ignore(right)))
-            || self.inner.expr_fallback.as_mut().map_or(false, |f| f(left, right))
+            || self.inner.expr_fallback.as_mut().is_some_and(|f| f(left, right))
     }
 
     fn eq_exprs(&mut self, left: &[Expr<'_>], right: &[Expr<'_>]) -> bool {
@@ -724,7 +724,7 @@ fn swap_binop<'a>(
 /// `eq_fn`.
 pub fn both<X>(l: Option<&X>, r: Option<&X>, mut eq_fn: impl FnMut(&X, &X) -> bool) -> bool {
     l.as_ref()
-        .map_or_else(|| r.is_none(), |x| r.as_ref().map_or(false, |y| eq_fn(x, y)))
+        .map_or_else(|| r.is_none(), |x| r.as_ref().is_some_and(|y| eq_fn(x, y)))
 }
 
 /// Checks if two slices are equal as per `eq_fn`.
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 50d334acf18..19316a90683 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -342,10 +342,9 @@ pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
 /// Checks if the method call given in `expr` belongs to the given trait.
 /// This is a deprecated function, consider using [`is_trait_method`].
 pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool {
-    cx.typeck_results()
-        .type_dependent_def_id(expr.hir_id)
-        .and_then(|defid| cx.tcx.trait_of_item(defid))
-        .map_or(false, |trt_id| match_def_path(cx, trt_id, path))
+    let def_id = cx.typeck_results().type_dependent_def_id(expr.hir_id).unwrap();
+    let trt_id = cx.tcx.trait_of_item(def_id);
+    trt_id.is_some_and(|trt_id| match_def_path(cx, trt_id, path))
 }
 
 /// Checks if the given method call expression calls an inherent method.
@@ -379,7 +378,7 @@ pub fn is_diag_trait_item(cx: &LateContext<'_>, def_id: DefId, diag_item: Symbol
 pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -> bool {
     cx.typeck_results()
         .type_dependent_def_id(expr.hir_id)
-        .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
+        .is_some_and(|did| is_diag_trait_item(cx, did, diag_item))
 }
 
 /// Checks if the `def_id` belongs to a function that is part of a trait impl.
@@ -406,7 +405,7 @@ pub fn is_trait_item(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol) -
     if let ExprKind::Path(ref qpath) = expr.kind {
         cx.qpath_res(qpath, expr.hir_id)
             .opt_def_id()
-            .map_or(false, |def_id| is_diag_trait_item(cx, def_id, diag_item))
+            .is_some_and(|def_id| is_diag_trait_item(cx, def_id, diag_item))
     } else {
         false
     }
@@ -466,13 +465,13 @@ pub fn match_qpath(path: &QPath<'_>, segments: &[&str]) -> bool {
 ///
 /// Please use `is_path_diagnostic_item` if the target is a diagnostic item.
 pub fn is_expr_path_def_path(cx: &LateContext<'_>, expr: &Expr<'_>, segments: &[&str]) -> bool {
-    path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, segments))
+    path_def_id(cx, expr).is_some_and(|id| match_def_path(cx, id, segments))
 }
 
 /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
 /// it matches the given lang item.
 pub fn is_path_lang_item<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx>, lang_item: LangItem) -> bool {
-    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.lang_items().get(lang_item) == Some(id))
+    path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.lang_items().get(lang_item) == Some(id))
 }
 
 /// If `maybe_path` is a path node which resolves to an item, resolves it to a `DefId` and checks if
@@ -482,7 +481,7 @@ pub fn is_path_diagnostic_item<'tcx>(
     maybe_path: &impl MaybePath<'tcx>,
     diag_item: Symbol,
 ) -> bool {
-    path_def_id(cx, maybe_path).map_or(false, |id| cx.tcx.is_diagnostic_item(diag_item, id))
+    path_def_id(cx, maybe_path).is_some_and(|id| cx.tcx.is_diagnostic_item(diag_item, id))
 }
 
 /// THIS METHOD IS DEPRECATED. Matches a `Path` against a slice of segment string literals.
@@ -1315,7 +1314,7 @@ pub fn method_chain_args<'a>(expr: &'a Expr<'_>, methods: &[&str]) -> Option<Vec
 pub fn is_entrypoint_fn(cx: &LateContext<'_>, def_id: DefId) -> bool {
     cx.tcx
         .entry_fn(())
-        .map_or(false, |(entry_fn_def_id, _)| def_id == entry_fn_def_id)
+        .is_some_and(|(entry_fn_def_id, _)| def_id == entry_fn_def_id)
 }
 
 /// Returns `true` if the expression is in the program's `#[panic_handler]`.
@@ -1753,8 +1752,8 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
 
     match pat.kind {
         PatKind::Wild | 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::Deref(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
+        PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
+        PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
         PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
@@ -1778,7 +1777,7 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
                 },
             }
         },
-        PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) => true,
+        PatKind::Lit(..) | PatKind::Range(..) | PatKind::Err(_) | PatKind::Deref(_) => true,
     }
 }
 
@@ -2021,7 +2020,7 @@ pub fn match_libc_symbol(cx: &LateContext<'_>, did: DefId, name: &str) -> bool {
     let path = cx.get_def_path(did);
     // libc is meant to be used as a flat list of names, but they're all actually defined in different
     // modules based on the target platform. Ignore everything but crate name and the item name.
-    path.first().map_or(false, |s| s.as_str() == "libc") && path.last().map_or(false, |s| s.as_str() == name)
+    path.first().is_some_and(|s| s.as_str() == "libc") && path.last().is_some_and(|s| s.as_str() == name)
 }
 
 /// Returns the list of condition expressions and the list of blocks in a
@@ -2104,7 +2103,7 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
         _ => None,
     };
 
-    did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
+    did.is_some_and(|did| cx.tcx.has_attr(did, sym::must_use))
 }
 
 /// Checks if a function's body represents the identity function. Looks for bodies of the form:
@@ -2211,7 +2210,7 @@ pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>)
 pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     match expr.kind {
         ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
-        _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
+        _ => path_def_id(cx, expr).is_some_and(|id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/numeric_literal.rs b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
index c5a34160e3d..2c49df9d807 100644
--- a/src/tools/clippy/clippy_utils/src/numeric_literal.rs
+++ b/src/tools/clippy/clippy_utils/src/numeric_literal.rs
@@ -53,7 +53,7 @@ impl<'a> NumericLiteral<'a> {
                 .trim_start()
                 .chars()
                 .next()
-                .map_or(false, |c| c.is_ascii_digit())
+                .is_some_and(|c| c.is_ascii_digit())
         {
             let (unsuffixed, suffix) = split_suffix(src, lit_kind);
             let float = matches!(lit_kind, LitKind::Float(..));
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 666ec8df930..971f8eeb1b3 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -393,12 +393,8 @@ fn is_stable_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
 
                 msrv.meets(const_stab_rust_version)
             } else {
-                // Unstable const fn, check if the feature is enabled. We need both the regular stability
-                // feature and (if set) the const stability feature to const-call this function.
-                let stab = tcx.lookup_stability(def_id);
-                let is_enabled = stab.is_some_and(|s| s.is_stable() || tcx.features().enabled(s.feature))
-                    && const_stab.feature.is_none_or(|f| tcx.features().enabled(f));
-                is_enabled && msrv.current().is_none()
+                // Unstable const fn, check if the feature is enabled.
+                tcx.features().enabled(const_stab.feature) && msrv.current().is_none()
             }
         })
 }
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index 3255c51d009..25ebe879192 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -905,7 +905,7 @@ impl<'tcx> DerefDelegate<'_, 'tcx> {
             _ => return false,
         };
 
-        ty.map_or(false, |ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()))
+        ty.is_some_and(|ty| matches!(ty.kind(), ty::Ref(_, inner, _) if inner.is_ref()))
     }
 }
 
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index ce1a20e0066..770cd9c3786 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -45,7 +45,7 @@ pub fn is_copy<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
 pub fn has_debug_impl<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
     cx.tcx
         .get_diagnostic_item(sym::Debug)
-        .map_or(false, |debug| implements_trait(cx, ty, debug, &[]))
+        .is_some_and(|debug| implements_trait(cx, ty, debug, &[]))
 }
 
 /// Checks whether a type can be partially moved.
@@ -487,7 +487,7 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
             .tcx
             .lang_items()
             .drop_trait()
-            .map_or(false, |id| implements_trait(cx, ty, id, &[]))
+            .is_some_and(|id| implements_trait(cx, ty, id, &[]))
         {
             // This type doesn't implement drop, so no side effects here.
             // Check if any component type has any.
@@ -718,7 +718,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
                 {
                     let output = bounds
                         .projection_bounds()
-                        .find(|p| lang_items.fn_once_output().map_or(false, |id| id == p.item_def_id()))
+                        .find(|p| lang_items.fn_once_output().is_some_and(|id| id == p.item_def_id()))
                         .map(|p| p.map_bound(|p| p.term.expect_type()));
                     Some(ExprFnSig::Trait(bound.map_bound(|b| b.args.type_at(0)), output, None))
                 },
@@ -753,7 +753,7 @@ fn sig_from_bounds<'tcx>(
                     && p.self_ty() == ty =>
             {
                 let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
-                if inputs.map_or(false, |inputs| i != inputs) {
+                if inputs.is_some_and(|inputs| i != inputs) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
@@ -794,7 +794,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option
             {
                 let i = pred.kind().rebind(p.trait_ref.args.type_at(1));
 
-                if inputs.map_or(false, |inputs| inputs != i) {
+                if inputs.is_some_and(|inputs| inputs != i) {
                     // Multiple different fn trait impls. Is this even allowed?
                     return None;
                 }
@@ -1291,7 +1291,7 @@ pub fn normalize_with_regions<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>
 
 /// Checks if the type is `core::mem::ManuallyDrop<_>`
 pub fn is_manually_drop(ty: Ty<'_>) -> bool {
-    ty.ty_adt_def().map_or(false, AdtDef::is_manually_drop)
+    ty.ty_adt_def().is_some_and(AdtDef::is_manually_drop)
 }
 
 /// Returns the deref chain of a type, starting with the type itself.
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 8f5ec185bf1..a79be5ca7d4 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -344,13 +344,13 @@ pub fn is_const_evaluatable<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) ->
                     .cx
                     .qpath_res(p, hir_id)
                     .opt_def_id()
-                    .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
+                    .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {},
                 ExprKind::MethodCall(..)
                     if self
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| self.cx.tcx.is_const_fn(id)) => {},
+                        .is_some_and(|id| self.cx.tcx.is_const_fn(id)) => {},
                 ExprKind::Binary(_, lhs, rhs)
                     if self.cx.typeck_results().expr_ty(lhs).peel_refs().is_primitive_ty()
                         && self.cx.typeck_results().expr_ty(rhs).peel_refs().is_primitive_ty() => {},
@@ -426,9 +426,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
                         .cx
                         .typeck_results()
                         .type_dependent_def_id(e.hir_id)
-                        .map_or(false, |id| {
-                            self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe
-                        }) =>
+                        .is_some_and(|id| self.cx.tcx.fn_sig(id).skip_binder().safety() == Safety::Unsafe) =>
                 {
                     ControlFlow::Break(())
                 },
@@ -444,7 +442,7 @@ pub fn is_expr_unsafe<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> bool {
                         .cx
                         .qpath_res(p, e.hir_id)
                         .opt_def_id()
-                        .map_or(false, |id| self.cx.tcx.is_mutable_static(id)) =>
+                        .is_some_and(|id| self.cx.tcx.is_mutable_static(id)) =>
                 {
                     ControlFlow::Break(())
                 },
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 37d9cce2465..e32e0cb3604 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,4 +1,4 @@
 [toolchain]
-channel = "nightly-2024-11-07"
+channel = "nightly-2024-11-14"
 components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
 profile = "minimal"
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
index 0a994842834..d3fab60f9e3 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed
@@ -1,6 +1,7 @@
 //@aux-build:paths.rs
 #![deny(clippy::internal)]
 #![feature(rustc_private)]
+#![allow(clippy::unnecessary_map_or)]
 
 extern crate clippy_utils;
 extern crate paths;
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
index ba68de6c6d0..1b36f6b09e9 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs
@@ -1,6 +1,7 @@
 //@aux-build:paths.rs
 #![deny(clippy::internal)]
 #![feature(rustc_private)]
+#![allow(clippy::unnecessary_map_or)]
 
 extern crate clippy_utils;
 extern crate paths;
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
index 79da1731613..79521c5037a 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.stderr
@@ -1,5 +1,5 @@
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:36:13
+  --> tests/ui-internal/unnecessary_def_path.rs:37:13
    |
 LL |     let _ = match_type(cx, ty, &OPTION);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
@@ -12,61 +12,61 @@ LL | #![deny(clippy::internal)]
    = note: `#[deny(clippy::unnecessary_def_path)]` implied by `#[deny(clippy::internal)]`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:37:13
+  --> tests/ui-internal/unnecessary_def_path.rs:38:13
    |
 LL |     let _ = match_type(cx, ty, RESULT);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:38:13
+  --> tests/ui-internal/unnecessary_def_path.rs:39:13
    |
 LL |     let _ = match_type(cx, ty, &["core", "result", "Result"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:42:13
+  --> tests/ui-internal/unnecessary_def_path.rs:43:13
    |
 LL |     let _ = clippy_utils::ty::match_type(cx, ty, rc_path);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Rc)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:44:13
+  --> tests/ui-internal/unnecessary_def_path.rs:45:13
    |
 LL |     let _ = match_type(cx, ty, &paths::OPTION);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Option)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:45:13
+  --> tests/ui-internal/unnecessary_def_path.rs:46:13
    |
 LL |     let _ = match_type(cx, ty, paths::RESULT);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::Result)`
 
 error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:47:13
+  --> tests/ui-internal/unnecessary_def_path.rs:48:13
    |
 LL |     let _ = match_type(cx, ty, &["alloc", "boxed", "Box"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_lang_item(cx, ty, LangItem::OwnedBox)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:48:13
+  --> tests/ui-internal/unnecessary_def_path.rs:49:13
    |
 LL |     let _ = match_type(cx, ty, &["core", "mem", "maybe_uninit", "MaybeUninit", "uninit"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_type_diagnostic_item(cx, ty, sym::maybe_uninit_uninit)`
 
 error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:50:13
+  --> tests/ui-internal/unnecessary_def_path.rs:51:13
    |
 LL |     let _ = match_def_path(cx, did, &["alloc", "boxed", "Box"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OwnedBox) == Some(did)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:51:13
+  --> tests/ui-internal/unnecessary_def_path.rs:52:13
    |
 LL |     let _ = match_def_path(cx, did, &["core", "option", "Option"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.is_diagnostic_item(sym::Option, did)`
 
 error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:52:13
+  --> tests/ui-internal/unnecessary_def_path.rs:53:13
    |
 LL |     let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cx.tcx.lang_items().get(LangItem::OptionSome) == Some(did)`
@@ -74,25 +74,25 @@ LL |     let _ = match_def_path(cx, did, &["core", "option", "Option", "Some"]);
    = help: if this `DefId` came from a constructor expression or pattern then the parent `DefId` should be used instead
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:54:13
+  --> tests/ui-internal/unnecessary_def_path.rs:55:13
    |
 LL |     let _ = match_trait_method(cx, expr, &["core", "convert", "AsRef"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_trait_method(cx, expr, sym::AsRef)`
 
 error: use of a def path to a diagnostic item
-  --> tests/ui-internal/unnecessary_def_path.rs:56:13
+  --> tests/ui-internal/unnecessary_def_path.rs:57:13
    |
 LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_path_diagnostic_item(cx, expr, sym::Option)`
 
 error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:57:13
+  --> tests/ui-internal/unnecessary_def_path.rs:58:13
    |
 LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "iter", "traits", "Iterator", "next"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `path_res(cx, expr).opt_def_id().map_or(false, |id| cx.tcx.lang_items().get(LangItem::IteratorNext) == Some(id))`
 
 error: use of a def path to a `LangItem`
-  --> tests/ui-internal/unnecessary_def_path.rs:58:13
+  --> tests/ui-internal/unnecessary_def_path.rs:59:13
    |
 LL |     let _ = is_expr_path_def_path(cx, expr, &["core", "option", "Option", "Some"]);
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `is_res_lang_ctor(cx, path_res(cx, expr), LangItem::OptionSome)`
diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt b/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt
new file mode 100644
index 00000000000..e69de29bb2d
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/large_include_file/empty.txt
diff --git a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs
index dc9349f75a0..8a6dd36501c 100644
--- a/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs
+++ b/src/tools/clippy/tests/ui-toml/large_include_file/large_include_file.rs
@@ -15,5 +15,9 @@ const TOO_BIG_INCLUDE_BYTES: &[u8; 654] = include_bytes!("too_big.txt");
 const TOO_BIG_INCLUDE_STR: &str = include_str!("too_big.txt");
 //~^ large_include_file
 
-#[doc = include_str!("too_big.txt")] //~ large_include_file
+#[doc = include_str!("too_big.txt")]
+//~^ large_include_file
+// Should not lint!
+// Regression test for <https://github.com/rust-lang/rust-clippy/issues/13670>.
+#[doc = include_str!("empty.txt")]
 fn main() {}
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
index 8b4a165a97c..c4d77f24f12 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed
@@ -1,4 +1,5 @@
 #![warn(clippy::case_sensitive_file_extension_comparisons)]
+#![allow(clippy::unnecessary_map_or)]
 
 use std::string::String;
 
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
index e4b8178110b..690e93c2639 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs
@@ -1,4 +1,5 @@
 #![warn(clippy::case_sensitive_file_extension_comparisons)]
+#![allow(clippy::unnecessary_map_or)]
 
 use std::string::String;
 
diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
index d203f91b832..e21815f251b 100644
--- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
+++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.stderr
@@ -1,5 +1,5 @@
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:13:5
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:14:5
    |
 LL |     filename.ends_with(".rs")
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -15,7 +15,7 @@ LL +         .map_or(false, |ext| ext.eq_ignore_ascii_case("rs"))
    |
 
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:18:13
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13
    |
 LL |     let _ = String::new().ends_with(".ext12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -29,7 +29,7 @@ LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
    |
 
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:19:13
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:20:13
    |
 LL |     let _ = "str".ends_with(".ext12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -43,7 +43,7 @@ LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
    |
 
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:23:17
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:24:17
    |
 LL |         let _ = "str".ends_with(".ext12");
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -57,7 +57,7 @@ LL ~             .map_or(false, |ext| ext.eq_ignore_ascii_case("ext12"));
    |
 
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:30:13
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13
    |
 LL |     let _ = String::new().ends_with(".EXT12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -71,7 +71,7 @@ LL ~         .map_or(false, |ext| ext.eq_ignore_ascii_case("EXT12"));
    |
 
 error: case-sensitive file extension comparison
-  --> tests/ui/case_sensitive_file_extension_comparisons.rs:31:13
+  --> tests/ui/case_sensitive_file_extension_comparisons.rs:32:13
    |
 LL |     let _ = "str".ends_with(".EXT12");
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
index c238b4c9a17..2852e26680f 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/doc_comments.stderr
@@ -3,7 +3,7 @@ error: empty line after doc comment
    |
 LL | / /// for the crate
 LL | |
-   | |_
+   | |_^
 LL |   fn first_in_crate() {}
    |   ------------------- the comment documents this function
    |
@@ -22,7 +22,7 @@ error: empty line after doc comment
    |
 LL | /     /// for the module
 LL | |
-   | |_
+   | |_^
 LL |       fn first_in_module() {}
    |       -------------------- the comment documents this function
    |
@@ -39,7 +39,7 @@ error: empty line after doc comment
    |
 LL | /     /// # Indented
 LL | |
-   | |_
+   | |_^
 LL |       /// Blank line
 LL |       fn indented() {}
    |       ------------- the comment documents this function
@@ -55,7 +55,7 @@ error: empty line after doc comment
    |
 LL | / /// This should produce a warning
 LL | |
-   | |_
+   | |_^
 LL |   fn with_doc_and_newline() {}
    |   ------------------------- the comment documents this function
    |
@@ -69,7 +69,7 @@ LL | |
 LL | | /** This is also a doc comment and is part of the warning
 LL | |  */
 LL | |
-   | |_
+   | |_^
 ...
 LL |   fn three_attributes() {}
    |   --------------------- the comment documents this function
@@ -82,7 +82,7 @@ error: empty line after doc comment
 LL | /     /// docs for `old_code`
 LL | |     // fn old_code() {}
 LL | |
-   | |_
+   | |_^
 LL |       fn new_code() {}
    |       ------------- the comment documents this function
    |
@@ -102,7 +102,7 @@ LL | |     /// Docs
 LL | |     /// for OldB
 LL | |     // struct OldB;
 LL | |
-   | |_
+   | |_^
 ...
 LL |       struct Multiple;
    |       --------------- the comment documents this struct
@@ -125,7 +125,7 @@ LL | /     /**
 LL | |      * Meant to be inner doc comment
 LL | |      */
 LL | |
-   | |_
+   | |_^
 LL |       fn first_in_module() {}
    |       -------------------- the comment documents this function
    |
@@ -143,7 +143,7 @@ LL | |      * Docs for `old_code`
 LL | |      */
 LL | |     /* fn old_code() {} */
 LL | |
-   | |_
+   | |_^
 ...
 LL |       fn new_code() {}
    |       ------------- the comment documents this function
@@ -161,7 +161,7 @@ error: empty line after doc comment
 LL | /     /// Docs for `old_code2`
 LL | |     /* fn old_code2() {} */
 LL | |
-   | |_
+   | |_^
 LL |       /// Docs for `new_code2`
 LL |       fn new_code2() {}
    |       -------------- the comment documents this function
diff --git a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
index 958b40424a9..75fc23e9e7e 100644
--- a/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
+++ b/src/tools/clippy/tests/ui/empty_line_after/outer_attribute.stderr
@@ -3,7 +3,7 @@ error: empty line after outer attribute
    |
 LL | / #[crate_type = "lib"]
 LL | |
-   | |_
+   | |_^
 LL |   fn first_in_crate() {}
    |   ------------------- the attribute applies to this function
    |
@@ -20,7 +20,7 @@ error: empty line after outer attribute
    |
 LL | / #[inline]
 LL | |
-   | |_
+   | |_^
 LL |   /// some comment
 LL |   fn with_one_newline_and_comment() {}
    |   --------------------------------- the attribute applies to this function
@@ -32,7 +32,7 @@ error: empty line after outer attribute
    |
 LL | / #[inline]
 LL | |
-   | |_
+   | |_^
 LL |   fn with_one_newline() {}
    |   --------------------- the attribute applies to this function
    |
@@ -44,7 +44,7 @@ error: empty lines after outer attribute
 LL | /     #[crate_type = "lib"]
 LL | |
 LL | |
-   | |_
+   | |_^
 LL |       fn with_two_newlines() {}
    |       ---------------------- the attribute applies to this function
    |
@@ -59,7 +59,7 @@ error: empty line after outer attribute
    |
 LL | / #[doc = "doc attributes should be considered attributes"]
 LL | |
-   | |_
+   | |_^
 LL |   enum Baz {
    |   -------- the attribute applies to this enum
    |
@@ -70,7 +70,7 @@ error: empty line after outer attribute
    |
 LL | / #[repr(C)]
 LL | |
-   | |_
+   | |_^
 LL |   struct Foo {
    |   ---------- the attribute applies to this struct
    |
@@ -81,7 +81,7 @@ error: empty line after outer attribute
    |
 LL | / #[allow(dead_code)]
 LL | |
-   | |_
+   | |_^
 LL |   mod foo {}
    |   ------- the attribute applies to this module
    |
@@ -93,7 +93,7 @@ error: empty line after outer attribute
 LL | / #[inline]
 LL | | // Still lint cases where the empty line does not immediately follow the attribute
 LL | |
-   | |_
+   | |_^
 LL |   fn comment_before_empty_line() {}
    |   ------------------------------ the attribute applies to this function
    |
@@ -106,7 +106,7 @@ LL | / #[allow(unused)]
 LL | |
 LL | | // This comment is isolated
 LL | |
-   | |_
+   | |_^
 LL |   pub fn isolated_comment() {}
    |   ------------------------- the attribute applies to this function
    |
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes.stderr b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
index a2218ea4d10..3606a2227a0 100644
--- a/src/tools/clippy/tests/ui/four_forward_slashes.stderr
+++ b/src/tools/clippy/tests/ui/four_forward_slashes.stderr
@@ -3,7 +3,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d
    |
 LL | / //// whoops
 LL | | fn a() {}
-   | |_
+   | |_^
    |
    = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]`
@@ -18,7 +18,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d
 LL | / //// whoops
 LL | | #[allow(dead_code)]
 LL | | fn b() {}
-   | |_
+   | |_^
    |
 help: make this a doc comment by removing one `/`
    |
@@ -32,7 +32,7 @@ LL | / //// whoops
 LL | | //// two borked comments!
 LL | | #[track_caller]
 LL | | fn c() {}
-   | |_
+   | |_^
    |
 help: turn these into doc comments by removing one `/`
    |
@@ -46,7 +46,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d
 LL | / //// between attributes
 LL | | #[allow(dead_code)]
 LL | | fn g() {}
-   | |_
+   | |_^
    |
 help: make this a doc comment by removing one `/`
    |
@@ -58,7 +58,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d
    |
 LL | /     //// not very start of contents
 LL | | fn h() {}
-   | |_
+   | |_^
    |
 help: make this a doc comment by removing one `/`
    |
diff --git a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
index 23937034b7e..81732346412 100644
--- a/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
+++ b/src/tools/clippy/tests/ui/four_forward_slashes_first_line.stderr
@@ -3,7 +3,7 @@ error: this item has comments with 4 forward slashes (`////`). These look like d
    |
 LL | / //// borked doc comment on the first line. doesn't combust!
 LL | | fn a() {}
-   | |_
+   | |_^
    |
    = note: `-D clippy::four-forward-slashes` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::four_forward_slashes)]`
diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed
index b18d8560f6f..2e8e2366de6 100644
--- a/src/tools/clippy/tests/ui/identity_op.fixed
+++ b/src/tools/clippy/tests/ui/identity_op.fixed
@@ -116,7 +116,7 @@ fn main() {
     //~^ ERROR: this operation has no effect
     (match a { 0 => 10, _ => 20 }) + if b { 3 } else { 4 };
     //~^ ERROR: this operation has no effect
-    (if b { 1 } else { 2 });
+    ((if b { 1 } else { 2 }));
     //~^ ERROR: this operation has no effect
 
     ({ a }) + 3;
@@ -212,3 +212,47 @@ fn issue_12050() {
         //~^ ERROR: this operation has no effect
     }
 }
+
+fn issue_13470() {
+    let x = 1i32;
+    let y = 1i32;
+    // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works
+    let _: u64 = (x + y) as u64;
+    //~^ ERROR: this operation has no effect
+    // both of the next two lines should look the same after rustfix
+    let _: u64 = 1u64 & (x + y) as u64;
+    //~^ ERROR: this operation has no effect
+    // Same as above, but with extra redundant parenthesis
+    let _: u64 = 1u64 & ((x + y)) as u64;
+    //~^ ERROR: this operation has no effect
+    // Should maintain parenthesis even if the surrounding expr has the same precedence
+    let _: u64 = 5u64 + ((x + y)) as u64;
+    //~^ ERROR: this operation has no effect
+
+    // If we don't maintain the parens here, the behavior changes
+    let _ = -(x + y);
+    //~^ ERROR: this operation has no effect
+    // Similarly, we need to maintain parens here
+    let _ = -(x / y);
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is of higher precedence
+    let _ = 2i32 * (x + y);
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is the same precedence
+    // as not all operations are associative
+    let _ = 2i32 - (x - y);
+    //~^ ERROR: this operation has no effect
+    // But make sure that inner parens still exist
+    let z = 1i32;
+    let _ = 2 + (x + (y * z));
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is of lower precedence
+    // This is for clarity, and clippy will not warn on these being unnecessary
+    let _ = 2i32 + (x * y);
+    //~^ ERROR: this operation has no effect
+
+    let x = 1i16;
+    let y = 1i16;
+    let _: u64 = 1u64 + ((x as i32 + y as i32) as u64);
+    //~^ ERROR: this operation has no effect
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs
index f1f01b42447..3e20fa6f2b8 100644
--- a/src/tools/clippy/tests/ui/identity_op.rs
+++ b/src/tools/clippy/tests/ui/identity_op.rs
@@ -212,3 +212,47 @@ fn issue_12050() {
         //~^ ERROR: this operation has no effect
     }
 }
+
+fn issue_13470() {
+    let x = 1i32;
+    let y = 1i32;
+    // Removes the + 0i32 while keeping the parentheses around x + y so the cast operation works
+    let _: u64 = (x + y + 0i32) as u64;
+    //~^ ERROR: this operation has no effect
+    // both of the next two lines should look the same after rustfix
+    let _: u64 = 1u64 & (x + y + 0i32) as u64;
+    //~^ ERROR: this operation has no effect
+    // Same as above, but with extra redundant parenthesis
+    let _: u64 = 1u64 & ((x + y) + 0i32) as u64;
+    //~^ ERROR: this operation has no effect
+    // Should maintain parenthesis even if the surrounding expr has the same precedence
+    let _: u64 = 5u64 + ((x + y) + 0i32) as u64;
+    //~^ ERROR: this operation has no effect
+
+    // If we don't maintain the parens here, the behavior changes
+    let _ = -(x + y + 0i32);
+    //~^ ERROR: this operation has no effect
+    // Similarly, we need to maintain parens here
+    let _ = -(x / y / 1i32);
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is of higher precedence
+    let _ = 2i32 * (x + y + 0i32);
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is the same precedence
+    // as not all operations are associative
+    let _ = 2i32 - (x - y - 0i32);
+    //~^ ERROR: this operation has no effect
+    // But make sure that inner parens still exist
+    let z = 1i32;
+    let _ = 2 + (x + (y * z) + 0);
+    //~^ ERROR: this operation has no effect
+    // Maintain parenthesis if the parent expr is of lower precedence
+    // This is for clarity, and clippy will not warn on these being unnecessary
+    let _ = 2i32 + (x * y * 1i32);
+    //~^ ERROR: this operation has no effect
+
+    let x = 1i16;
+    let y = 1i16;
+    let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
+    //~^ ERROR: this operation has no effect
+}
diff --git a/src/tools/clippy/tests/ui/identity_op.stderr b/src/tools/clippy/tests/ui/identity_op.stderr
index 9fff86b86f9..99a58ef2c1b 100644
--- a/src/tools/clippy/tests/ui/identity_op.stderr
+++ b/src/tools/clippy/tests/ui/identity_op.stderr
@@ -149,7 +149,7 @@ error: this operation has no effect
   --> tests/ui/identity_op.rs:119:5
    |
 LL |     (if b { 1 } else { 2 }) + 0;
-   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(if b { 1 } else { 2 })`
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((if b { 1 } else { 2 }))`
 
 error: this operation has no effect
   --> tests/ui/identity_op.rs:122:5
@@ -313,5 +313,71 @@ error: this operation has no effect
 LL |         let _: i32 = **&&*&x + 0;
    |                      ^^^^^^^^^^^ help: consider reducing it to: `***&&*&x`
 
-error: aborting due to 52 previous errors
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:220:18
+   |
+LL |     let _: u64 = (x + y + 0i32) as u64;
+   |                  ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:223:25
+   |
+LL |     let _: u64 = 1u64 & (x + y + 0i32) as u64;
+   |                         ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:226:25
+   |
+LL |     let _: u64 = 1u64 & ((x + y) + 0i32) as u64;
+   |                         ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:229:25
+   |
+LL |     let _: u64 = 5u64 + ((x + y) + 0i32) as u64;
+   |                         ^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x + y))`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:233:14
+   |
+LL |     let _ = -(x + y + 0i32);
+   |              ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:236:14
+   |
+LL |     let _ = -(x / y / 1i32);
+   |              ^^^^^^^^^^^^^^ help: consider reducing it to: `(x / y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:239:20
+   |
+LL |     let _ = 2i32 * (x + y + 0i32);
+   |                    ^^^^^^^^^^^^^^ help: consider reducing it to: `(x + y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:243:20
+   |
+LL |     let _ = 2i32 - (x - y - 0i32);
+   |                    ^^^^^^^^^^^^^^ help: consider reducing it to: `(x - y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:247:17
+   |
+LL |     let _ = 2 + (x + (y * z) + 0);
+   |                 ^^^^^^^^^^^^^^^^^ help: consider reducing it to: `(x + (y * z))`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:251:20
+   |
+LL |     let _ = 2i32 + (x * y * 1i32);
+   |                    ^^^^^^^^^^^^^^ help: consider reducing it to: `(x * y)`
+
+error: this operation has no effect
+  --> tests/ui/identity_op.rs:256:25
+   |
+LL |     let _: u64 = 1u64 + ((x as i32 + y as i32) as u64 + 0u64);
+   |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider reducing it to: `((x as i32 + y as i32) as u64)`
+
+error: aborting due to 63 previous errors
 
diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed
index 679388372e6..b6e148e9f77 100644
--- a/src/tools/clippy/tests/ui/question_mark.fixed
+++ b/src/tools/clippy/tests/ui/question_mark.fixed
@@ -96,12 +96,42 @@ impl MoveStruct {
 }
 
 fn func() -> Option<i32> {
+    macro_rules! opt_none {
+        () => {
+            None
+        };
+    }
+
     fn f() -> Option<String> {
         Some(String::new())
     }
 
     f()?;
 
+    let _val = f()?;
+
+    let s: &str = match &Some(String::new()) {
+        Some(v) => v,
+        None => return None,
+    };
+
+    f()?;
+
+    opt_none!()?;
+
+    match f() {
+        Some(x) => x,
+        None => return opt_none!(),
+    };
+
+    match f() {
+        Some(val) => {
+            println!("{val}");
+            val
+        },
+        None => return None,
+    };
+
     Some(0)
 }
 
@@ -114,6 +144,10 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
 
     x?;
 
+    let _val = func_returning_result()?;
+
+    func_returning_result()?;
+
     // No warning
     let y = if let Ok(x) = x {
         x
@@ -157,6 +191,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     Ok(y)
 }
 
+fn infer_check() {
+    let closure = |x: Result<u8, ()>| {
+        // `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
+        let _val = match x {
+            Ok(val) => val,
+            Err(val) => return Err(val),
+        };
+
+        Ok(())
+    };
+
+    let closure = |x: Result<u8, ()>| -> Result<(), _> {
+        // `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
+        let _val = match x {
+            Ok(val) => val,
+            Err(val) => return Err(val),
+        };
+
+        Ok(())
+    };
+}
+
 // see issue #8019
 pub enum NotOption {
     None,
diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs
index 601ab78bf5a..48dc9eb0a62 100644
--- a/src/tools/clippy/tests/ui/question_mark.rs
+++ b/src/tools/clippy/tests/ui/question_mark.rs
@@ -124,6 +124,12 @@ impl MoveStruct {
 }
 
 fn func() -> Option<i32> {
+    macro_rules! opt_none {
+        () => {
+            None
+        };
+    }
+
     fn f() -> Option<String> {
         Some(String::new())
     }
@@ -132,6 +138,39 @@ fn func() -> Option<i32> {
         return None;
     }
 
+    let _val = match f() {
+        Some(val) => val,
+        None => return None,
+    };
+
+    let s: &str = match &Some(String::new()) {
+        Some(v) => v,
+        None => return None,
+    };
+
+    match f() {
+        Some(val) => val,
+        None => return None,
+    };
+
+    match opt_none!() {
+        Some(x) => x,
+        None => return None,
+    };
+
+    match f() {
+        Some(x) => x,
+        None => return opt_none!(),
+    };
+
+    match f() {
+        Some(val) => {
+            println!("{val}");
+            val
+        },
+        None => return None,
+    };
+
     Some(0)
 }
 
@@ -146,6 +185,16 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
         return x;
     }
 
+    let _val = match func_returning_result() {
+        Ok(val) => val,
+        Err(err) => return Err(err),
+    };
+
+    match func_returning_result() {
+        Ok(val) => val,
+        Err(err) => return Err(err),
+    };
+
     // No warning
     let y = if let Ok(x) = x {
         x
@@ -189,6 +238,28 @@ fn result_func(x: Result<i32, i32>) -> Result<i32, i32> {
     Ok(y)
 }
 
+fn infer_check() {
+    let closure = |x: Result<u8, ()>| {
+        // `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
+        let _val = match x {
+            Ok(val) => val,
+            Err(val) => return Err(val),
+        };
+
+        Ok(())
+    };
+
+    let closure = |x: Result<u8, ()>| -> Result<(), _> {
+        // `?` would fail here, as it expands to `Err(val.into())` which is not constrained.
+        let _val = match x {
+            Ok(val) => val,
+            Err(val) => return Err(val),
+        };
+
+        Ok(())
+    };
+}
+
 // see issue #8019
 pub enum NotOption {
     None,
diff --git a/src/tools/clippy/tests/ui/question_mark.stderr b/src/tools/clippy/tests/ui/question_mark.stderr
index 5f26a7ea2c3..0a48c4e80cb 100644
--- a/src/tools/clippy/tests/ui/question_mark.stderr
+++ b/src/tools/clippy/tests/ui/question_mark.stderr
@@ -94,29 +94,76 @@ LL | |         };
    | |_________^ help: replace it with: `self.opt?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:131:5
+  --> tests/ui/question_mark.rs:137:5
    |
 LL | /     if f().is_none() {
 LL | |         return None;
 LL | |     }
    | |_____^ help: replace it with: `f()?;`
 
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:141:16
+   |
+LL |       let _val = match f() {
+   |  ________________^
+LL | |         Some(val) => val,
+LL | |         None => return None,
+LL | |     };
+   | |_____^ help: try instead: `f()?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:151:5
+   |
+LL | /     match f() {
+LL | |         Some(val) => val,
+LL | |         None => return None,
+LL | |     };
+   | |_____^ help: try instead: `f()?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:156:5
+   |
+LL | /     match opt_none!() {
+LL | |         Some(x) => x,
+LL | |         None => return None,
+LL | |     };
+   | |_____^ help: try instead: `opt_none!()?`
+
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:143:13
+  --> tests/ui/question_mark.rs:182:13
    |
 LL |     let _ = if let Ok(x) = x { x } else { return x };
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace it with: `x?`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:145:5
+  --> tests/ui/question_mark.rs:184:5
    |
 LL | /     if x.is_err() {
 LL | |         return x;
 LL | |     }
    | |_____^ help: replace it with: `x?;`
 
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:188:16
+   |
+LL |       let _val = match func_returning_result() {
+   |  ________________^
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(err),
+LL | |     };
+   | |_____^ help: try instead: `func_returning_result()?`
+
+error: this `match` expression can be replaced with `?`
+  --> tests/ui/question_mark.rs:193:5
+   |
+LL | /     match func_returning_result() {
+LL | |         Ok(val) => val,
+LL | |         Err(err) => return Err(err),
+LL | |     };
+   | |_____^ help: try instead: `func_returning_result()?`
+
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:213:5
+  --> tests/ui/question_mark.rs:284:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -124,7 +171,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:220:5
+  --> tests/ui/question_mark.rs:291:5
    |
 LL | /     if let Err(err) = func_returning_result() {
 LL | |         return Err(err);
@@ -132,7 +179,7 @@ LL | |     }
    | |_____^ help: replace it with: `func_returning_result()?;`
 
 error: this block may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:297:13
+  --> tests/ui/question_mark.rs:368:13
    |
 LL | /             if a.is_none() {
 LL | |                 return None;
@@ -142,12 +189,12 @@ LL | |             }
    | |_____________^ help: replace it with: `a?;`
 
 error: this `let...else` may be rewritten with the `?` operator
-  --> tests/ui/question_mark.rs:357:5
+  --> tests/ui/question_mark.rs:428:5
    |
 LL | /     let Some(v) = bar.foo.owned.clone() else {
 LL | |         return None;
 LL | |     };
    | |______^ help: replace it with: `let v = bar.foo.owned.clone()?;`
 
-error: aborting due to 17 previous errors
+error: aborting due to 22 previous errors
 
diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr
index 6403265a39c..6ef333f0cfd 100644
--- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr
+++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph-fix.stderr
@@ -6,7 +6,7 @@ LL | | /// A much longer explanation that goes into a lot more detail about
 LL | | /// how the thing works, possibly with doclinks and so one,
 LL | | /// and probably spanning a many rows. Blablabla, it needs to be over
 LL | | /// 200 characters so I needed to write something longeeeeeeer.
-   | |_
+   | |_^
    |
    = note: `-D clippy::too-long-first-doc-paragraph` implied by `-D warnings`
    = help: to override `-D warnings` add `#[allow(clippy::too_long_first_doc_paragraph)]`
diff --git a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr
index 39926647f54..95f42349b9b 100644
--- a/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr
+++ b/src/tools/clippy/tests/ui/too_long_first_doc_paragraph.stderr
@@ -23,7 +23,7 @@ error: first doc comment paragraph is too long
 LL | / /// Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia
 LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero,
 LL | | /// gravida non lacinia at, rhoncus eu lacus.
-   | |_
+   | |_^
 
 error: first doc comment paragraph is too long
   --> tests/ui/too_long_first_doc_paragraph.rs:36:1
@@ -32,7 +32,7 @@ LL | / /// Lorem
 LL | | /// ipsum dolor sit amet, consectetur adipiscing elit. Nunc turpis nunc, lacinia
 LL | | /// a dolor in, pellentesque aliquet enim. Cras nec maximus sem. Mauris arcu libero,
 LL | | /// gravida non lacinia at, rhoncus eu lacus.
-   | |_
+   | |_^
 
 error: aborting due to 3 previous errors
 
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.fixed b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
new file mode 100644
index 00000000000..2d932a70e9d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.fixed
@@ -0,0 +1,64 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unnecessary_map_or)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::unnecessary_lazy_evaluations)]
+#[clippy::msrv = "1.70.0"]
+#[macro_use]
+extern crate proc_macros;
+
+fn main() {
+    // should trigger
+    let _ = (Some(5) == Some(5));
+    let _ = (Some(5) != Some(5));
+    let _ = (Some(5) == Some(5));
+    let _ = Some(5).is_some_and(|n| {
+        let _ = n;
+        6 >= 5
+    });
+    let _ = Some(vec![5]).is_some_and(|n| n == [5]);
+    let _ = Some(vec![1]).is_some_and(|n| vec![2] == n);
+    let _ = Some(5).is_some_and(|n| n == n);
+    let _ = Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 });
+    let _ = Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5]);
+    let _ = (Ok::<i32, i32>(5) == Ok(5));
+    let _ = (Some(5) == Some(5)).then(|| 1);
+
+    // shouldnt trigger
+    let _ = Some(5).map_or(true, |n| n == 5);
+    let _ = Some(5).map_or(true, |n| 5 == n);
+    macro_rules! x {
+        () => {
+            Some(1)
+        };
+    }
+    // methods lints dont fire on macros
+    let _ = x!().map_or(false, |n| n == 1);
+    let _ = x!().map_or(false, |n| n == vec![1][0]);
+
+    msrv_1_69();
+
+    external! {
+        let _ = Some(5).map_or(false, |n| n == 5);
+    }
+
+    with_span! {
+        let _ = Some(5).map_or(false, |n| n == 5);
+    }
+
+    // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent
+    struct S;
+    let r: Result<i32, S> = Ok(3);
+    let _ = r.is_ok_and(|x| x == 7);
+
+    #[derive(PartialEq)]
+    struct S2;
+    let r: Result<i32, S2> = Ok(4);
+    let _ = (r == Ok(8));
+}
+
+#[clippy::msrv = "1.69.0"]
+fn msrv_1_69() {
+    // is_some_and added in 1.70.0
+    let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.rs b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
new file mode 100644
index 00000000000..4a9d69be1e9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.rs
@@ -0,0 +1,67 @@
+//@aux-build:proc_macros.rs
+#![warn(clippy::unnecessary_map_or)]
+#![allow(clippy::no_effect)]
+#![allow(clippy::eq_op)]
+#![allow(clippy::unnecessary_lazy_evaluations)]
+#[clippy::msrv = "1.70.0"]
+#[macro_use]
+extern crate proc_macros;
+
+fn main() {
+    // should trigger
+    let _ = Some(5).map_or(false, |n| n == 5);
+    let _ = Some(5).map_or(true, |n| n != 5);
+    let _ = Some(5).map_or(false, |n| {
+        let _ = 1;
+        n == 5
+    });
+    let _ = Some(5).map_or(false, |n| {
+        let _ = n;
+        6 >= 5
+    });
+    let _ = Some(vec![5]).map_or(false, |n| n == [5]);
+    let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
+    let _ = Some(5).map_or(false, |n| n == n);
+    let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
+    let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
+    let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
+    let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
+
+    // shouldnt trigger
+    let _ = Some(5).map_or(true, |n| n == 5);
+    let _ = Some(5).map_or(true, |n| 5 == n);
+    macro_rules! x {
+        () => {
+            Some(1)
+        };
+    }
+    // methods lints dont fire on macros
+    let _ = x!().map_or(false, |n| n == 1);
+    let _ = x!().map_or(false, |n| n == vec![1][0]);
+
+    msrv_1_69();
+
+    external! {
+        let _ = Some(5).map_or(false, |n| n == 5);
+    }
+
+    with_span! {
+        let _ = Some(5).map_or(false, |n| n == 5);
+    }
+
+    // check for presence of PartialEq, and alter suggestion to use `is_ok_and` if absent
+    struct S;
+    let r: Result<i32, S> = Ok(3);
+    let _ = r.map_or(false, |x| x == 7);
+
+    #[derive(PartialEq)]
+    struct S2;
+    let r: Result<i32, S2> = Ok(4);
+    let _ = r.map_or(false, |x| x == 8);
+}
+
+#[clippy::msrv = "1.69.0"]
+fn msrv_1_69() {
+    // is_some_and added in 1.70.0
+    let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_map_or.stderr b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
new file mode 100644
index 00000000000..299a4e5da7a
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_map_or.stderr
@@ -0,0 +1,99 @@
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:12:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+   |
+   = note: `-D clippy::unnecessary-map-or` implied by `-D warnings`
+   = help: to override `-D warnings` add `#[allow(clippy::unnecessary_map_or)]`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:13:13
+   |
+LL |     let _ = Some(5).map_or(true, |n| n != 5);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) != Some(5))`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:14:13
+   |
+LL |       let _ = Some(5).map_or(false, |n| {
+   |  _____________^
+LL | |         let _ = 1;
+LL | |         n == 5
+LL | |     });
+   | |______^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:18:13
+   |
+LL |       let _ = Some(5).map_or(false, |n| {
+   |  _____________^
+LL | |         let _ = n;
+LL | |         6 >= 5
+LL | |     });
+   | |______^
+   |
+help: use is_some_and instead
+   |
+LL ~     let _ = Some(5).is_some_and(|n| {
+LL +         let _ = n;
+LL +         6 >= 5
+LL ~     });
+   |
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:22:13
+   |
+LL |     let _ = Some(vec![5]).map_or(false, |n| n == [5]);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![5]).is_some_and(|n| n == [5])`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:23:13
+   |
+LL |     let _ = Some(vec![1]).map_or(false, |n| vec![2] == n);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(vec![1]).is_some_and(|n| vec![2] == n)`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:24:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == n);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == n)`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:25:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == if 2 > 1 { n } else { 0 });
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_some_and instead: `Some(5).is_some_and(|n| n == if 2 > 1 { n } else { 0 })`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:26:13
+   |
+LL |     let _ = Ok::<Vec<i32>, i32>(vec![5]).map_or(false, |n| n == [5]);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `Ok::<Vec<i32>, i32>(vec![5]).is_ok_and(|n| n == [5])`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:27:13
+   |
+LL |     let _ = Ok::<i32, i32>(5).map_or(false, |n| n == 5);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Ok::<i32, i32>(5) == Ok(5))`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:28:13
+   |
+LL |     let _ = Some(5).map_or(false, |n| n == 5).then(|| 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(Some(5) == Some(5))`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:55:13
+   |
+LL |     let _ = r.map_or(false, |x| x == 7);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use is_ok_and instead: `r.is_ok_and(|x| x == 7)`
+
+error: this `map_or` is redundant
+  --> tests/ui/unnecessary_map_or.rs:60:13
+   |
+LL |     let _ = r.map_or(false, |x| x == 8);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use a standard comparison instead: `(r == Ok(8))`
+
+error: aborting due to 13 previous errors
+
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index cef6b525a7b..b784bdb7139 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -14,7 +14,7 @@ unified-diff = "0.2.1"
 getopts = "0.2"
 indexmap = "2.0.0"
 miropt-test-tools = { path = "../miropt-test-tools" }
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 tracing = "0.1"
 tracing-subscriber = { version = "0.3.3", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] }
 regex = "1.0"
diff --git a/src/tools/compiletest/src/directive-list.rs b/src/tools/compiletest/src/directive-list.rs
index 8570a8ce115..bdd0b80b395 100644
--- a/src/tools/compiletest/src/directive-list.rs
+++ b/src/tools/compiletest/src/directive-list.rs
@@ -25,6 +25,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "dont-check-failure-status",
     "edition",
     "error-pattern",
+    "exact-llvm-major-version",
     "exec-env",
     "failure-status",
     "filecheck-flags",
@@ -35,6 +36,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "ignore-64bit",
     "ignore-aarch64",
     "ignore-aarch64-unknown-linux-gnu",
+    "ignore-aix",
     "ignore-android",
     "ignore-apple",
     "ignore-arm",
@@ -118,6 +120,7 @@ const KNOWN_DIRECTIVE_NAMES: &[&str] = &[
     "incremental",
     "known-bug",
     "llvm-cov-flags",
+    "max-llvm-major-version",
     "min-cdb-version",
     "min-gdb-version",
     "min-lldb-version",
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 300a03e5f33..3539e85ba63 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -1547,6 +1547,20 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
                 };
             }
         } else if let Some(version_string) =
+            config.parse_name_value_directive(line, "max-llvm-major-version")
+        {
+            let max_version = extract_llvm_version(&version_string);
+            // Ignore if actual major version is larger than the maximum required major version.
+            if actual_version.major > max_version.major {
+                return IgnoreDecision::Ignore {
+                    reason: format!(
+                        "ignored when the LLVM version ({actual_version}) is newer than major\
+                        version {}",
+                        max_version.major
+                    ),
+                };
+            }
+        } else if let Some(version_string) =
             config.parse_name_value_directive(line, "min-system-llvm-version")
         {
             let min_version = extract_llvm_version(&version_string);
@@ -1585,6 +1599,19 @@ fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision {
                     };
                 }
             }
+        } else if let Some(version_string) =
+            config.parse_name_value_directive(line, "exact-llvm-major-version")
+        {
+            // Syntax is "exact-llvm-major-version: <version>"
+            let version = extract_llvm_version(&version_string);
+            if actual_version.major != version.major {
+                return IgnoreDecision::Ignore {
+                    reason: format!(
+                        "ignored when the actual LLVM major version is {}, but the test only targets major version {}",
+                        actual_version.major, version.major
+                    ),
+                };
+            }
         }
     }
     IgnoreDecision::Continue
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index c3fb8d4ab80..4d75c38dd32 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -284,6 +284,30 @@ fn llvm_version() {
 
     let config: Config = cfg().llvm_version("10.0.0").build();
     assert!(!check_ignore(&config, "//@ min-llvm-version: 9.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(check_ignore(&config, "//@ exact-llvm-major-version: 9.0"));
+
+    let config: Config = cfg().llvm_version("9.0.0").build();
+    assert!(check_ignore(&config, "//@ exact-llvm-major-version: 10.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10.0"));
+
+    let config: Config = cfg().llvm_version("10.0.0").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10"));
+
+    let config: Config = cfg().llvm_version("10.6.2").build();
+    assert!(!check_ignore(&config, "//@ exact-llvm-major-version: 10"));
+
+    let config: Config = cfg().llvm_version("19.0.0").build();
+    assert!(!check_ignore(&config, "//@ max-llvm-major-version: 19"));
+
+    let config: Config = cfg().llvm_version("19.1.2").build();
+    assert!(!check_ignore(&config, "//@ max-llvm-major-version: 19"));
+
+    let config: Config = cfg().llvm_version("20.0.0").build();
+    assert!(check_ignore(&config, "//@ max-llvm-major-version: 19"));
 }
 
 #[test]
diff --git a/src/tools/miri/rust-version b/src/tools/miri/rust-version
index 07d41ad7fa3..6c84893627a 100644
--- a/src/tools/miri/rust-version
+++ b/src/tools/miri/rust-version
@@ -1 +1 @@
-c22887b4d97400e8e024e19fb5f724eda65ad58d
+3bc6916f4ca50bb83b211d9013dac38e84618750
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index 63591474120..41b7be37c37 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -195,7 +195,7 @@ pub fn prune_stacktrace<'tcx>(
                 // This len check ensures that we don't somehow remove every frame, as doing so breaks
                 // the primary error message.
                 while stacktrace.len() > 1
-                    && stacktrace.last().map_or(false, |frame| !machine.is_local(frame))
+                    && stacktrace.last().is_some_and(|frame| !machine.is_local(frame))
                 {
                     stacktrace.pop();
                 }
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index d34f8ad0520..d0413911014 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 env_logger = "0.11"
 log = "0.4"
 anyhow = { version = "1", features = ["backtrace"] }
diff --git a/src/tools/run-make-support/Cargo.toml b/src/tools/run-make-support/Cargo.toml
index 3affa199fa5..3c172b2d956 100644
--- a/src/tools/run-make-support/Cargo.toml
+++ b/src/tools/run-make-support/Cargo.toml
@@ -10,7 +10,7 @@ similar = "2.5.0"
 wasmparser = { version = "0.216", default-features = false, features = ["std"] }
 regex = "1.8" # 1.8 to avoid memchr 2.6.0, as 2.5.0 is pinned in the workspace
 gimli = "0.31.0"
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 serde_json = "1.0"
 libc = "0.2"
 
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 35d983dc607..494daeca963 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -5,7 +5,7 @@ use crate::command::Command;
 use crate::env::env_var;
 use crate::path_helpers::cwd;
 use crate::util::set_host_rpath;
-use crate::{is_darwin, is_msvc, is_windows, uname};
+use crate::{is_aix, is_darwin, is_msvc, is_windows, uname};
 
 /// Construct a new `rustc` invocation. This will automatically set the library
 /// search path as `-L cwd()`. Use [`bare_rustc`] to avoid this.
@@ -346,7 +346,7 @@ impl Rustc {
         //     endif
         // endif
         // ```
-        let flag = if is_windows() {
+        if is_windows() {
             // So this is a bit hacky: we can't use the DLL version of libstdc++ because
             // it pulls in the DLL version of libgcc, which means that we end up with 2
             // instances of the DW2 unwinding implementation. This is a problem on
@@ -362,18 +362,19 @@ impl Rustc {
             // So we end up with the following hack: we link use static:-bundle to only
             // link the parts of libstdc++ that we actually use, which doesn't include
             // the dependency on the pthreads DLL.
-            if is_msvc() { None } else { Some("-lstatic:-bundle=stdc++") }
+            if !is_msvc() {
+                self.cmd.arg("-lstatic:-bundle=stdc++");
+            };
         } else if is_darwin() {
-            Some("-lc++")
+            self.cmd.arg("-lc++");
+        } else if is_aix() {
+            self.cmd.arg("-lc++");
+            self.cmd.arg("-lc++abi");
         } else {
-            match &uname()[..] {
-                "FreeBSD" | "SunOS" | "OpenBSD" => None,
-                _ => Some("-lstdc++"),
-            }
+            if !matches!(&uname()[..], "FreeBSD" | "SunOS" | "OpenBSD") {
+                self.cmd.arg("-lstdc++");
+            };
         };
-        if let Some(flag) = flag {
-            self.cmd.arg(flag);
-        }
         self
     }
 }
diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs
index 5765cb97a7e..6cf0aedfe9f 100644
--- a/src/tools/run-make-support/src/lib.rs
+++ b/src/tools/run-make-support/src/lib.rs
@@ -78,7 +78,7 @@ pub use env::{env_var, env_var_os, set_current_dir};
 pub use run::{cmd, run, run_fail, run_with_args};
 
 /// Helpers for checking target information.
-pub use targets::{is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os};
+pub use targets::{is_aix, is_darwin, is_msvc, is_windows, llvm_components_contain, target, uname, apple_os};
 
 /// Helpers for building names of output artifacts that are potentially target-specific.
 pub use artifact_names::{
diff --git a/src/tools/run-make-support/src/targets.rs b/src/tools/run-make-support/src/targets.rs
index 896abb73fc1..ae004fd0cbd 100644
--- a/src/tools/run-make-support/src/targets.rs
+++ b/src/tools/run-make-support/src/targets.rs
@@ -28,6 +28,12 @@ pub fn is_darwin() -> bool {
     target().contains("darwin")
 }
 
+/// Check if target uses AIX.
+#[must_use]
+pub fn is_aix() -> bool {
+    target().contains("aix")
+}
+
 /// Get the target OS on Apple operating systems.
 #[must_use]
 pub fn apple_os() -> &'static str {
diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
index e0135a0269a..5258d9ddd3a 100644
--- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
@@ -53,7 +53,6 @@ jobs:
           cargo workspaces rename --from project-model project_model
           cargo workspaces rename --from test-fixture test_fixture
           cargo workspaces rename --from test-utils test_utils
-          cargo workspaces rename --from text-edit text_edit
           # Remove library crates from the workspaces so we don't auto-publish them as well
           sed -i 's/ "lib\/\*",//' ./Cargo.toml
           cargo workspaces rename ra_ap_%n
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 6d07dc8f9be..2a13f74aac7 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -13,7 +13,6 @@ use syntax::{ast, Parse};
 use triomphe::Arc;
 
 use crate::{
-    attr::Attrs,
     db::DefDatabase,
     expander::{Expander, Mark},
     item_tree::{self, AssocItem, FnFlags, ItemTree, ItemTreeId, MacroCall, ModItem, TreeId},
@@ -37,8 +36,6 @@ pub struct FunctionData {
     pub name: Name,
     pub params: Box<[TypeRefId]>,
     pub ret_type: TypeRefId,
-    // FIXME: why are these stored here? They should be accessed via the query
-    pub attrs: Attrs,
     pub visibility: RawVisibility,
     pub abi: Option<Symbol>,
     pub legacy_const_generics_indices: Option<Box<Box<[u32]>>>,
@@ -115,7 +112,6 @@ impl FunctionData {
                 .filter_map(|(_, param)| param.type_ref)
                 .collect(),
             ret_type: func.ret_type,
-            attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
             visibility,
             abi: func.abi.clone(),
             legacy_const_generics_indices,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
index 5c25a55362e..95dfe56ff54 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs
@@ -633,6 +633,19 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe"
     ),
     rustc_attr!(
+        rustc_intrinsic, Normal, template!(Word), ErrorFollowing,
+        "the `#[rustc_intrinsic]` attribute is used to declare intrinsics with function bodies",
+    ),
+    rustc_attr!(
+        rustc_no_mir_inline, Normal, template!(Word), WarnFollowing,
+        "#[rustc_no_mir_inline] prevents the MIR inliner from inlining a function while not affecting codegen"
+    ),
+    rustc_attr!(
+        rustc_intrinsic_must_be_overridden, Normal, template!(Word), ErrorFollowing,
+        "the `#[rustc_intrinsic_must_be_overridden]` attribute is used to declare intrinsics without real bodies",
+    ),
+
+    rustc_attr!(
         rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing,
         "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024",
     ),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index 05cd7bd37b4..53795c0b600 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -381,8 +381,9 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
         TyKind::Error.intern(Interner)
     }
 
+    // object safety was renamed to dyn-compatibility but still remains here in chalk.
+    // This will be removed since we are going to migrate to next-gen trait solver.
     fn is_object_safe(&self, trait_id: chalk_ir::TraitId<Interner>) -> bool {
-        // FIXME: When cargo is updated, change to dyn_compatibility
         let trait_ = from_chalk_trait_id(trait_id);
         crate::dyn_compatibility::dyn_compatibility(self.db, trait_).is_none()
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
index c5706172b20..c1ac7ae173b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -4,9 +4,8 @@ use super::*;
 fn size_of() {
     check_number(
         r#"
-        extern "rust-intrinsic" {
-            pub fn size_of<T>() -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of<T>() -> usize;
 
         const GOAL: usize = size_of::<i32>();
         "#,
@@ -19,9 +18,8 @@ fn size_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         struct X(i32, u8);
 
@@ -32,9 +30,8 @@ fn size_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         const GOAL: usize = {
             let it: &[i32] = &[1, 2, 3];
@@ -48,9 +45,8 @@ fn size_of_val() {
         //- minicore: coerce_unsized, transmute
         use core::mem::transmute;
 
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         struct X {
             x: i64,
@@ -70,9 +66,8 @@ fn size_of_val() {
         //- minicore: coerce_unsized, transmute
         use core::mem::transmute;
 
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         struct X {
             x: i32,
@@ -90,9 +85,8 @@ fn size_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized, fmt, builtin_impls, dispatch_from_dyn
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         const GOAL: usize = {
             let x: &i16 = &5;
@@ -106,9 +100,8 @@ fn size_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
-        extern "rust-intrinsic" {
-            pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
 
         const GOAL: usize = {
             size_of_val("salam")
@@ -123,9 +116,8 @@ fn min_align_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
-        extern "rust-intrinsic" {
-            pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
 
         struct X(i32, u8);
 
@@ -136,9 +128,8 @@ fn min_align_of_val() {
     check_number(
         r#"
         //- minicore: coerce_unsized
-        extern "rust-intrinsic" {
-            pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
-        }
+        #[rustc_intrinsic]
+        pub fn min_align_of_val<T: ?Sized>(_: *const T) -> usize;
 
         const GOAL: usize = {
             let x: &[i32] = &[1, 2, 3];
@@ -153,9 +144,8 @@ fn min_align_of_val() {
 fn type_name() {
     check_str(
         r#"
-        extern "rust-intrinsic" {
-            pub fn type_name<T: ?Sized>() -> &'static str;
-        }
+        #[rustc_intrinsic]
+        pub fn type_name<T: ?Sized>() -> &'static str;
 
         const GOAL: &str = type_name::<i32>();
         "#,
@@ -163,9 +153,8 @@ fn type_name() {
     );
     check_str(
         r#"
-        extern "rust-intrinsic" {
-            pub fn type_name<T: ?Sized>() -> &'static str;
-        }
+        #[rustc_intrinsic]
+        pub fn type_name<T: ?Sized>() -> &'static str;
 
         mod mod1 {
             pub mod mod2 {
@@ -183,9 +172,8 @@ fn type_name() {
 fn transmute() {
     check_number(
         r#"
-        extern "rust-intrinsic" {
-            pub fn transmute<T, U>(e: T) -> U;
-        }
+        #[rustc_intrinsic]
+        pub fn transmute<T, U>(e: T) -> U;
 
         const GOAL: i32 = transmute((1i16, 1i16));
         "#,
@@ -197,10 +185,10 @@ fn transmute() {
 fn read_via_copy() {
     check_number(
         r#"
-        extern "rust-intrinsic" {
-            pub fn read_via_copy<T>(e: *const T) -> T;
-            pub fn volatile_load<T>(e: *const T) -> T;
-        }
+        #[rustc_intrinsic]
+        pub fn read_via_copy<T>(e: *const T) -> T;
+        #[rustc_intrinsic]
+        pub fn volatile_load<T>(e: *const T) -> T;
 
         const GOAL: i32 = {
             let x = 2;
@@ -399,9 +387,14 @@ fn discriminant_value() {
 fn likely() {
     check_number(
         r#"
-        extern "rust-intrinsic" {
-            pub fn likely(b: bool) -> bool;
-            pub fn unlikely(b: bool) -> bool;
+        #[rustc_intrinsic]
+        pub const fn likely(b: bool) -> bool {
+            b
+        }
+
+        #[rustc_intrinsic]
+        pub const fn unlikely(b: bool) -> bool {
+            b
         }
 
         const GOAL: bool = likely(true) && unlikely(true) && !likely(false) && !unlikely(false);
@@ -704,9 +697,8 @@ fn rotate() {
     );
     check_number(
         r#"
-        extern "rust-intrinsic" {
-            pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
-        }
+        #[rustc_intrinsic]
+        pub fn rotate_right<T: Copy>(x: T, y: T) -> T;
 
         const GOAL: i32 = rotate_right(10006016, 1020315);
         "#,
@@ -721,9 +713,8 @@ fn simd() {
         pub struct i8x16(
             i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
         );
-        extern "platform-intrinsic" {
-            pub fn simd_bitmask<T, U>(x: T) -> U;
-        }
+        #[rustc_intrinsic]
+        pub fn simd_bitmask<T, U>(x: T) -> U;
         const GOAL: u16 = simd_bitmask(i8x16(
             0, 1, 0, 0, 2, 255, 100, 0, 50, 0, 1, 1, 0, 0, 0, 0
         ));
@@ -735,10 +726,10 @@ fn simd() {
         pub struct i8x16(
             i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,i8,
         );
-        extern "platform-intrinsic" {
-            pub fn simd_lt<T, U>(x: T, y: T) -> U;
-            pub fn simd_bitmask<T, U>(x: T) -> U;
-        }
+        #[rustc_intrinsic]
+        pub fn simd_lt<T, U>(x: T, y: T) -> U;
+        #[rustc_intrinsic]
+        pub fn simd_bitmask<T, U>(x: T) -> U;
         const GOAL: u16 = simd_bitmask(simd_lt::<i8x16, i8x16>(
             i8x16(
                 -105, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
index c9ab0acc084..4991d173b9c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs
@@ -201,7 +201,7 @@ impl<'a> DeclValidator<'a> {
 
             // Don't run the lint on extern "[not Rust]" fn items with the
             // #[no_mangle] attribute.
-            let no_mangle = data.attrs.by_key(&sym::no_mangle).exists();
+            let no_mangle = self.db.attrs(func.into()).by_key(&sym::no_mangle).exists();
             if no_mangle && data.abi.as_ref().is_some_and(|abi| *abi != sym::Rust) {
                 cov_mark::hit!(extern_func_no_mangle_ignored);
             } else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
index 3d21785a70a..fadf8aca998 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility.rs
@@ -472,7 +472,7 @@ fn receiver_is_dispatchable(
         return false;
     };
 
-    // `self: Self` can't be dispatched on, but this is already considered dyn compatible
+    // `self: Self` can't be dispatched on, but this is already considered dyn-compatible
     // See rustc's comment on https://github.com/rust-lang/rust/blob/3f121b9461cce02a703a0e7e450568849dfaa074/compiler/rustc_trait_selection/src/traits/object_safety.rs#L433-L437
     if sig
         .skip_binders()
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
index 3f3e68eeb1c..8a56bd28b59 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/dyn_compatibility/tests.rs
@@ -66,7 +66,7 @@ fn check_dyn_compatibility<'a>(
             });
             ControlFlow::Continue(())
         });
-        assert_eq!(osvs, expected, "Dyn Compatibility violations for `{name}` do not match;");
+        assert_eq!(osvs, expected, "dyn-compatibility violations for `{name}` do not match;");
     }
 
     let remains: Vec<_> = expected.keys().collect();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index 9c1d8bcf36f..22e7b1d920f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -98,7 +98,7 @@ pub use mapping::{
 };
 pub use method_resolution::check_orphan_rules;
 pub use traits::TraitEnvironment;
-pub use utils::{all_super_traits, is_fn_unsafe_to_call};
+pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call};
 
 pub use chalk_ir::{
     cast::Cast,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 0cdad74a4f6..0a78f4a5b24 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -9,7 +9,7 @@ use hir_def::{
     resolver::HasResolver,
 };
 use hir_expand::name::Name;
-use intern::sym;
+use intern::{sym, Symbol};
 
 use crate::{
     error_lifetime,
@@ -54,49 +54,32 @@ impl Evaluator<'_> {
         }
 
         let function_data = self.db.function_data(def);
-        let is_intrinsic = match &function_data.abi {
-            Some(abi) => *abi == sym::rust_dash_intrinsic,
-            None => match def.lookup(self.db.upcast()).container {
-                hir_def::ItemContainerId::ExternBlockId(block) => {
-                    let id = block.lookup(self.db.upcast()).id;
-                    id.item_tree(self.db.upcast())[id.value].abi.as_ref()
-                        == Some(&sym::rust_dash_intrinsic)
-                }
-                _ => false,
-            },
-        };
+        let attrs = self.db.attrs(def.into());
+        let is_intrinsic = attrs.by_key(&sym::rustc_intrinsic).exists()
+            // Keep this around for a bit until extern "rustc-intrinsic" abis are no longer used
+            || (match &function_data.abi {
+                Some(abi) => *abi == sym::rust_dash_intrinsic,
+                None => match def.lookup(self.db.upcast()).container {
+                    hir_def::ItemContainerId::ExternBlockId(block) => {
+                        let id = block.lookup(self.db.upcast()).id;
+                        id.item_tree(self.db.upcast())[id.value].abi.as_ref()
+                            == Some(&sym::rust_dash_intrinsic)
+                    }
+                    _ => false,
+                },
+            });
+
         if is_intrinsic {
-            self.exec_intrinsic(
+            return self.exec_intrinsic(
                 function_data.name.as_str(),
                 args,
                 generic_args,
                 destination,
                 locals,
                 span,
-            )?;
-            return Ok(true);
-        }
-        let is_platform_intrinsic = match &function_data.abi {
-            Some(abi) => *abi == sym::platform_dash_intrinsic,
-            None => match def.lookup(self.db.upcast()).container {
-                hir_def::ItemContainerId::ExternBlockId(block) => {
-                    let id = block.lookup(self.db.upcast()).id;
-                    id.item_tree(self.db.upcast())[id.value].abi.as_ref()
-                        == Some(&sym::platform_dash_intrinsic)
-                }
-                _ => false,
-            },
-        };
-        if is_platform_intrinsic {
-            self.exec_platform_intrinsic(
-                function_data.name.as_str(),
-                args,
-                generic_args,
-                destination,
-                locals,
-                span,
-            )?;
-            return Ok(true);
+                !function_data.has_body()
+                    || attrs.by_key(&sym::rustc_intrinsic_must_be_overridden).exists(),
+            );
         }
         let is_extern_c = match def.lookup(self.db.upcast()).container {
             hir_def::ItemContainerId::ExternBlockId(block) => {
@@ -106,27 +89,25 @@ impl Evaluator<'_> {
             _ => false,
         };
         if is_extern_c {
-            self.exec_extern_c(
-                function_data.name.as_str(),
-                args,
-                generic_args,
-                destination,
-                locals,
-                span,
-            )?;
-            return Ok(true);
+            return self
+                .exec_extern_c(
+                    function_data.name.as_str(),
+                    args,
+                    generic_args,
+                    destination,
+                    locals,
+                    span,
+                )
+                .map(|()| true);
         }
-        let alloc_fn = function_data
-            .attrs
-            .iter()
-            .filter_map(|it| it.path().as_ident())
-            .map(|it| it.as_str())
-            .find(|it| {
+
+        let alloc_fn =
+            attrs.iter().filter_map(|it| it.path().as_ident()).map(|it| it.symbol()).find(|it| {
                 [
-                    "rustc_allocator",
-                    "rustc_deallocator",
-                    "rustc_reallocator",
-                    "rustc_allocator_zeroed",
+                    &sym::rustc_allocator,
+                    &sym::rustc_deallocator,
+                    &sym::rustc_reallocator,
+                    &sym::rustc_allocator_zeroed,
                 ]
                 .contains(it)
             });
@@ -270,12 +251,12 @@ impl Evaluator<'_> {
 
     fn exec_alloc_fn(
         &mut self,
-        alloc_fn: &str,
+        alloc_fn: &Symbol,
         args: &[IntervalAndTy],
         destination: Interval,
     ) -> Result<()> {
         match alloc_fn {
-            "rustc_allocator_zeroed" | "rustc_allocator" => {
+            _ if *alloc_fn == sym::rustc_allocator_zeroed || *alloc_fn == sym::rustc_allocator => {
                 let [size, align] = args else {
                     return Err(MirEvalError::InternalError(
                         "rustc_allocator args are not provided".into(),
@@ -286,8 +267,8 @@ impl Evaluator<'_> {
                 let result = self.heap_allocate(size, align)?;
                 destination.write_from_bytes(self, &result.to_bytes())?;
             }
-            "rustc_deallocator" => { /* no-op for now */ }
-            "rustc_reallocator" => {
+            _ if *alloc_fn == sym::rustc_deallocator => { /* no-op for now */ }
+            _ if *alloc_fn == sym::rustc_reallocator => {
                 let [ptr, old_size, align, new_size] = args else {
                     return Err(MirEvalError::InternalError(
                         "rustc_allocator args are not provided".into(),
@@ -603,21 +584,6 @@ impl Evaluator<'_> {
         }
     }
 
-    fn exec_platform_intrinsic(
-        &mut self,
-        name: &str,
-        args: &[IntervalAndTy],
-        generic_args: &Substitution,
-        destination: Interval,
-        locals: &Locals,
-        span: MirSpan,
-    ) -> Result<()> {
-        if let Some(name) = name.strip_prefix("simd_") {
-            return self.exec_simd_intrinsic(name, args, generic_args, destination, locals, span);
-        }
-        not_supported!("unknown platform intrinsic {name}");
-    }
-
     fn exec_intrinsic(
         &mut self,
         name: &str,
@@ -626,9 +592,17 @@ impl Evaluator<'_> {
         destination: Interval,
         locals: &Locals,
         span: MirSpan,
-    ) -> Result<()> {
+        needs_override: bool,
+    ) -> Result<bool> {
         if let Some(name) = name.strip_prefix("atomic_") {
-            return self.exec_atomic_intrinsic(name, args, generic_args, destination, locals, span);
+            return self
+                .exec_atomic_intrinsic(name, args, generic_args, destination, locals, span)
+                .map(|()| true);
+        }
+        if let Some(name) = name.strip_prefix("simd_") {
+            return self
+                .exec_simd_intrinsic(name, args, generic_args, destination, locals, span)
+                .map(|()| true);
         }
         // FIXME(#17451): Add `f16` and `f128` intrinsics.
         if let Some(name) = name.strip_suffix("f64") {
@@ -701,7 +675,7 @@ impl Evaluator<'_> {
                 }
                 _ => not_supported!("unknown f64 intrinsic {name}"),
             };
-            return destination.write_from_bytes(self, &result.to_le_bytes());
+            return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
         }
         if let Some(name) = name.strip_suffix("f32") {
             let result = match name {
@@ -773,7 +747,7 @@ impl Evaluator<'_> {
                 }
                 _ => not_supported!("unknown f32 intrinsic {name}"),
             };
-            return destination.write_from_bytes(self, &result.to_le_bytes());
+            return destination.write_from_bytes(self, &result.to_le_bytes()).map(|()| true);
         }
         match name {
             "size_of" => {
@@ -1146,12 +1120,6 @@ impl Evaluator<'_> {
                 };
                 destination.write_from_interval(self, arg.interval)
             }
-            "likely" | "unlikely" => {
-                let [arg] = args else {
-                    return Err(MirEvalError::InternalError("likely arg is not provided".into()));
-                };
-                destination.write_from_interval(self, arg.interval)
-            }
             "ctpop" => {
                 let [arg] = args else {
                     return Err(MirEvalError::InternalError("ctpop arg is not provided".into()));
@@ -1296,7 +1264,7 @@ impl Evaluator<'_> {
                             None,
                             span,
                         )?;
-                        return Ok(());
+                        return Ok(true);
                     }
                 }
                 not_supported!("FnOnce was not available for executing const_eval_select");
@@ -1349,8 +1317,10 @@ impl Evaluator<'_> {
                 self.write_memory_using_ref(dst, size)?.fill(val);
                 Ok(())
             }
-            _ => not_supported!("unknown intrinsic {name}"),
+            _ if needs_override => not_supported!("intrinsic {name} is not implemented"),
+            _ => return Ok(false),
         }
+        .map(|()| true)
     }
 
     fn size_align_of_unsized(
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
index 0a436ff2b41..28bda1e10e5 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -43,6 +43,17 @@ pub(crate) fn fn_traits(
         .flat_map(|it| it.as_trait())
 }
 
+/// Returns an iterator over the direct super traits (including the trait itself).
+pub fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
+    let mut result = smallvec![trait_];
+    direct_super_traits_cb(db, trait_, |tt| {
+        if !result.contains(&tt) {
+            result.push(tt);
+        }
+    });
+    result
+}
+
 /// Returns an iterator over the whole super trait hierarchy (including the
 /// trait itself).
 pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[TraitId; 4]> {
@@ -54,7 +65,7 @@ pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trai
     while let Some(&t) = result.get(i) {
         // yeah this is quadratic, but trait hierarchies should be flat
         // enough that this doesn't matter
-        direct_super_traits(db, t, |tt| {
+        direct_super_traits_cb(db, t, |tt| {
             if !result.contains(&tt) {
                 result.push(tt);
             }
@@ -153,7 +164,7 @@ impl Iterator for ClauseElaborator<'_> {
     }
 }
 
-fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
+fn direct_super_traits_cb(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) {
     let resolver = trait_.resolver(db);
     let generic_params = db.generic_params(trait_.into());
     let trait_self = generic_params.trait_self_param();
@@ -259,25 +270,25 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
         return true;
     }
 
+    let is_intrinsic = db.attrs(func.into()).by_key(&sym::rustc_intrinsic).exists()
+        || data.abi.as_ref() == Some(&sym::rust_dash_intrinsic);
+
     let loc = func.lookup(db.upcast());
     match loc.container {
         hir_def::ItemContainerId::ExternBlockId(block) => {
-            // Function in an `extern` block are always unsafe to call, except when
-            // it is marked as `safe` or it has `"rust-intrinsic"` ABI there are a
-            // few exceptions.
-            let id = block.lookup(db.upcast()).id;
-
-            let is_intrinsic =
-                id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic);
-
-            if is_intrinsic {
+            if is_intrinsic || {
+                let id = block.lookup(db.upcast()).id;
+                id.item_tree(db.upcast())[id.value].abi.as_ref() == Some(&sym::rust_dash_intrinsic)
+            } {
                 // Intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
-                !data.attrs.by_key(&sym::rustc_safe_intrinsic).exists()
+                !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists()
             } else {
-                // Extern items without `safe` modifier are always unsafe
+                // Function in an `extern` block are always unsafe to call, except when
+                // it is marked as `safe`.
                 !data.is_safe()
             }
         }
+        _ if is_intrinsic => !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists(),
         _ => false,
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index ebd84fd2be2..c9498b3aead 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -68,7 +68,7 @@ use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
     diagnostics::BodyValidationDiagnostic,
-    error_lifetime, known_const_to_ast,
+    direct_super_traits, error_lifetime, known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
     method_resolution,
     mir::{interpret_mir, MutBorrowKind},
@@ -2246,35 +2246,33 @@ impl Function {
 
     /// Does this function have `#[test]` attribute?
     pub fn is_test(self, db: &dyn HirDatabase) -> bool {
-        db.function_data(self.id).attrs.is_test()
+        db.attrs(self.id.into()).is_test()
     }
 
     /// is this a `fn main` or a function with an `export_name` of `main`?
     pub fn is_main(self, db: &dyn HirDatabase) -> bool {
-        let data = db.function_data(self.id);
-        data.attrs.export_name() == Some(&sym::main)
-            || self.module(db).is_crate_root() && data.name == sym::main
+        db.attrs(self.id.into()).export_name() == Some(&sym::main)
+            || self.module(db).is_crate_root() && db.function_data(self.id).name == sym::main
     }
 
     /// Is this a function with an `export_name` of `main`?
     pub fn exported_main(self, db: &dyn HirDatabase) -> bool {
-        let data = db.function_data(self.id);
-        data.attrs.export_name() == Some(&sym::main)
+        db.attrs(self.id.into()).export_name() == Some(&sym::main)
     }
 
     /// Does this function have the ignore attribute?
     pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
-        db.function_data(self.id).attrs.is_ignore()
+        db.attrs(self.id.into()).is_ignore()
     }
 
     /// Does this function have `#[bench]` attribute?
     pub fn is_bench(self, db: &dyn HirDatabase) -> bool {
-        db.function_data(self.id).attrs.is_bench()
+        db.attrs(self.id.into()).is_bench()
     }
 
     /// Is this function marked as unstable with `#[feature]` attribute?
     pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
-        db.function_data(self.id).attrs.is_unstable()
+        db.attrs(self.id.into()).is_unstable()
     }
 
     pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
@@ -2289,8 +2287,7 @@ impl Function {
     }
 
     pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
-        let function_data = db.function_data(self.id);
-        let attrs = &function_data.attrs;
+        let attrs = db.attrs(self.id.into());
         // FIXME: Store this in FunctionData flags?
         if !(attrs.is_proc_macro()
             || attrs.is_proc_macro_attribute()
@@ -2707,13 +2704,22 @@ impl Trait {
         db.trait_data(self.id).name.clone()
     }
 
+    pub fn direct_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> {
+        let traits = direct_super_traits(db.upcast(), self.into());
+        traits.iter().map(|tr| Trait::from(*tr)).collect()
+    }
+
+    pub fn all_supertraits(self, db: &dyn HirDatabase) -> Vec<Trait> {
+        let traits = all_super_traits(db.upcast(), self.into());
+        traits.iter().map(|tr| Trait::from(*tr)).collect()
+    }
+
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
         db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
     }
 
     pub fn items_with_supertraits(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
-        let traits = all_super_traits(db.upcast(), self.into());
-        traits.iter().flat_map(|tr| Trait::from(*tr).items(db)).collect()
+        self.all_supertraits(db).into_iter().flat_map(|tr| tr.items(db)).collect()
     }
 
     pub fn is_auto(self, db: &dyn HirDatabase) -> bool {
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 055080ad17b..5ef65c209ca 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -19,6 +19,7 @@ pub struct StructureNode {
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub enum StructureNodeKind {
     SymbolKind(SymbolKind),
+    ExternBlock,
     Region,
 }
 
@@ -158,6 +159,7 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
             ast::Trait(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Trait)),
             ast::TraitAlias(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::TraitAlias)),
             ast::Module(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Module)),
+            ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
             ast::TypeAlias(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::TypeAlias)),
             ast::RecordField(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Field)),
             ast::Const(it) => decl_with_type_ref(&it, it.ty(), StructureNodeKind::SymbolKind(SymbolKind::Const)),
@@ -205,7 +207,23 @@ fn structure_node(node: &SyntaxNode) -> Option<StructureNode> {
 
                 Some(node)
             },
-            ast::Macro(it) => decl(it, StructureNodeKind::SymbolKind(SymbolKind::Macro)),
+            ast::ExternBlock(it) => {
+                let mut label = "extern".to_owned();
+                let abi = it.abi()?;
+                if let Some(abi) = abi.string_token() {
+                    label.push(' ');
+                    label.push_str(abi.text());
+                }
+                Some(StructureNode {
+                    parent: None,
+                    label,
+                    navigation_range: abi.syntax().text_range(),
+                    node_range: it.syntax().text_range(),
+                    kind: StructureNodeKind::ExternBlock,
+                    detail: None,
+                    deprecated: false,
+                })
+            },
             _ => None,
         }
     }
@@ -327,6 +345,8 @@ fn f() {}
 fn g() {}
 }
 
+extern "C" {}
+
 fn let_statements() {
     let x = 42;
     let mut y = x;
@@ -664,9 +684,18 @@ fn let_statements() {
                     },
                     StructureNode {
                         parent: None,
+                        label: "extern \"C\"",
+                        navigation_range: 638..648,
+                        node_range: 638..651,
+                        kind: ExternBlock,
+                        detail: None,
+                        deprecated: false,
+                    },
+                    StructureNode {
+                        parent: None,
                         label: "let_statements",
-                        navigation_range: 641..655,
-                        node_range: 638..798,
+                        navigation_range: 656..670,
+                        node_range: 653..813,
                         kind: SymbolKind(
                             Function,
                         ),
@@ -677,11 +706,11 @@ fn let_statements() {
                     },
                     StructureNode {
                         parent: Some(
-                            26,
+                            27,
                         ),
                         label: "x",
-                        navigation_range: 668..669,
-                        node_range: 664..675,
+                        navigation_range: 683..684,
+                        node_range: 679..690,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -690,11 +719,11 @@ fn let_statements() {
                     },
                     StructureNode {
                         parent: Some(
-                            26,
+                            27,
                         ),
                         label: "mut y",
-                        navigation_range: 684..689,
-                        node_range: 680..694,
+                        navigation_range: 699..704,
+                        node_range: 695..709,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -703,11 +732,11 @@ fn let_statements() {
                     },
                     StructureNode {
                         parent: Some(
-                            26,
+                            27,
                         ),
                         label: "Foo { .. }",
-                        navigation_range: 703..725,
-                        node_range: 699..738,
+                        navigation_range: 718..740,
+                        node_range: 714..753,
                         kind: SymbolKind(
                             Local,
                         ),
@@ -716,11 +745,11 @@ fn let_statements() {
                     },
                     StructureNode {
                         parent: Some(
-                            26,
+                            27,
                         ),
                         label: "_",
-                        navigation_range: 788..789,
-                        node_range: 784..796,
+                        navigation_range: 803..804,
+                        node_range: 799..811,
                         kind: SymbolKind(
                             Local,
                         ),
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index d9ddc2d015b..5a00d635698 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1009,10 +1009,10 @@ fn render_dyn_compatibility(
     safety: Option<DynCompatibilityViolation>,
 ) {
     let Some(osv) = safety else {
-        buf.push_str("Is Dyn compatible");
+        buf.push_str("Is dyn-compatible");
         return;
     };
-    buf.push_str("Is not Dyn compatible due to ");
+    buf.push_str("Is not dyn-compatible due to ");
     match osv {
         DynCompatibilityViolation::SizedSelf => {
             buf.push_str("having a `Self: Sized` bound");
@@ -1055,7 +1055,7 @@ fn render_dyn_compatibility(
         }
         DynCompatibilityViolation::HasNonCompatibleSuperTrait(super_trait) => {
             let name = hir::Trait::from(super_trait).name(db);
-            format_to!(buf, "having a dyn incompatible supertrait `{}`", name.as_str());
+            format_to!(buf, "having a dyn-incompatible supertrait `{}`", name.as_str());
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 0ffbf988c35..0986d5542cd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -9371,7 +9371,7 @@ trait Compat$0 {}
 
             ---
 
-            Is Dyn compatible
+            Is dyn-compatible
         "#]],
     );
     check(
@@ -9393,7 +9393,7 @@ trait UnCompat$0 {
 
             ---
 
-            Is not Dyn compatible due to having a method `f` that is not dispatchable due to missing a receiver
+            Is not dyn-compatible due to having a method `f` that is not dispatchable due to missing a receiver
         "#]],
     );
     check(
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index aecafb444c3..865518fe941 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -392,18 +392,22 @@ define_symbols! {
     rust_2024,
     rust_analyzer,
     Rust,
+    rustc_allocator_zeroed,
+    rustc_allocator,
     rustc_allow_incoherent_impl,
     rustc_builtin_macro,
     rustc_coherence_is_core,
     rustc_const_panic_str,
+    rustc_deallocator,
     rustc_deprecated_safe_2024,
     rustc_has_incoherent_inherent_impls,
-    rustc_intrinsic,
     rustc_intrinsic_must_be_overridden,
+    rustc_intrinsic,
     rustc_layout_scalar_valid_range_end,
     rustc_layout_scalar_valid_range_start,
     rustc_legacy_const_generics,
     rustc_macro_transparency,
+    rustc_reallocator,
     rustc_reservation_impl,
     rustc_safe_intrinsic,
     rustc_skip_array_during_method_dispatch,
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index fa584ab4d21..a5c9d2823e0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -1131,7 +1131,7 @@ pub(crate) fn handle_completion_resolve(
     else {
         return Ok(original_completion);
     };
-    let resolved_completions = to_proto::completion_items(
+    let mut resolved_completions = to_proto::completion_items(
         &snap.config,
         &forced_resolve_completions_config.fields_to_resolve,
         &line_index,
@@ -1140,15 +1140,13 @@ pub(crate) fn handle_completion_resolve(
         resolve_data.trigger_character,
         resolved_completions,
     );
-    let Some(mut resolved_completion) = resolved_completions.into_iter().find(|completion| {
-        completion.label == original_completion.label
-            && completion.kind == original_completion.kind
-            && completion.deprecated == original_completion.deprecated
-            && completion.preselect == original_completion.preselect
-            && completion.sort_text == original_completion.sort_text
-    }) else {
-        return Ok(original_completion);
-    };
+
+    let mut resolved_completion =
+        if resolved_completions.get(resolve_data.completion_item_index).is_some() {
+            resolved_completions.swap_remove(resolve_data.completion_item_index)
+        } else {
+            return Ok(original_completion);
+        };
 
     if !resolve_data.imports.is_empty() {
         let additional_edits = snap
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
index 8039f0644ee..6ddfe118d5e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs
@@ -826,6 +826,7 @@ pub struct CompletionResolveData {
     pub imports: Vec<CompletionImport>,
     pub version: Option<i32>,
     pub trigger_character: Option<char>,
+    pub completion_item_index: usize,
 }
 
 #[derive(Debug, Serialize, Deserialize)]
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 d654dc3e7f4..d444f90a131 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
@@ -88,6 +88,7 @@ pub(crate) fn structure_node_kind(kind: StructureNodeKind) -> lsp_types::SymbolK
     match kind {
         StructureNodeKind::SymbolKind(symbol) => symbol_kind(symbol),
         StructureNodeKind::Region => lsp_types::SymbolKind::NAMESPACE,
+        StructureNodeKind::ExternBlock => lsp_types::SymbolKind::NAMESPACE,
     }
 }
 
@@ -391,18 +392,36 @@ fn completion_item(
         } else {
             Vec::new()
         };
-    if something_to_resolve || !imports.is_empty() {
-        let data = lsp_ext::CompletionResolveData {
+    let (ref_resolve_data, resolve_data) = if something_to_resolve || !imports.is_empty() {
+        let mut item_index = acc.len();
+        let ref_resolve_data = if ref_match.is_some() {
+            let ref_resolve_data = lsp_ext::CompletionResolveData {
+                position: tdpp.clone(),
+                imports: Vec::new(),
+                version,
+                trigger_character: completion_trigger_character,
+                completion_item_index: item_index,
+            };
+            item_index += 1;
+            Some(to_value(ref_resolve_data).unwrap())
+        } else {
+            None
+        };
+        let resolve_data = lsp_ext::CompletionResolveData {
             position: tdpp.clone(),
             imports,
             version,
             trigger_character: completion_trigger_character,
+            completion_item_index: item_index,
         };
-        lsp_item.data = Some(to_value(data).unwrap());
-    }
+        (ref_resolve_data, Some(to_value(resolve_data).unwrap()))
+    } else {
+        (None, None)
+    };
 
     if let Some((label, indel, relevance)) = ref_match {
-        let mut lsp_item_with_ref = lsp_types::CompletionItem { label, ..lsp_item.clone() };
+        let mut lsp_item_with_ref =
+            lsp_types::CompletionItem { label, data: ref_resolve_data, ..lsp_item.clone() };
         lsp_item_with_ref
             .additional_text_edits
             .get_or_insert_with(Default::default)
@@ -411,6 +430,7 @@ fn completion_item(
         acc.push(lsp_item_with_ref);
     };
 
+    lsp_item.data = resolve_data;
     acc.push(lsp_item);
 
     fn set_score(
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
index 67629fcf7cc..07767d5ae9f 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -370,15 +370,13 @@ pub mod mem {
     // endregion:drop
 
     // region:transmute
-    extern "rust-intrinsic" {
-        pub fn transmute<Src, Dst>(src: Src) -> Dst;
-    }
+    #[rustc_intrinsic]
+    pub fn transmute<Src, Dst>(src: Src) -> Dst;
     // endregion:transmute
 
     // region:size_of
-    extern "rust-intrinsic" {
-        pub fn size_of<T>() -> usize;
-    }
+    #[rustc_intrinsic]
+    pub fn size_of<T>() -> usize;
     // endregion:size_of
 
     // region:discriminant
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 12e6d829a08..cd0f49174cd 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -47,7 +47,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frust-analyzer
   Each triaged issue should have one of these labels.
 * [fun](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%3Afun)
   is for cool, but probably hard stuff.
-* [Design](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aopen+is%3Aissue+label%Design)
+* [C-Architecture](https://github.com/rust-lang/rust-analyzer/issues?q=is%3Aissue%20state%3Aopen%20label%3AC-Architecture)
   is for moderate/large scale architecture discussion.
   Also a kind of fun.
   These issues should generally include a link to a Zulip discussion thread.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index 7764f7843a0..b7c536e0279 100644
--- a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
+++ b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
@@ -1,5 +1,5 @@
 <!---
-lsp/ext.rs hash: 90cf7718d54fe3c2
+lsp/ext.rs hash: 96f88b7a5d0080c6
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
diff --git a/src/tools/rust-analyzer/editors/code/package-lock.json b/src/tools/rust-analyzer/editors/code/package-lock.json
index 10b633511d3..6027f813311 100644
--- a/src/tools/rust-analyzer/editors/code/package-lock.json
+++ b/src/tools/rust-analyzer/editors/code/package-lock.json
@@ -13,12 +13,12 @@
                 "anser": "^2.1.1",
                 "d3": "^7.8.5",
                 "d3-graphviz": "^5.0.2",
-                "vscode-languageclient": "^8.1.0"
+                "vscode-languageclient": "^9.0.1"
             },
             "devDependencies": {
                 "@tsconfig/strictest": "^2.0.1",
                 "@types/node": "~16.11.7",
-                "@types/vscode": "~1.78.1",
+                "@types/vscode": "~1.83",
                 "@typescript-eslint/eslint-plugin": "^6.0.0",
                 "@typescript-eslint/parser": "^6.0.0",
                 "@vscode/test-electron": "^2.3.8",
@@ -32,7 +32,7 @@
                 "typescript": "^5.6.0"
             },
             "engines": {
-                "vscode": "^1.78.0"
+                "vscode": "^1.83.0"
             }
         },
         "node_modules/@aashutoshrathi/word-wrap": {
@@ -880,9 +880,9 @@
             "dev": true
         },
         "node_modules/@types/vscode": {
-            "version": "1.78.1",
-            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.78.1.tgz",
-            "integrity": "sha512-wEA+54axejHu7DhcUfnFBan1IqFD1gBDxAFz8LoX06NbNDMRJv/T6OGthOs52yZccasKfN588EyffHWABkR0fg==",
+            "version": "1.83.3",
+            "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.83.3.tgz",
+            "integrity": "sha512-ZPp5+OQNYrCSFoT4jWOZKdcuXijj+JdN2BJNDhWH4pPbVL6PRQycG9NT8C4a94oul1tFMbkVbXXa9HasI7cLUg==",
             "dev": true
         },
         "node_modules/@typescript-eslint/eslint-plugin": {
@@ -5059,24 +5059,24 @@
             }
         },
         "node_modules/vscode-jsonrpc": {
-            "version": "8.1.0",
-            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.1.0.tgz",
-            "integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==",
+            "version": "8.2.0",
+            "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz",
+            "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==",
             "engines": {
                 "node": ">=14.0.0"
             }
         },
         "node_modules/vscode-languageclient": {
-            "version": "8.1.0",
-            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.1.0.tgz",
-            "integrity": "sha512-GL4QdbYUF/XxQlAsvYWZRV3V34kOkpRlvV60/72ghHfsYFnS/v2MANZ9P6sHmxFcZKOse8O+L9G7Czg0NUWing==",
+            "version": "9.0.1",
+            "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-9.0.1.tgz",
+            "integrity": "sha512-JZiimVdvimEuHh5olxhxkht09m3JzUGwggb5eRUkzzJhZ2KjCN0nh55VfiED9oez9DyF8/fz1g1iBV3h+0Z2EA==",
             "dependencies": {
                 "minimatch": "^5.1.0",
                 "semver": "^7.3.7",
-                "vscode-languageserver-protocol": "3.17.3"
+                "vscode-languageserver-protocol": "3.17.5"
             },
             "engines": {
-                "vscode": "^1.67.0"
+                "vscode": "^1.82.0"
             }
         },
         "node_modules/vscode-languageclient/node_modules/brace-expansion": {
@@ -5099,18 +5099,18 @@
             }
         },
         "node_modules/vscode-languageserver-protocol": {
-            "version": "3.17.3",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.3.tgz",
-            "integrity": "sha512-924/h0AqsMtA5yK22GgMtCYiMdCOtWTSGgUOkgEDX+wk2b0x4sAfLiO4NxBxqbiVtz7K7/1/RgVrVI0NClZwqA==",
+            "version": "3.17.5",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz",
+            "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==",
             "dependencies": {
-                "vscode-jsonrpc": "8.1.0",
-                "vscode-languageserver-types": "3.17.3"
+                "vscode-jsonrpc": "8.2.0",
+                "vscode-languageserver-types": "3.17.5"
             }
         },
         "node_modules/vscode-languageserver-types": {
-            "version": "3.17.3",
-            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.3.tgz",
-            "integrity": "sha512-SYU4z1dL0PyIMd4Vj8YOqFvHu7Hz/enbWtpfnVbJHU4Nd1YNYx8u0ennumc6h48GQNeOLxmwySmnADouT/AuZA=="
+            "version": "3.17.5",
+            "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz",
+            "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg=="
         },
         "node_modules/which": {
             "version": "2.0.2",
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index ccc8c0e3842..b868622b3a5 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -27,7 +27,7 @@
         }
     },
     "engines": {
-        "vscode": "^1.78.0"
+        "vscode": "^1.83.0"
     },
     "enabledApiProposals": [],
     "scripts": {
@@ -49,12 +49,12 @@
         "anser": "^2.1.1",
         "d3": "^7.8.5",
         "d3-graphviz": "^5.0.2",
-        "vscode-languageclient": "^8.1.0"
+        "vscode-languageclient": "^9.0.1"
     },
     "devDependencies": {
         "@tsconfig/strictest": "^2.0.1",
         "@types/node": "~16.11.7",
-        "@types/vscode": "~1.78.1",
+        "@types/vscode": "~1.83",
         "@typescript-eslint/eslint-plugin": "^6.0.0",
         "@typescript-eslint/parser": "^6.0.0",
         "@vscode/test-electron": "^2.3.8",
@@ -490,15 +490,19 @@
                         "type": "string",
                         "enum": [
                             "auto",
+                            "llvm-vs-code-extensions.lldb-dap",
                             "vadimcn.vscode-lldb",
-                            "ms-vscode.cpptools"
+                            "ms-vscode.cpptools",
+                            "webfreak.debug"
                         ],
                         "default": "auto",
                         "description": "Preferred debug engine.",
                         "markdownEnumDescriptions": [
-                            "First try to use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), if it's not installed try to use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools).",
+                            "Use the first available extension out of [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap), [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb), [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools), and [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug).",
+                            "Use [LLDB DAP](https://marketplace.visualstudio.com/items?itemName=llvm-vs-code-extensions.lldb-dap)",
                             "Use [CodeLLDB](https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb)",
-                            "Use [MS C++ tools](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)"
+                            "Use [C/C++ for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ms-vscode.cpptools)",
+                            "Use [Native Debug](https://marketplace.visualstudio.com/items?itemName=webfreak.debug)"
                         ]
                     },
                     "rust-analyzer.debug.sourceFileMap": {
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index bf58112916b..eac7b849fdb 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -350,6 +350,7 @@ class ExperimentalFeatures implements lc.StaticFeature {
         _documentSelector: lc.DocumentSelector | undefined,
     ): void {}
     dispose(): void {}
+    clear(): void {}
 }
 
 class OverrideFeatures implements lc.StaticFeature {
@@ -369,6 +370,7 @@ class OverrideFeatures implements lc.StaticFeature {
         _documentSelector: lc.DocumentSelector | undefined,
     ): void {}
     dispose(): void {}
+    clear(): void {}
 }
 
 function isCodeActionWithoutEditsAndCommands(value: any): boolean {
diff --git a/src/tools/rust-analyzer/triagebot.toml b/src/tools/rust-analyzer/triagebot.toml
index d62adb9144b..1138035d0e8 100644
--- a/src/tools/rust-analyzer/triagebot.toml
+++ b/src/tools/rust-analyzer/triagebot.toml
@@ -19,3 +19,5 @@ exclude_titles = [ # exclude syncs from subtree in rust-lang/rust
     "sync from rust",
 ]
 labels = ["has-merge-commits", "S-waiting-on-author"]
+
+[transfer]
diff --git a/src/tools/rustbook/.gitignore b/src/tools/rustbook/.gitignore
new file mode 100644
index 00000000000..ea8c4bf7f35
--- /dev/null
+++ b/src/tools/rustbook/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 27ccb205b50..9e549348da3 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -47,9 +47,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.15"
+version = "0.6.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526"
+checksum = "23a1e53f0f5d86382dafe1cf314783b2044280f406e7e1506368220ad11b1338"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -62,43 +62,43 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.8"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1"
+checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.5"
+version = "0.2.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb"
+checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.1.1"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a"
+checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c"
 dependencies = [
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.4"
+version = "3.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8"
+checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
 dependencies = [
  "anstyle",
- "windows-sys 0.52.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.89"
+version = "1.0.92"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86fdf8605db99b54d3cd748a44c6d04df638eb5dafb219b135d0149bd0db01f6"
+checksum = "74f37166d7d48a0284b99dd824694c26119c700b53bf0d1540cdb147dbdaaf13"
 
 [[package]]
 name = "autocfg"
@@ -161,9 +161,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "cc"
-version = "1.1.22"
+version = "1.1.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9540e661f81799159abee814118cc139a2004b3a3aa3ea37724a1b66530b90e0"
+checksum = "67b9470d453346108f93a59222a9a1a5724db32d0a4727b7ab7ace4b4d822dc9"
 dependencies = [
  "shlex",
 ]
@@ -185,14 +185,14 @@ dependencies = [
  "js-sys",
  "num-traits",
  "wasm-bindgen",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
 name = "clap"
-version = "4.5.18"
+version = "4.5.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0956a43b323ac1afaffc053ed5c4b7c1f1800bacd1683c353aabbb752515dd3"
+checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -200,9 +200,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.18"
+version = "4.5.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d72166dd41634086d5803a47eb71ae740e61d84709c36f3c34110173db3961b"
+checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
 dependencies = [
  "anstream",
  "anstyle",
@@ -213,9 +213,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.29"
+version = "4.5.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8937760c3f4c60871870b8c3ee5f9b30771f792a7045c48bcbba999d7d6b3b8e"
+checksum = "86bc73de94bc81e52f3bebec71bc4463e9748f7a59166663e32044669577b0e2"
 dependencies = [
  "clap",
 ]
@@ -240,9 +240,9 @@ checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
 
 [[package]]
 name = "colorchoice"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0"
+checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
 
 [[package]]
 name = "core-foundation-sys"
@@ -441,11 +441,12 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "5.1.2"
+version = "6.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d08485b96a0e6393e9e4d1b8d48cf74ad6c063cd905eb33f42c1ce3f0377539b"
+checksum = "fd4ccde012831f9a071a637b0d4e31df31c0f6c525784b35ae76a9ac6bc1e315"
 dependencies = [
  "log",
+ "num-order",
  "pest",
  "pest_derive",
  "serde",
@@ -455,9 +456,9 @@ dependencies = [
 
 [[package]]
 name = "hashbrown"
-version = "0.14.5"
+version = "0.15.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb"
 
 [[package]]
 name = "heck"
@@ -535,9 +536,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.5.0"
+version = "2.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5"
+checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -557,9 +558,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
 
 [[package]]
 name = "js-sys"
-version = "0.3.70"
+version = "0.3.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a"
+checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -572,9 +573,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
 
 [[package]]
 name = "libc"
-version = "0.2.159"
+version = "0.2.161"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
 
 [[package]]
 name = "libdbus-sys"
@@ -645,9 +646,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.40"
+version = "0.4.42"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b45a38e19bd200220ef07c892b0157ad3d2365e5b5a267ca01ad12182491eea5"
+checksum = "7624879735513024d323e7267a0b3a7176aceb0db537939beb4ee31d9e8945e3"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -763,6 +764,21 @@ dependencies = [
 ]
 
 [[package]]
+name = "num-modular"
+version = "0.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f"
+
+[[package]]
+name = "num-order"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6"
+dependencies = [
+ "num-modular",
+]
+
+[[package]]
 name = "num-traits"
 version = "0.2.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -773,9 +789,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "onig"
@@ -831,14 +847,14 @@ dependencies = [
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
 name = "pathdiff"
-version = "0.2.1"
+version = "0.2.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd"
+checksum = "d61c5ce1153ab5b689d0c074c4e7fc613e942dfb7dd9eea5ab202d2ad91fe361"
 
 [[package]]
 name = "percent-encoding"
@@ -848,9 +864,9 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.13"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdbef9d1d47087a895abd220ed25eb4ad973a5e26f6a4367b038c25e28dfc2d9"
+checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442"
 dependencies = [
  "memchr",
  "thiserror",
@@ -859,9 +875,9 @@ dependencies = [
 
 [[package]]
 name = "pest_derive"
-version = "2.7.13"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d3a6e3394ec80feb3b6393c725571754c6188490265c61aaf260810d6b95aa0"
+checksum = "d214365f632b123a47fd913301e14c946c61d1c183ee245fa76eb752e59a02dd"
 dependencies = [
  "pest",
  "pest_generator",
@@ -869,9 +885,9 @@ dependencies = [
 
 [[package]]
 name = "pest_generator"
-version = "2.7.13"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94429506bde1ca69d1b5601962c73f4172ab4726571a59ea95931218cb0e930e"
+checksum = "eb55586734301717aea2ac313f50b2eb8f60d2fc3dc01d190eefa2e625f60c4e"
 dependencies = [
  "pest",
  "pest_meta",
@@ -882,9 +898,9 @@ dependencies = [
 
 [[package]]
 name = "pest_meta"
-version = "2.7.13"
+version = "2.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac8a071862e93690b6e34e9a5fb8e33ff3734473ac0245b27232222c4906a33f"
+checksum = "b75da2a70cf4d9cb76833c990ac9cd3923c9a8905a8929789ce347c84564d03d"
 dependencies = [
  "once_cell",
  "pest",
@@ -980,9 +996,9 @@ checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.89"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
 dependencies = [
  "unicode-ident",
 ]
@@ -1083,18 +1099,18 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.5.6"
+version = "0.5.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "355ae415ccd3a04315d3f8246e86d67689ea74d88d915576e1589a351062a13b"
+checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
 dependencies = [
  "bitflags 2.6.0",
 ]
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1104,9 +1120,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -1115,9 +1131,9 @@ dependencies = [
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "rustbook"
@@ -1134,9 +1150,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.37"
+version = "0.38.38"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811"
+checksum = "aa260229e6538e52293eeb577aabd09945a09d6d9cc0fc550ed7529056c2e32a"
 dependencies = [
  "bitflags 2.6.0",
  "errno",
@@ -1174,18 +1190,18 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
 
 [[package]]
 name = "serde"
-version = "1.0.210"
+version = "1.0.214"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a"
+checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.210"
+version = "1.0.214"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f"
+checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1194,9 +1210,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.128"
+version = "1.0.132"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8"
+checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
 dependencies = [
  "itoa",
  "memchr",
@@ -1276,9 +1292,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
 
 [[package]]
 name = "syn"
-version = "2.0.79"
+version = "2.0.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590"
+checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1331,12 +1347,12 @@ dependencies = [
 
 [[package]]
 name = "terminal_size"
-version = "0.3.0"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7"
+checksum = "4f599bd7ca042cfdf8f4512b277c02ba102247820f9d9d4a9f521f496751a6ef"
 dependencies = [
  "rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.59.0",
 ]
 
 [[package]]
@@ -1347,18 +1363,18 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9"
 
 [[package]]
 name = "thiserror"
-version = "1.0.64"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d50af8abc119fb8bb6dbabcfa89656f46f84aa0ac7688088608076ad2b459a84"
+checksum = "5d171f59dbaa811dbbb1aee1e73db92ec2b122911a48e1390dfe327a821ddede"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.64"
+version = "1.0.66"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08904e7672f5eb876eaaf87e0ce17857500934f4981c4a0ab2b4aa98baac7fc3"
+checksum = "b08be0f17bd307950653ce45db00cd31200d82b624b36e181337d9c7d92765b5"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1437,24 +1453,21 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
 name = "ucd-trie"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
+checksum = "2896d95c02a80c6d6a5d6e953d479f5ddf2dfdb6a244441010e373ac0fb88971"
 
 [[package]]
 name = "unicase"
-version = "2.7.0"
+version = "2.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89"
-dependencies = [
- "version_check",
-]
+checksum = "7e51b68083f157f853b6379db119d1c1be0e6e4dec98101079dec41f6f5cf6df"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.15"
+version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
+checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893"
 
 [[package]]
 name = "unicode-ident"
@@ -1524,9 +1537,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5"
+checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -1535,9 +1548,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b"
+checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358"
 dependencies = [
  "bumpalo",
  "log",
@@ -1550,9 +1563,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf"
+checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -1560,9 +1573,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836"
+checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1573,9 +1586,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.93"
+version = "0.2.95"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484"
+checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d"
 
 [[package]]
 name = "winapi"
@@ -1614,16 +1627,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-sys"
-version = "0.48.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
-dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1632,7 +1636,7 @@ version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
 dependencies = [
- "windows-targets 0.52.6",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1641,22 +1645,7 @@ version = "0.59.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
 dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
-dependencies = [
- "windows_aarch64_gnullvm 0.48.5",
- "windows_aarch64_msvc 0.48.5",
- "windows_i686_gnu 0.48.5",
- "windows_i686_msvc 0.48.5",
- "windows_x86_64_gnu 0.48.5",
- "windows_x86_64_gnullvm 0.48.5",
- "windows_x86_64_msvc 0.48.5",
+ "windows-targets",
 ]
 
 [[package]]
@@ -1665,48 +1654,30 @@ version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
 dependencies = [
- "windows_aarch64_gnullvm 0.52.6",
- "windows_aarch64_msvc 0.52.6",
- "windows_i686_gnu 0.52.6",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
  "windows_i686_gnullvm",
- "windows_i686_msvc 0.52.6",
- "windows_x86_64_gnu 0.52.6",
- "windows_x86_64_gnullvm 0.52.6",
- "windows_x86_64_msvc 0.52.6",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
-
-[[package]]
-name = "windows_aarch64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
-
-[[package]]
-name = "windows_i686_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
@@ -1719,48 +1690,24 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
-
-[[package]]
-name = "windows_i686_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
-
-[[package]]
-name = "windows_x86_64_gnu"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
-
-[[package]]
-name = "windows_x86_64_msvc"
 version = "0.52.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml
index 4cb200ebc7c..f7384a98f85 100644
--- a/src/tools/rustdoc-gui-test/Cargo.toml
+++ b/src/tools/rustdoc-gui-test/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 compiletest = { path = "../compiletest" }
 getopts = "0.2"
 walkdir = "2"
diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js
index e162ba033cc..7aa5e102e6d 100644
--- a/src/tools/rustdoc-js/tester.js
+++ b/src/tools/rustdoc-js/tester.js
@@ -2,6 +2,14 @@
 const fs = require("fs");
 const path = require("path");
 
+
+function arrayToCode(array) {
+    return array.map((value, index) => {
+        value = value.split("&nbsp;").join(" ");
+        return (index % 2 === 1) ? ("`" + value + "`") : value;
+    }).join("");
+}
+
 function loadContent(content) {
     const Module = module.constructor;
     const m = new Module();
@@ -84,7 +92,6 @@ function checkNeededFields(fullPath, expected, error_text, queryName, position)
     if (fullPath.length === 0) {
         fieldsToCheck = [
             "foundElems",
-            "original",
             "returned",
             "userQuery",
             "error",
@@ -181,15 +188,7 @@ function valueCheck(fullPath, expected, result, error_text, queryName) {
                 if (!result_v.forEach) {
                     throw result_v;
                 }
-                result_v.forEach((value, index) => {
-                    value = value.split("&nbsp;").join(" ");
-                    if (index % 2 === 1) {
-                        result_v[index] = "`" + value + "`";
-                    } else {
-                        result_v[index] = value;
-                    }
-                });
-                result_v = result_v.join("");
+                result_v = arrayToCode(result_v);
             }
             const obj_path = fullPath + (fullPath.length > 0 ? "." : "") + key;
             valueCheck(obj_path, expected[key], result_v, error_text, queryName);
@@ -437,9 +436,41 @@ function loadSearchJS(doc_folder, resource_suffix) {
     searchModule.initSearch(searchIndex.searchIndex);
     const docSearch = searchModule.docSearch;
     return {
-        doSearch: function(queryStr, filterCrate, currentCrate) {
-            return docSearch.execQuery(searchModule.parseQuery(queryStr),
+        doSearch: async function(queryStr, filterCrate, currentCrate) {
+            const result = await docSearch.execQuery(searchModule.parseQuery(queryStr),
                 filterCrate, currentCrate);
+            for (const tab in result) {
+                if (!Object.prototype.hasOwnProperty.call(result, tab)) {
+                    continue;
+                }
+                if (!(result[tab] instanceof Array)) {
+                    continue;
+                }
+                for (const entry of result[tab]) {
+                    for (const key in entry) {
+                        if (!Object.prototype.hasOwnProperty.call(entry, key)) {
+                            continue;
+                        }
+                        if (key === "displayTypeSignature") {
+                            const {type, mappedNames, whereClause} =
+                                await entry.displayTypeSignature;
+                            entry.displayType = arrayToCode(type);
+                            entry.displayMappedNames = [...mappedNames.entries()]
+                                .map(([name, qname]) => {
+                                    return `${name} = ${qname}`;
+                                }).join(", ");
+                            entry.displayWhereClause = [...whereClause.entries()]
+                                .flatMap(([name, value]) => {
+                                    if (value.length === 0) {
+                                        return [];
+                                    }
+                                    return [`${name}: ${arrayToCode(value)}`];
+                                }).join(", ");
+                        }
+                    }
+                }
+            }
+            return result;
         },
         getCorrections: function(queryStr, filterCrate, currentCrate) {
             const parsedQuery = searchModule.parseQuery(queryStr);
diff --git a/src/tools/suggest-tests/Cargo.toml b/src/tools/suggest-tests/Cargo.toml
index 7c048d53a50..d6f86078d7e 100644
--- a/src/tools/suggest-tests/Cargo.toml
+++ b/src/tools/suggest-tests/Cargo.toml
@@ -5,4 +5,4 @@ edition = "2021"
 
 [dependencies]
 glob = "0.3.0"
-build_helper = { version = "0.1.0", path = "../build_helper" }
+build_helper = { version = "0.1.0", path = "../../build_helper" }
diff --git a/src/tools/tidy/Cargo.toml b/src/tools/tidy/Cargo.toml
index 42e608ff5ce..bc75787fb1a 100644
--- a/src/tools/tidy/Cargo.toml
+++ b/src/tools/tidy/Cargo.toml
@@ -5,7 +5,7 @@ edition = "2021"
 autobins = false
 
 [dependencies]
-build_helper = { path = "../build_helper" }
+build_helper = { path = "../../build_helper" }
 cargo_metadata = "0.18"
 regex = "1"
 miropt-test-tools = { path = "../miropt-test-tools" }
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 8e12db409ec..e065f01ebba 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -24,6 +24,7 @@ const LICENSES: &[&str] = &[
     "BSD-2-Clause OR Apache-2.0 OR MIT",                   // zerocopy
     "ISC",
     "MIT / Apache-2.0",
+    "MIT AND (MIT OR Apache-2.0)",
     "MIT AND Apache-2.0 WITH LLVM-exception AND (MIT OR Apache-2.0)", // compiler-builtins
     "MIT OR Apache-2.0 OR LGPL-2.1-or-later",              // r-efi, r-efi-alloc
     "MIT OR Apache-2.0 OR Zlib",                           // tinyvec_macros
@@ -92,6 +93,7 @@ const EXCEPTIONS: ExceptionList = &[
     ("constant_time_eq", "CC0-1.0 OR MIT-0 OR Apache-2.0"),  // rustc
     ("dissimilar", "Apache-2.0"),                            // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps)
     ("fluent-langneg", "Apache-2.0"),                        // rustc (fluent translations)
+    ("foldhash", "Zlib"),                                    // rustc
     ("instant", "BSD-3-Clause"),                             // rustc_driver/tracing-subscriber/parking_lot
     ("mdbook", "MPL-2.0"),                                   // mdbook
     ("option-ext", "MPL-2.0"),                               // cargo-miri (via `directories`)
@@ -283,6 +285,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
     "fluent-langneg",
     "fluent-syntax",
     "fnv",
+    "foldhash",
     "generic-array",
     "getopts",
     "getrandom",
diff --git a/src/tools/tidy/src/known_bug.rs b/src/tools/tidy/src/known_bug.rs
index 182a81c6ec9..a8771654144 100644
--- a/src/tools/tidy/src/known_bug.rs
+++ b/src/tools/tidy/src/known_bug.rs
@@ -6,8 +6,22 @@ use crate::walk::*;
 
 pub fn check(filepath: &Path, bad: &mut bool) {
     walk(filepath, |path, _is_dir| filter_not_rust(path), &mut |entry, contents| {
-        let file = entry.path();
-        if !contents.lines().any(|line| line.starts_with("//@ known-bug: ")) {
+        let file: &Path = entry.path();
+
+        // files in "auxiliary" do not need to crash by themselves
+        let test_path_segments =
+            file.iter().map(|s| s.to_string_lossy().into()).collect::<Vec<String>>();
+        let test_path_segments_str =
+            test_path_segments.iter().map(|s| s.as_str()).collect::<Vec<&str>>();
+
+        if !matches!(test_path_segments_str[..], [
+            ..,
+            "tests",
+            "crashes",
+            "auxiliary",
+            _aux_file_rs
+        ]) && !contents.lines().any(|line| line.starts_with("//@ known-bug: "))
+        {
             tidy_error!(
                 bad,
                 "{} crash/ice test does not have a \"//@ known-bug: \" directive",
diff --git a/src/tools/unicode-table-generator/src/range_search.rs b/src/tools/unicode-table-generator/src/range_search.rs
index 9a51979a2f0..14da876eda7 100644
--- a/src/tools/unicode-table-generator/src/range_search.rs
+++ b/src/tools/unicode-table-generator/src/range_search.rs
@@ -1,4 +1,5 @@
 #[inline(always)]
+#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))]
 const fn bitset_search<
     const N: usize,
     const CHUNK_SIZE: usize,
diff --git a/src/tools/unicode-table-generator/src/raw_emitter.rs b/src/tools/unicode-table-generator/src/raw_emitter.rs
index 46010692fe5..dd064c59283 100644
--- a/src/tools/unicode-table-generator/src/raw_emitter.rs
+++ b/src/tools/unicode-table-generator/src/raw_emitter.rs
@@ -97,6 +97,10 @@ impl RawEmitter {
 
         self.blank_line();
 
+        writeln!(
+            &mut self.file,
+            r#"#[cfg_attr(bootstrap, rustc_const_stable(feature = "const_unicode_case_lookup", since = "1.84.0"))]"#
+        ).unwrap();
         writeln!(&mut self.file, "pub const fn lookup(c: char) -> bool {{").unwrap();
         if first_code_point > 0x7f {
             writeln!(&mut self.file, "    (c as u32) >= {first_code_point:#04x} &&").unwrap();