about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml10
-rw-r--r--Cargo.lock97
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs4
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs7
-rw-r--r--compiler/rustc_borrowck/src/lib.rs3
-rw-r--r--compiler/rustc_borrowck/src/path_utils.rs1
-rw-r--r--compiler/rustc_borrowck/src/polonius/loan_invalidations.rs1
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs6
-rw-r--r--compiler/rustc_const_eval/messages.ftl8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs13
-rw-r--r--compiler/rustc_const_eval/src/errors.rs142
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/projection.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs28
-rw-r--r--compiler/rustc_const_eval/src/interpret/visitor.rs10
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs14
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/resolver.rs8
-rw-r--r--compiler/rustc_errors/src/diagnostic.rs11
-rw-r--r--compiler/rustc_errors/src/lib.rs700
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs2
-rw-r--r--compiler/rustc_hir/src/hir.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs25
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs42
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs9
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/unsafety.rs149
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs7
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs6
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs15
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs32
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs49
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs18
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs5
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs37
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs4
-rw-r--r--compiler/rustc_interface/src/queries.rs6
-rw-r--r--compiler/rustc_lint/src/builtin.rs3
-rw-r--r--compiler/rustc_lint/src/context.rs4
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs3
-rw-r--r--compiler/rustc_lint/src/internal.rs11
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs2
-rw-r--r--compiler/rustc_lint/src/types.rs11
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs1
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs7
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs1
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs76
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs15
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs8
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs19
-rw-r--r--compiler/rustc_middle/src/ty/region.rs8
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs10
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs2
-rw-r--r--compiler/rustc_middle/src/util/bug.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs2
-rw-r--r--compiler/rustc_mir_transform/src/coroutine.rs4
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs12
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs15
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs5
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_passes/src/check_attr.rs9
-rw-r--r--compiler/rustc_span/src/lib.rs7
-rw-r--r--compiler/rustc_span/src/symbol.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs14
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs8
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs4
-rw-r--r--library/alloc/src/boxed/thin.rs64
-rw-r--r--library/alloc/src/collections/btree/map.rs213
-rw-r--r--library/alloc/src/fmt.rs5
-rw-r--r--library/core/src/cell.rs10
-rw-r--r--library/core/src/ffi/c_str.rs1
-rw-r--r--library/core/src/intrinsics.rs58
-rw-r--r--library/core/src/intrinsics/simd.rs54
-rw-r--r--library/core/src/num/f32.rs2
-rw-r--r--library/core/src/num/f64.rs2
-rw-r--r--library/core/src/option.rs1
-rw-r--r--library/core/src/primitive_docs.rs5
-rw-r--r--library/core/src/ptr/metadata.rs5
-rw-r--r--library/core/src/ptr/mod.rs6
-rw-r--r--library/core/src/sync/atomic.rs4
-rw-r--r--library/core/src/task/wake.rs6
-rw-r--r--library/core/src/time.rs125
-rw-r--r--library/core/src/tuple.rs14
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--library/core/tests/time.rs43
-rw-r--r--library/proc_macro/src/bridge/arena.rs1
-rw-r--r--library/proc_macro/src/lib.rs3
-rw-r--r--library/std/src/lib.rs2
-rw-r--r--library/std/src/os/fd/owned.rs6
-rw-r--r--library/std/src/os/unix/net/datagram.rs1
-rw-r--r--library/std/src/os/unix/net/listener.rs1
-rw-r--r--library/std/src/os/unix/net/stream.rs1
-rw-r--r--library/std/src/os/unix/process.rs5
-rw-r--r--library/std/src/os/windows/io/handle.rs5
-rw-r--r--library/std/src/os/windows/io/socket.rs3
-rw-r--r--library/std/src/os/windows/process.rs3
-rw-r--r--library/std/src/sys/cmath.rs88
-rw-r--r--library/std/src/sys/cmath/builtins.rs35
-rw-r--r--library/std/src/sys/cmath/mod.rs11
-rw-r--r--library/std/src/sys/cmath/windows.rs94
-rw-r--r--library/std/src/sys/pal/unix/locks/mod.rs4
-rw-r--r--library/std/src/sys/pal/unix/locks/pthread_rwlock.rs195
-rw-r--r--library/std/src/sys/pal/unix/locks/queue_rwlock.rs557
-rw-r--r--library/std/src/thread/mod.rs11
-rw-r--r--src/bootstrap/src/core/build_steps/check.rs19
-rw-r--r--src/bootstrap/src/core/build_steps/compile.rs38
-rw-r--r--src/bootstrap/src/core/build_steps/doc.rs10
-rw-r--r--src/bootstrap/src/core/build_steps/run.rs2
-rw-r--r--src/bootstrap/src/core/build_steps/test.rs34
-rw-r--r--src/bootstrap/src/core/build_steps/tool.rs4
-rw-r--r--src/bootstrap/src/core/builder.rs314
-rw-r--r--src/bootstrap/src/core/config/config.rs7
-rw-r--r--src/ci/github-actions/ci.yml9
-rwxr-xr-xsrc/ci/scripts/select-xcode.sh4
-rw-r--r--src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md26
-rw-r--r--src/doc/unstable-book/src/library-features/duration-constructors.md9
-rw-r--r--src/librustdoc/clean/inline.rs56
-rw-r--r--src/librustdoc/clean/mod.rs8
-rw-r--r--src/librustdoc/clean/utils.rs8
-rw-r--r--src/librustdoc/passes/collect_trait_impls.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_constants.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/dbg_macro.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/modulo_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/transmute/transmutes_expressible_as_ptr_casts.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs10
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs2
-rw-r--r--src/tools/clippy/tests/integration.rs2
-rw-r--r--src/tools/linkchecker/Cargo.toml1
-rw-r--r--src/tools/linkchecker/main.rs425
-rw-r--r--src/tools/linkchecker/tests/broken_intra_doc_link/foo.html5
-rw-r--r--src/tools/linkchecker/tests/checks.rs8
-rw-r--r--src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs31
-rw-r--r--src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr20
-rw-r--r--src/tools/rust-analyzer/.github/workflows/ci.yaml6
-rw-r--r--src/tools/rust-analyzer/Cargo.lock214
-rw-r--r--src/tools/rust-analyzer/Cargo.toml29
-rw-r--r--src/tools/rust-analyzer/clippy.toml5
-rw-r--r--src/tools/rust-analyzer/crates/base-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs2
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs32
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs175
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs48
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/generics.rs191
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/import_map.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs78
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs686
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs41
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/src.rs195
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/trace.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/visibility.rs120
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs28
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/db.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs71
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/quote.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/builder.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/db.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs717
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs83
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs113
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lower.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs9
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs12
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs14
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests.rs15
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs31
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/attrs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/diagnostics.rs39
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/display.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs89
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs175
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs298
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs188
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs126
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs198
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs62
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs131
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs30
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs217
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs148
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs55
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/defs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs13
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/tests/sourcegen_lints.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/traits.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs75
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs26
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs375
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs390
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs11
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs44
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/file_structure.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs87
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/interpret_function.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/join_lines.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/navigation_target.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/prime_caches.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/runnables.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/ssr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/status.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/typing.rs15
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_hir.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/view_mir.rs2
-rw-r--r--src/tools/rust-analyzer/crates/limit/src/lib.rs13
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/benchmark.rs72
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander.rs2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs8
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs14
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs16
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar.rs15
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs12
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs25
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs47
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs13
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/lexed_str.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs5
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast28
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast25
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rast56
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rs4
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rast44
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rast33
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rs1
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rast45
-rw-r--r--src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs113
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs13
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs6
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs10
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs8
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/profile/src/stop_watch.rs3
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs8
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs12
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs30
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs15
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs28
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs4
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs24
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs61
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs20
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs28
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs27
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs73
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs16
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs89
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs46
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs73
-rw-r--r--src/tools/rust-analyzer/crates/salsa/Cargo.toml35
-rw-r--r--src/tools/rust-analyzer/crates/salsa/FAQ.md34
-rw-r--r--src/tools/rust-analyzer/crates/salsa/LICENSE-APACHE201
-rw-r--r--src/tools/rust-analyzer/crates/salsa/LICENSE-MIT23
-rw-r--r--src/tools/rust-analyzer/crates/salsa/README.md42
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/Cargo.toml23
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-APACHE1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-MIT1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/README.md1
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs250
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/lib.rs146
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/parenthesized.rs13
-rw-r--r--src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs737
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/debug.rs66
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/derived.rs233
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs833
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/doctest.rs115
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/durability.rs50
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/hash.rs4
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/input.rs384
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/intern_id.rs131
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/interned.rs508
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lib.rs742
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/lru.rs325
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/plumbing.rs238
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/revision.rs67
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime.rs667
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs251
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs214
-rw-r--r--src/tools/rust-analyzer/crates/salsa/src/storage.rs54
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/cycles.rs493
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/dyn_trait.rs28
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs145
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/counter.rs14
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs59
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/log.rs16
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/main.rs9
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_dep_inputs.rs60
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_inputs.rs76
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs77
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/interned.rs90
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/lru.rs102
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/macros.rs11
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/no_send_sync.rs31
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs147
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/panic_safely.rs93
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/cancellation.rs132
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/frozen.rs57
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/independent.rs29
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/main.rs13
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs110
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs110
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs69
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs95
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs37
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/setup.rs197
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/signal.rs40
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/stress.rs168
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/parallel/true_parallel.rs125
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/implementation.rs19
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/main.rs5
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/queries.rs22
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs49
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/transparent.rs39
-rw-r--r--src/tools/rust-analyzer/crates/salsa/tests/variadic.rs51
-rw-r--r--src/tools/rust-analyzer/crates/sourcegen/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/span/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/span/src/lib.rs23
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/anymap.rs5
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/panic_context.rs3
-rw-r--r--src/tools/rust-analyzer/crates/stdx/src/rand.rs5
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs42
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs60
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/fuzz.rs3
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/parsing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ptr.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs12
-rw-r--r--src/tools/rust-analyzer/crates/test-fixture/src/lib.rs10
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/bench_fixture.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/fixture.rs34
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/lib.rs7
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs2
-rw-r--r--src/tools/rust-analyzer/crates/text-edit/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/buffer.rs2
-rw-r--r--src/tools/rust-analyzer/crates/tt/src/lib.rs52
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/loader.rs2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs14
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md21
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc11
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json10
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts17
-rw-r--r--src/tools/rust-analyzer/editors/code/src/lsp_ext.ts6
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts2
-rw-r--r--src/tools/rust-analyzer/lib/la-arena/src/lib.rs12
-rw-r--r--src/tools/rust-analyzer/lib/la-arena/src/map.rs6
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs3
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/lib.rs11
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs2
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/src/dist.rs8
-rw-r--r--src/tools/rust-analyzer/xtask/src/flags.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/src/install.rs2
-rw-r--r--src/tools/rust-analyzer/xtask/src/main.rs1
-rw-r--r--src/tools/rust-analyzer/xtask/src/metrics.rs6
-rw-r--r--src/tools/rust-analyzer/xtask/src/release/changelog.rs2
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/suggest-tests/src/dynamic_suggestions.rs41
-rw-r--r--tests/codegen/comparison-operators-2-tuple.rs14
-rw-r--r--tests/incremental/delayed_span_bug.rs4
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir2
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir2
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir2
-rw-r--r--tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir2
-rw-r--r--tests/rustdoc-ui/normalize-in-inlined-type-alias.rs14
-rw-r--r--tests/ui/async-await/async-closures/auxiliary/foreign.rs7
-rw-r--r--tests/ui/async-await/async-closures/foreign.rs19
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.rs2
-rw-r--r--tests/ui/async-await/async-closures/is-not-fn.stderr2
-rw-r--r--tests/ui/async-await/async-closures/move-consuming-capture.stderr2
-rw-r--r--tests/ui/coercion/type-errors.rs15
-rw-r--r--tests/ui/coercion/type-errors.stderr9
-rw-r--r--tests/ui/coherence/coherence-impls-copy.stderr24
-rw-r--r--tests/ui/consts/cycle-static-promoted.rs12
-rw-r--r--tests/ui/consts/issue-17718-const-bad-values.rs1
-rw-r--r--tests/ui/consts/issue-17718-const-bad-values.stderr15
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr5
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr5
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr35
-rw-r--r--tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr35
-rw-r--r--tests/ui/consts/miri_unleashed/extern-static.rs24
-rw-r--r--tests/ui/consts/miri_unleashed/extern-static.stderr15
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr15
-rw-r--r--tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr15
-rw-r--r--tests/ui/consts/miri_unleashed/tls.rs2
-rw-r--r--tests/ui/consts/miri_unleashed/tls.stderr4
-rw-r--r--tests/ui/error-codes/E0401.rs2
-rw-r--r--tests/ui/error-codes/E0401.stderr45
-rw-r--r--tests/ui/feature-gates/feature-gate-const-refs-to-static.rs1
-rw-r--r--tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr15
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs19
-rw-r--r--tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr17
-rw-r--r--tests/ui/lint/large_assignments/box_rc_arc_allowed.rs29
-rw-r--r--tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs38
-rw-r--r--tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr (renamed from tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr)16
-rw-r--r--tests/ui/lint/large_assignments/large_future.rs2
-rw-r--r--tests/ui/lint/large_assignments/move_into_box_rc_arc.rs38
-rw-r--r--tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr15
-rw-r--r--tests/ui/lint/large_assignments/move_into_fn.rs22
-rw-r--r--tests/ui/lint/large_assignments/move_into_fn.stderr15
-rw-r--r--tests/ui/mir/inline-wrong-abi.rs32
-rw-r--r--tests/ui/mir/inline-wrong-abi.stderr12
-rw-r--r--tests/ui/proc-macro/auxiliary/issue-118809.rs20
-rw-r--r--tests/ui/proc-macro/issue-118809.rs10
-rw-r--r--tests/ui/proc-macro/issue-118809.stderr21
-rw-r--r--tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr8
-rw-r--r--tests/ui/thread-local/thread-local-static.rs1
-rw-r--r--tests/ui/thread-local/thread-local-static.stderr14
-rw-r--r--tests/ui/trait-impl-bound-suggestions.fixed9
-rw-r--r--tests/ui/trait-impl-bound-suggestions.rs9
-rw-r--r--tests/ui/trait-impl-bound-suggestions.stderr18
-rw-r--r--tests/ui/treat-err-as-bug/span_delayed_bug.rs4
-rw-r--r--tests/ui/treat-err-as-bug/span_delayed_bug.stderr4
-rw-r--r--tests/ui/typeck/issue-104510-ice.rs2
-rw-r--r--tests/ui/typeck/issue-104510-ice.stderr16
-rw-r--r--tests/ui/typeck/issue-116864.rs31
-rw-r--r--triagebot.toml3
635 files changed, 18065 insertions, 5279 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 26e589c092e..f95551d679b 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -322,7 +322,7 @@ jobs:
               RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -335,7 +335,7 @@ jobs:
               RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -347,6 +347,7 @@ jobs:
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
               MACOSX_STD_DEPLOYMENT_TARGET: 10.12
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -358,6 +359,7 @@ jobs:
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
               MACOSX_STD_DEPLOYMENT_TARGET: 10.12
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -367,7 +369,7 @@ jobs:
               SCRIPT: "./x.py dist bootstrap --include-default-paths --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
               RUST_CONFIGURE_ARGS: "--enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false --set rust.lto=thin"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
@@ -381,7 +383,7 @@ jobs:
               SCRIPT: "./x.py --stage 2 test --host=aarch64-apple-darwin --target=aarch64-apple-darwin"
               RUST_CONFIGURE_ARGS: "--enable-sanitizers --enable-profiler --set rust.jemalloc"
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
diff --git a/Cargo.lock b/Cargo.lock
index fff30b0f27b..d552bb655b4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -147,7 +147,21 @@ dependencies = [
  "anstyle",
  "anstyle-parse",
  "anstyle-query",
- "anstyle-wincon",
+ "anstyle-wincon 2.1.0",
+ "colorchoice",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstream"
+version = "0.6.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-query",
+ "anstyle-wincon 3.0.2",
  "colorchoice",
  "utf8parse",
 ]
@@ -187,6 +201,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "anstyle-wincon"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
 name = "anyhow"
 version = "1.0.75"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -520,7 +544,7 @@ version = "4.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5179bb514e4d7c2051749d8fcefa2ed6d06a9f4e6d69faf3805f5d80b8cf8d56"
 dependencies = [
- "anstream",
+ "anstream 0.5.0",
  "anstyle",
  "clap_lex",
  "strsim",
@@ -558,7 +582,7 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
 name = "clippy"
 version = "0.1.78"
 dependencies = [
- "anstream",
+ "anstream 0.5.0",
  "clippy_config",
  "clippy_lints",
  "clippy_utils",
@@ -1235,6 +1259,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "env_filter"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a009aa4810eb158359dda09d0c87378e4bbb89b5a801f016885a4707ba24f7ea"
+dependencies = [
+ "log",
+ "regex",
+]
+
+[[package]]
 name = "env_logger"
 version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1248,6 +1282,19 @@ dependencies = [
 ]
 
 [[package]]
+name = "env_logger"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "05e7cf40684ae96ade6232ed84582f40ce0a66efcd43a5117aef610534f8e0b8"
+dependencies = [
+ "anstream 0.6.11",
+ "anstyle",
+ "env_filter",
+ "humantime",
+ "log",
+]
+
+[[package]]
 name = "equivalent"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1638,9 +1685,9 @@ dependencies = [
 
 [[package]]
 name = "handlebars"
-version = "4.3.7"
+version = "5.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83c3372087601b532857d332f5957cbae686da52bb7810bf038c3e3c3cc2fa0d"
+checksum = "ab283476b99e66691dee3f1640fea91487a8d81f50fb5ecc75538f8f8879a1e4"
 dependencies = [
  "log",
  "pest",
@@ -2227,6 +2274,7 @@ dependencies = [
 name = "linkchecker"
 version = "0.1.0"
 dependencies = [
+ "html5ever",
  "once_cell",
  "regex",
 ]
@@ -2335,9 +2383,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.36"
+version = "0.4.37"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80992cb0e05f22cc052c99f8e883f1593b891014b96a8b4637fd274d7030c85e"
+checksum = "0c33564061c3c640bed5ace7d6a2a1b65f2c64257d1ac930c15e94ed0fb561d3"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -2345,14 +2393,13 @@ dependencies = [
  "clap",
  "clap_complete",
  "elasticlunr-rs",
- "env_logger",
+ "env_logger 0.11.1",
  "handlebars",
  "log",
  "memchr",
  "once_cell",
  "opener",
- "pathdiff",
- "pulldown-cmark",
+ "pulldown-cmark 0.10.0",
  "regex",
  "serde",
  "serde_json",
@@ -2471,7 +2518,7 @@ dependencies = [
  "aes",
  "colored",
  "ctrlc",
- "env_logger",
+ "env_logger 0.10.0",
  "getrandom",
  "jemalloc-sys",
  "lazy_static",
@@ -2689,7 +2736,7 @@ dependencies = [
  "camino",
  "clap",
  "derive_builder",
- "env_logger",
+ "env_logger 0.10.0",
  "fs_extra",
  "glob",
  "humansize",
@@ -3013,6 +3060,24 @@ dependencies = [
 ]
 
 [[package]]
+name = "pulldown-cmark"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dce76ce678ffc8e5675b22aa1405de0b7037e2fdf8913fea40d1926c6fe1e6e7"
+dependencies = [
+ "bitflags 2.4.1",
+ "memchr",
+ "pulldown-cmark-escape",
+ "unicase",
+]
+
+[[package]]
+name = "pulldown-cmark-escape"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5d8f9aa0e3cbcfaf8bf00300004ee3b72f74770f9cbac93f6928771f613276b"
+
+[[package]]
 name = "punycode"
 version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3271,7 +3336,7 @@ name = "rustbook"
 version = "0.1.0"
 dependencies = [
  "clap",
- "env_logger",
+ "env_logger 0.10.0",
  "mdbook",
 ]
 
@@ -4427,7 +4492,7 @@ name = "rustc_resolve"
 version = "0.0.0"
 dependencies = [
  "bitflags 2.4.1",
- "pulldown-cmark",
+ "pulldown-cmark 0.9.6",
  "rustc_arena",
  "rustc_ast",
  "rustc_ast_pretty",
@@ -4971,9 +5036,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f"
 
 [[package]]
 name = "shlex"
-version = "1.1.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "siphasher"
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index f87269960bc..2676e3009db 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -403,8 +403,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                     }
                 }
                 let typeck = self.infcx.tcx.typeck(self.mir_def_id());
-                let hir_id = hir.parent_id(expr.hir_id);
-                let parent = self.infcx.tcx.hir_node(hir_id);
+                let parent = self.infcx.tcx.parent_hir_node(expr.hir_id);
                 let (def_id, args, offset) = if let hir::Node::Expr(parent_expr) = parent
                     && let hir::ExprKind::MethodCall(_, _, args, _) = parent_expr.kind
                     && let Some(def_id) = typeck.type_dependent_def_id(parent_expr.hir_id)
@@ -1660,8 +1659,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
 
         // Check that the parent of the closure is a method call,
         // with receiver matching with local's type (modulo refs)
-        let parent = hir.parent_id(closure_expr.hir_id);
-        if let hir::Node::Expr(parent) = tcx.hir_node(parent) {
+        if let hir::Node::Expr(parent) = tcx.parent_hir_node(closure_expr.hir_id) {
             if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
                 let recv_ty = typeck_results.expr_ty(recv);
 
@@ -3020,7 +3018,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
     /// assignment to `x.f`).
     pub(crate) fn report_illegal_reassignment(
         &mut self,
-        _location: Location,
         (place, span): (Place<'tcx>, Span),
         assigned_span: Span,
         err_place: Place<'tcx>,
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 9e7fd45ec19..5aed18ca456 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -944,7 +944,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         let hir = self.infcx.tcx.hir();
         let closure_id = self.mir_hir_id();
         let closure_span = self.infcx.tcx.def_span(self.mir_def_id());
-        let fn_call_id = hir.parent_id(closure_id);
+        let fn_call_id = self.infcx.tcx.parent_hir_id(closure_id);
         let node = self.infcx.tcx.hir_node(fn_call_id);
         let def_id = hir.enclosing_body_owner(fn_call_id);
         let mut look_at_return = true;
@@ -1034,7 +1034,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
         if let InstanceDef::Item(def_id) = source.instance
             && let Some(Node::Expr(hir::Expr { hir_id, kind, .. })) = hir.get_if_local(def_id)
             && let ExprKind::Closure(hir::Closure { kind: hir::ClosureKind::Closure, .. }) = kind
-            && let Some(Node::Expr(expr)) = hir.find_parent(*hir_id)
+            && let Node::Expr(expr) = self.infcx.tcx.parent_hir_node(*hir_id)
         {
             let mut cur_expr = expr;
             while let ExprKind::MethodCall(path_segment, recv, _, _) = cur_expr.kind {
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index e69d2ca966b..7529ec53a98 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -214,8 +214,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
                 if let Some(id) = placeholder.bound.kind.get_id()
                     && let Some(placeholder_id) = id.as_local()
                     && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id)
-                    && let Some(generics_impl) =
-                        hir.get_parent(hir.parent_id(gat_hir_id)).generics()
+                    && let Some(generics_impl) = self
+                        .infcx
+                        .tcx
+                        .parent_hir_node(self.infcx.tcx.parent_hir_id(gat_hir_id))
+                        .generics()
                 {
                     Some((gat_hir_id, generics_impl))
                 } else {
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index 4dba34c11f9..e8ffab9307e 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -1036,7 +1036,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
             self,
             self.infcx.tcx,
             self.body,
-            location,
             (sd, place_span.0),
             &borrow_set,
             |borrow_index| borrows_in_scope.contains(borrow_index),
@@ -2174,7 +2173,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
                 // report the error as an illegal reassignment
                 let init = &self.move_data.inits[init_index];
                 let assigned_span = init.span(self.body);
-                self.report_illegal_reassignment(location, (place, span), assigned_span, place);
+                self.report_illegal_reassignment((place, span), assigned_span, place);
             } else {
                 self.report_mutability_error(place, span, the_place_err, error_access, location)
             }
diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs
index adafad7fa2f..88b20bba9fb 100644
--- a/compiler/rustc_borrowck/src/path_utils.rs
+++ b/compiler/rustc_borrowck/src/path_utils.rs
@@ -27,7 +27,6 @@ pub(super) fn each_borrow_involving_path<'tcx, F, I, S>(
     s: &mut S,
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
-    _location: Location,
     access_place: (AccessDepth, Place<'tcx>),
     borrow_set: &BorrowSet<'tcx>,
     is_candidate: I,
diff --git a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
index 93aae1a7f97..10941cadcbb 100644
--- a/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
+++ b/compiler/rustc_borrowck/src/polonius/loan_invalidations.rs
@@ -340,7 +340,6 @@ impl<'cx, 'tcx> LoanInvalidationsGenerator<'cx, 'tcx> {
             self,
             self.tcx,
             self.body,
-            location,
             (sd, place),
             self.borrow_set,
             |_| true,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 3153b709ffe..34d60fc8f6e 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -662,7 +662,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
         polonius_output: Option<Rc<PoloniusOutput>>,
     ) -> (Option<ClosureRegionRequirements<'tcx>>, RegionErrors<'tcx>) {
         let mir_def_id = body.source.def_id();
-        self.propagate_constraints(body);
+        self.propagate_constraints();
 
         let mut errors_buffer = RegionErrors::new(infcx.tcx);
 
@@ -716,8 +716,8 @@ impl<'tcx> RegionInferenceContext<'tcx> {
     /// for each region variable until all the constraints are
     /// satisfied. Note that some values may grow **too** large to be
     /// feasible, but we check this later.
-    #[instrument(skip(self, _body), level = "debug")]
-    fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
+    #[instrument(skip(self), level = "debug")]
+    fn propagate_constraints(&mut self) {
         debug!("constraints={:#?}", {
             let mut constraints: Vec<_> = self.outlives_constraints().collect();
             constraints.sort_by_key(|c| (c.sup, c.sub));
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index 546001a25b2..85ebbb00c5f 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -98,6 +98,8 @@ const_eval_error = {$error_kind ->
 const_eval_exact_div_has_remainder =
     exact_div: {$a} cannot be divided by {$b} without remainder
 
+const_eval_extern_static =
+    cannot access extern static ({$did})
 const_eval_fn_ptr_call =
     function pointers need an RFC before allowed to be called in {const_eval_const_context}s
 const_eval_for_loop_into_iter_non_const =
@@ -172,6 +174,10 @@ const_eval_invalid_meta =
     invalid metadata in wide pointer: total size is bigger than largest supported object
 const_eval_invalid_meta_slice =
     invalid metadata in wide pointer: slice is bigger than largest supported object
+
+const_eval_invalid_niched_enum_variant_written =
+    trying to set discriminant of a {$ty} to the niched variant, but the value does not match
+
 const_eval_invalid_str =
     this string is not valid UTF-8: {$err}
 const_eval_invalid_tag =
@@ -298,8 +304,6 @@ const_eval_raw_ptr_to_int =
     .note = at compile-time, pointers do not have an integer value
     .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
 
-const_eval_read_extern_static =
-    cannot read from extern static ({$did})
 const_eval_read_pointer_as_int =
     unable to turn pointer into integer
 const_eval_realloc_or_alloc_with_offset =
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 71085c2b2a5..80d02589900 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -151,7 +151,7 @@ where
             let mut err = tcx.dcx().create_err(err);
 
             let msg = error.diagnostic_message();
-            error.add_args(tcx.dcx(), &mut err);
+            error.add_args(&mut err);
 
             // Use *our* span to label the interp error
             err.span_label(our_span, msg);
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 0844cdbe99b..c55d899e4d5 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -356,22 +356,13 @@ pub fn const_validate_mplace<'mir, 'tcx>(
     let mut inner = false;
     while let Some((mplace, path)) = ref_tracking.todo.pop() {
         let mode = match ecx.tcx.static_mutability(cid.instance.def_id()) {
-            Some(_) if cid.promoted.is_some() => {
-                // Promoteds in statics are consts that re allowed to point to statics.
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell: false,
-                    allow_extern_static_ptrs: true,
-                }
-            }
+            _ if cid.promoted.is_some() => CtfeValidationMode::Promoted,
             Some(mutbl) => CtfeValidationMode::Static { mutbl }, // a `static`
             None => {
                 // In normal `const` (not promoted), the outermost allocation is always only copied,
                 // so having `UnsafeCell` in there is okay despite them being in immutable memory.
                 let allow_immutable_unsafe_cell = cid.promoted.is_none() && !inner;
-                CtfeValidationMode::Const {
-                    allow_immutable_unsafe_cell,
-                    allow_extern_static_ptrs: false,
-                }
+                CtfeValidationMode::Const { allow_immutable_unsafe_cell }
             }
         };
         ecx.const_validate_operand(&mplace.into(), path, &mut ref_tracking, mode)?;
diff --git a/compiler/rustc_const_eval/src/errors.rs b/compiler/rustc_const_eval/src/errors.rs
index fb89b49fade..11679ab77e3 100644
--- a/compiler/rustc_const_eval/src/errors.rs
+++ b/compiler/rustc_const_eval/src/errors.rs
@@ -426,7 +426,7 @@ pub struct UndefinedBehavior {
 pub trait ReportErrorExt {
     /// Returns the diagnostic message for this error.
     fn diagnostic_message(&self) -> DiagnosticMessage;
-    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>);
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>);
 
     fn debug(self) -> String
     where
@@ -434,11 +434,11 @@ pub trait ReportErrorExt {
     {
         ty::tls::with(move |tcx| {
             let dcx = tcx.dcx();
-            let mut builder = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
+            let mut diag = dcx.struct_allow(DiagnosticMessage::Str(String::new().into()));
             let message = self.diagnostic_message();
-            self.add_args(dcx, &mut builder);
-            let s = dcx.eagerly_translate_to_string(message, builder.args());
-            builder.cancel();
+            self.add_args(&mut diag);
+            let s = dcx.eagerly_translate_to_string(message, diag.args());
+            diag.cancel();
             s
         })
     }
@@ -497,25 +497,25 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             ScalarSizeMismatch(_) => const_eval_scalar_size_mismatch,
             UninhabitedEnumVariantWritten(_) => const_eval_uninhabited_enum_variant_written,
             UninhabitedEnumVariantRead(_) => const_eval_uninhabited_enum_variant_read,
+            InvalidNichedEnumVariantWritten { .. } => {
+                const_eval_invalid_niched_enum_variant_written
+            }
             AbiMismatchArgument { .. } => const_eval_incompatible_types,
             AbiMismatchReturn { .. } => const_eval_incompatible_return_types,
         }
     }
 
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         use UndefinedBehaviorInfo::*;
+        let dcx = diag.dcx;
         match self {
             Ub(_) => {}
             Custom(custom) => {
                 (custom.add_args)(&mut |name, value| {
-                    builder.arg(name, value);
+                    diag.arg(name, value);
                 });
             }
-            ValidationError(e) => e.add_args(dcx, builder),
+            ValidationError(e) => e.add_args(diag),
 
             Unreachable
             | DivisionByZero
@@ -530,20 +530,18 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             | UninhabitedEnumVariantWritten(_)
             | UninhabitedEnumVariantRead(_) => {}
             BoundsCheckFailed { len, index } => {
-                builder.arg("len", len);
-                builder.arg("index", index);
+                diag.arg("len", len);
+                diag.arg("index", index);
             }
             UnterminatedCString(ptr) | InvalidFunctionPointer(ptr) | InvalidVTablePointer(ptr) => {
-                builder.arg("pointer", ptr);
+                diag.arg("pointer", ptr);
             }
             PointerUseAfterFree(alloc_id, msg) => {
-                builder
-                    .arg("alloc_id", alloc_id)
+                diag.arg("alloc_id", alloc_id)
                     .arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             PointerOutOfBounds { alloc_id, alloc_size, ptr_offset, ptr_size, msg } => {
-                builder
-                    .arg("alloc_id", alloc_id)
+                diag.arg("alloc_id", alloc_id)
                     .arg("alloc_size", alloc_size.bytes())
                     .arg("ptr_offset", ptr_offset)
                     .arg("ptr_size", ptr_size.bytes())
@@ -551,44 +549,47 @@ impl<'a> ReportErrorExt for UndefinedBehaviorInfo<'a> {
             }
             DanglingIntPointer(ptr, msg) => {
                 if ptr != 0 {
-                    builder.arg("pointer", format!("{ptr:#x}[noalloc]"));
+                    diag.arg("pointer", format!("{ptr:#x}[noalloc]"));
                 }
 
-                builder.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
+                diag.arg("bad_pointer_message", bad_pointer_message(msg, dcx));
             }
             AlignmentCheckFailed(Misalignment { required, has }, msg) => {
-                builder.arg("required", required.bytes());
-                builder.arg("has", has.bytes());
-                builder.arg("msg", format!("{msg:?}"));
+                diag.arg("required", required.bytes());
+                diag.arg("has", has.bytes());
+                diag.arg("msg", format!("{msg:?}"));
             }
             WriteToReadOnly(alloc) | DerefFunctionPointer(alloc) | DerefVTablePointer(alloc) => {
-                builder.arg("allocation", alloc);
+                diag.arg("allocation", alloc);
             }
             InvalidBool(b) => {
-                builder.arg("value", format!("{b:02x}"));
+                diag.arg("value", format!("{b:02x}"));
             }
             InvalidChar(c) => {
-                builder.arg("value", format!("{c:08x}"));
+                diag.arg("value", format!("{c:08x}"));
             }
             InvalidTag(tag) => {
-                builder.arg("tag", format!("{tag:x}"));
+                diag.arg("tag", format!("{tag:x}"));
             }
             InvalidStr(err) => {
-                builder.arg("err", format!("{err}"));
+                diag.arg("err", format!("{err}"));
             }
             InvalidUninitBytes(Some((alloc, info))) => {
-                builder.arg("alloc", alloc);
-                builder.arg("access", info.access);
-                builder.arg("uninit", info.bad);
+                diag.arg("alloc", alloc);
+                diag.arg("access", info.access);
+                diag.arg("uninit", info.bad);
             }
             ScalarSizeMismatch(info) => {
-                builder.arg("target_size", info.target_size);
-                builder.arg("data_size", info.data_size);
+                diag.arg("target_size", info.target_size);
+                diag.arg("data_size", info.data_size);
+            }
+            InvalidNichedEnumVariantWritten { enum_ty } => {
+                diag.arg("ty", enum_ty.to_string());
             }
             AbiMismatchArgument { caller_ty, callee_ty }
             | AbiMismatchReturn { caller_ty, callee_ty } => {
-                builder.arg("caller_ty", caller_ty.to_string());
-                builder.arg("callee_ty", callee_ty.to_string());
+                diag.arg("caller_ty", caller_ty.to_string());
+                diag.arg("callee_ty", callee_ty.to_string());
             }
         }
     }
@@ -668,7 +669,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
     }
 
-    fn add_args<G: EmissionGuarantee>(self, dcx: &DiagCtxt, err: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, err: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated as fluent;
         use rustc_middle::mir::interpret::ValidationErrorKind::*;
 
@@ -678,12 +679,12 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         }
 
         let message = if let Some(path) = self.path {
-            dcx.eagerly_translate_to_string(
+            err.dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value_with_path,
                 [("path".into(), DiagnosticArgValue::Str(path.into()))].iter().map(|(a, b)| (a, b)),
             )
         } else {
-            dcx.eagerly_translate_to_string(
+            err.dcx.eagerly_translate_to_string(
                 fluent::const_eval_validation_front_matter_invalid_value,
                 [].into_iter(),
             )
@@ -694,7 +695,6 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
         fn add_range_arg<G: EmissionGuarantee>(
             r: WrappingRange,
             max_hi: u128,
-            dcx: &DiagCtxt,
             err: &mut DiagnosticBuilder<'_, G>,
         ) {
             let WrappingRange { start: lo, end: hi } = r;
@@ -718,7 +718,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 ("hi".into(), DiagnosticArgValue::Str(hi.to_string().into())),
             ];
             let args = args.iter().map(|(a, b)| (a, b));
-            let message = dcx.eagerly_translate_to_string(msg, args);
+            let message = err.dcx.eagerly_translate_to_string(msg, args);
             err.arg("in_range", message);
         }
 
@@ -740,7 +740,7 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                     ExpectedKind::EnumTag => fluent::const_eval_validation_expected_enum_tag,
                     ExpectedKind::Str => fluent::const_eval_validation_expected_str,
                 };
-                let msg = dcx.eagerly_translate_to_string(msg, [].into_iter());
+                let msg = err.dcx.eagerly_translate_to_string(msg, [].into_iter());
                 err.arg("expected", msg);
             }
             InvalidEnumTag { value }
@@ -751,11 +751,11 @@ impl<'tcx> ReportErrorExt for ValidationErrorInfo<'tcx> {
                 err.arg("value", value);
             }
             NullablePtrOutOfRange { range, max_value } | PtrOutOfRange { range, max_value } => {
-                add_range_arg(range, max_value, dcx, err)
+                add_range_arg(range, max_value, err)
             }
             OutOfRange { range, max_value, value } => {
                 err.arg("value", value);
-                add_range_arg(range, max_value, dcx, err);
+                add_range_arg(range, max_value, err);
             }
             UnalignedPtr { required_bytes, found_bytes, .. } => {
                 err.arg("required_bytes", required_bytes);
@@ -793,16 +793,16 @@ impl ReportErrorExt for UnsupportedOpInfo {
             UnsupportedOpInfo::ReadPartialPointer(_) => const_eval_partial_pointer_copy,
             UnsupportedOpInfo::ReadPointerAsInt(_) => const_eval_read_pointer_as_int,
             UnsupportedOpInfo::ThreadLocalStatic(_) => const_eval_thread_local_static,
-            UnsupportedOpInfo::ReadExternStatic(_) => const_eval_read_extern_static,
+            UnsupportedOpInfo::ExternStatic(_) => const_eval_extern_static,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, builder: &mut DiagnosticBuilder<'_, G>) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         use crate::fluent_generated::*;
 
         use UnsupportedOpInfo::*;
         if let ReadPointerAsInt(_) | OverwritePartialPointer(_) | ReadPartialPointer(_) = self {
-            builder.help(const_eval_ptr_as_bytes_1);
-            builder.help(const_eval_ptr_as_bytes_2);
+            diag.help(const_eval_ptr_as_bytes_1);
+            diag.help(const_eval_ptr_as_bytes_2);
         }
         match self {
             // `ReadPointerAsInt(Some(info))` is never printed anyway, it only serves as an error to
@@ -810,10 +810,10 @@ impl ReportErrorExt for UnsupportedOpInfo {
             // print. So it's not worth the effort of having diagnostics that can print the `info`.
             UnsizedLocal | Unsupported(_) | ReadPointerAsInt(_) => {}
             OverwritePartialPointer(ptr) | ReadPartialPointer(ptr) => {
-                builder.arg("ptr", ptr);
+                diag.arg("ptr", ptr);
             }
-            ThreadLocalStatic(did) | ReadExternStatic(did) => {
-                builder.arg("did", format!("{did:?}"));
+            ThreadLocalStatic(did) | ExternStatic(did) => {
+                diag.arg("did", format!("{did:?}"));
             }
         }
     }
@@ -829,18 +829,14 @@ impl<'tcx> ReportErrorExt for InterpError<'tcx> {
             InterpError::MachineStop(e) => e.diagnostic_message(),
         }
     }
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         match self {
-            InterpError::UndefinedBehavior(ub) => ub.add_args(dcx, builder),
-            InterpError::Unsupported(e) => e.add_args(dcx, builder),
-            InterpError::InvalidProgram(e) => e.add_args(dcx, builder),
-            InterpError::ResourceExhaustion(e) => e.add_args(dcx, builder),
+            InterpError::UndefinedBehavior(ub) => ub.add_args(diag),
+            InterpError::Unsupported(e) => e.add_args(diag),
+            InterpError::InvalidProgram(e) => e.add_args(diag),
+            InterpError::ResourceExhaustion(e) => e.add_args(diag),
             InterpError::MachineStop(e) => e.add_args(&mut |name, value| {
-                builder.arg(name, value);
+                diag.arg(name, value);
             }),
         }
     }
@@ -858,28 +854,24 @@ impl<'tcx> ReportErrorExt for InvalidProgramInfo<'tcx> {
             }
         }
     }
-    fn add_args<G: EmissionGuarantee>(
-        self,
-        dcx: &DiagCtxt,
-        builder: &mut DiagnosticBuilder<'_, G>,
-    ) {
+    fn add_args<G: EmissionGuarantee>(self, diag: &mut DiagnosticBuilder<'_, G>) {
         match self {
             InvalidProgramInfo::TooGeneric | InvalidProgramInfo::AlreadyReported(_) => {}
             InvalidProgramInfo::Layout(e) => {
-                // The level doesn't matter, `diag` is consumed without it being used.
+                // The level doesn't matter, `dummy_diag` is consumed without it being used.
                 let dummy_level = Level::Bug;
-                let diag: DiagnosticBuilder<'_, ()> =
-                    e.into_diagnostic().into_diagnostic(dcx, dummy_level);
-                for (name, val) in diag.args() {
-                    builder.arg(name.clone(), val.clone());
+                let dummy_diag: DiagnosticBuilder<'_, ()> =
+                    e.into_diagnostic().into_diagnostic(diag.dcx, dummy_level);
+                for (name, val) in dummy_diag.args() {
+                    diag.arg(name.clone(), val.clone());
                 }
-                diag.cancel();
+                dummy_diag.cancel();
             }
             InvalidProgramInfo::FnAbiAdjustForForeignAbi(
                 AdjustForForeignAbiError::Unsupported { arch, abi },
             ) => {
-                builder.arg("arch", arch);
-                builder.arg("abi", abi.name());
+                diag.arg("arch", arch);
+                diag.arg("abi", abi.name());
             }
         }
     }
@@ -894,7 +886,7 @@ impl ReportErrorExt for ResourceExhaustionInfo {
             ResourceExhaustionInfo::AddressSpaceFull => const_eval_address_space_full,
         }
     }
-    fn add_args<G: EmissionGuarantee>(self, _: &DiagCtxt, _: &mut DiagnosticBuilder<'_, G>) {}
+    fn add_args<G: EmissionGuarantee>(self, _: &mut DiagnosticBuilder<'_, G>) {}
 }
 
 impl rustc_errors::IntoDiagnosticArg for InternKind {
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index bb8c17cf779..e951a77611c 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -85,6 +85,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                     // Write result.
                     let niche_dest = self.project_field(dest, tag_field)?;
                     self.write_immediate(*tag_val, &niche_dest)?;
+                } else {
+                    // The untagged variant is implicitly encoded simply by having a value that is
+                    // outside the niche variants. But what if the data stored here does not
+                    // actually encode this variant? That would be bad! So let's double-check...
+                    let actual_variant = self.read_discriminant(&dest.to_op(self)?)?;
+                    if actual_variant != variant_index {
+                        throw_ub!(InvalidNichedEnumVariantWritten { enum_ty: dest.layout().ty });
+                    }
                 }
             }
         }
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index dd9dfe3fe79..ff90059203a 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -445,7 +445,7 @@ pub fn format_interp_error<'tcx>(dcx: &DiagCtxt, e: InterpErrorInfo<'tcx>) -> St
     #[allow(rustc::untranslatable_diagnostic)]
     let mut diag = dcx.struct_allow("");
     let msg = e.diagnostic_message();
-    e.add_args(dcx, &mut diag);
+    e.add_args(&mut diag);
     let s = dcx.eagerly_translate_to_string(msg, diag.args());
     diag.cancel();
     s
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 38ad8cbf3a6..4acf4ed893c 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -557,7 +557,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
                 if self.tcx.is_foreign_item(def_id) {
                     // This is unreachable in Miri, but can happen in CTFE where we actually *do* support
                     // referencing arbitrary (declared) extern statics.
-                    throw_unsup!(ReadExternStatic(def_id));
+                    throw_unsup!(ExternStatic(def_id));
                 }
 
                 // We don't give a span -- statics don't need that, they cannot be generic or associated.
diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs
index 3a441c1d649..7b68a37fdf3 100644
--- a/compiler/rustc_const_eval/src/interpret/projection.rs
+++ b/compiler/rustc_const_eval/src/interpret/projection.rs
@@ -149,6 +149,8 @@ where
             "`field` projection called on a slice -- call `index` projection instead"
         );
         let offset = base.layout().fields.offset(field);
+        // Computing the layout does normalization, so we get a normalized type out of this
+        // even if the field type is non-normalized (possible e.g. via associated types).
         let field_layout = base.layout().field(self, field);
 
         // Offset may need adjustment for unsized fields.
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 38aeace02ba..05e28db652f 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -129,17 +129,20 @@ pub enum PathElem {
 pub enum CtfeValidationMode {
     /// Validation of a `static`
     Static { mutbl: Mutability },
-    /// Validation of a `const` (including promoteds).
+    /// Validation of a promoted.
+    Promoted,
+    /// Validation of a `const`.
     /// `allow_immutable_unsafe_cell` says whether we allow `UnsafeCell` in immutable memory (which is the
     /// case for the top-level allocation of a `const`, where this is fine because the allocation will be
     /// copied at each use site).
-    Const { allow_immutable_unsafe_cell: bool, allow_extern_static_ptrs: bool },
+    Const { allow_immutable_unsafe_cell: bool },
 }
 
 impl CtfeValidationMode {
     fn allow_immutable_unsafe_cell(self) -> bool {
         match self {
             CtfeValidationMode::Static { .. } => false,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { allow_immutable_unsafe_cell, .. } => {
                 allow_immutable_unsafe_cell
             }
@@ -149,6 +152,7 @@ impl CtfeValidationMode {
     fn may_contain_mutable_ref(self) -> bool {
         match self {
             CtfeValidationMode::Static { mutbl } => mutbl == Mutability::Mut,
+            CtfeValidationMode::Promoted { .. } => false,
             CtfeValidationMode::Const { .. } => false,
         }
     }
@@ -476,34 +480,32 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, '
                                 throw_validation_failure!(self.path, MutableRefToImmutable);
                             }
                         }
+                        // Mode-specific checks
                         match self.ctfe_mode {
-                            Some(CtfeValidationMode::Static { .. }) => {
+                            Some(
+                                CtfeValidationMode::Static { .. }
+                                | CtfeValidationMode::Promoted { .. },
+                            ) => {
                                 // We skip recursively checking other statics. These statics must be sound by
                                 // themselves, and the only way to get broken statics here is by using
                                 // unsafe code.
                                 // The reasons we don't check other statics is twofold. For one, in all
                                 // sound cases, the static was already validated on its own, and second, we
                                 // trigger cycle errors if we try to compute the value of the other static
-                                // and that static refers back to us.
+                                // and that static refers back to us (potentially through a promoted).
                                 // This could miss some UB, but that's fine.
                                 return Ok(());
                             }
-                            Some(CtfeValidationMode::Const {
-                                allow_extern_static_ptrs, ..
-                            }) => {
+                            Some(CtfeValidationMode::Const { .. }) => {
                                 // For consts on the other hand we have to recursively check;
                                 // pattern matching assumes a valid value. However we better make
                                 // sure this is not mutable.
                                 if is_mut {
                                     throw_validation_failure!(self.path, ConstRefToMutable);
                                 }
+                                // We can't recursively validate `extern static`, so we better reject them.
                                 if self.ecx.tcx.is_foreign_item(did) {
-                                    if !allow_extern_static_ptrs {
-                                        throw_validation_failure!(self.path, ConstRefToExtern);
-                                    } else {
-                                        // We can't validate this...
-                                        return Ok(());
-                                    }
+                                    throw_validation_failure!(self.path, ConstRefToExtern);
                                 }
                             }
                             None => {}
diff --git a/compiler/rustc_const_eval/src/interpret/visitor.rs b/compiler/rustc_const_eval/src/interpret/visitor.rs
index de0590a4b14..340a496a689 100644
--- a/compiler/rustc_const_eval/src/interpret/visitor.rs
+++ b/compiler/rustc_const_eval/src/interpret/visitor.rs
@@ -153,6 +153,16 @@ pub trait ValueVisitor<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>>: Sized {
                 // We visited all parts of this one.
                 return Ok(());
             }
+
+            // Non-normalized types should never show up here.
+            ty::Param(..)
+            | ty::Alias(..)
+            | ty::Bound(..)
+            | ty::Placeholder(..)
+            | ty::Infer(..)
+            | ty::Error(..) => throw_inval!(TooGeneric),
+
+            // The rest is handled below.
             _ => {}
         };
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 28dc69859fd..43048dc41d3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -619,9 +619,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
                 if base_ty.is_unsafe_ptr() {
                     if place_ref.projection.is_empty() {
                         let decl = &self.body.local_decls[place_ref.local];
-                        if let LocalInfo::StaticRef { def_id, .. } = *decl.local_info() {
-                            let span = decl.source_info.span;
-                            self.check_static(def_id, span);
+                        // If this is a static, then this is not really dereferencing a pointer,
+                        // just directly accessing a static. That is not subject to any feature
+                        // gates (except for the one about whether statics can even be used, but
+                        // that is checked already by `visit_operand`).
+                        if let LocalInfo::StaticRef { .. } = *decl.local_info() {
                             return;
                         }
                     }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 98276ff2e68..1be2a2bc1f3 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -131,11 +131,10 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
     let local_def_id = def_id.expect_local();
     let hir_id = tcx.local_def_id_to_hir_id(local_def_id);
 
-    let Some(parent) = tcx.hir().opt_parent_id(hir_id) else { return false };
-
-    if !tcx.is_const_trait_impl_raw(parent.owner.def_id.to_def_id()) {
+    let parent_owner_id = tcx.parent_hir_id(hir_id).owner;
+    if !tcx.is_const_trait_impl_raw(parent_owner_id.to_def_id()) {
         return false;
     }
 
-    tcx.lookup_const_stability(parent.owner).is_some_and(|stab| stab.is_const_stable())
+    tcx.lookup_const_stability(parent_owner_id).is_some_and(|stab| stab.is_const_stable())
 }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index a9d472d377c..0c93cfaa546 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -409,11 +409,6 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
     fn status_in_item(&self, _: &ConstCx<'_, 'tcx>) -> Status {
         Status::Unstable(sym::const_refs_to_cell)
     }
-    fn importance(&self) -> DiagnosticImportance {
-        // The cases that cannot possibly work will already emit a `CellBorrow`, so we should
-        // not additionally emit a feature gate error if activating the feature gate won't work.
-        DiagnosticImportance::Secondary
-    }
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         ccx.tcx
             .sess
@@ -427,6 +422,11 @@ impl<'tcx> NonConstOp<'tcx> for TransientCellBorrow {
 /// it in the future for static items.
 pub struct CellBorrow;
 impl<'tcx> NonConstOp<'tcx> for CellBorrow {
+    fn importance(&self) -> DiagnosticImportance {
+        // Most likely the code will try to do mutation with these borrows, which
+        // triggers its own errors. Only show this one if that does not happen.
+        DiagnosticImportance::Secondary
+    }
     fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> {
         // FIXME: Maybe a more elegant solution to this if else case
         if let hir::ConstContext::Static(_) = ccx.const_kind() {
@@ -459,8 +459,8 @@ impl<'tcx> NonConstOp<'tcx> for MutBorrow {
     }
 
     fn importance(&self) -> DiagnosticImportance {
-        // If there were primary errors (like non-const function calls), do not emit further
-        // errors about mutable references.
+        // Most likely the code will try to do mutation with these borrows, which
+        // triggers its own errors. Only show this one if that does not happen.
         DiagnosticImportance::Secondary
     }
 
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
index a23922c778f..2c835f6750f 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/resolver.rs
@@ -96,7 +96,7 @@ where
         });
     }
 
-    fn address_of_allows_mutation(&self, _mt: mir::Mutability, _place: mir::Place<'tcx>) -> bool {
+    fn address_of_allows_mutation(&self) -> bool {
         // Exact set of permissions granted by AddressOf is undecided. Conservatively assume that
         // it might allow mutation until resolution of #56604.
         true
@@ -171,10 +171,8 @@ where
         self.super_rvalue(rvalue, location);
 
         match rvalue {
-            mir::Rvalue::AddressOf(mt, borrowed_place) => {
-                if !borrowed_place.is_indirect()
-                    && self.address_of_allows_mutation(*mt, *borrowed_place)
-                {
+            mir::Rvalue::AddressOf(_mt, borrowed_place) => {
+                if !borrowed_place.is_indirect() && self.address_of_allows_mutation() {
                     let place_ty = borrowed_place.ty(self.ccx.body, self.ccx.tcx).ty;
                     if Q::in_any_value_of_ty(self.ccx, place_ty) {
                         self.state.qualif.insert(borrowed_place.local);
diff --git a/compiler/rustc_errors/src/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs
index 03717a4d654..2deb18484ec 100644
--- a/compiler/rustc_errors/src/diagnostic.rs
+++ b/compiler/rustc_errors/src/diagnostic.rs
@@ -516,6 +516,17 @@ impl Diagnostic {
 
     /// Helper for pushing to `self.suggestions`, if available (not disable).
     fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
+        for subst in &suggestion.substitutions {
+            for part in &subst.parts {
+                let span = part.span;
+                let call_site = span.ctxt().outer_expn_data().call_site;
+                if span.in_derive_expansion() && span.overlaps_or_adjacent(call_site) {
+                    // Ignore if spans is from derive macro.
+                    return;
+                }
+            }
+        }
+
         if let Ok(suggestions) = &mut self.suggestions {
             suggestions.push(suggestion);
         }
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index ab3ad0e9d68..da9ef6627be 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -411,8 +411,8 @@ impl CodeSuggestion {
 /// or `.span_bug` rather than a failed assertion, etc.
 pub struct ExplicitBug;
 
-/// Signifies that the compiler died with an explicit call to `.delay_*_bug`
-/// rather than a failed assertion, etc.
+/// Signifies that the compiler died due to a delayed bug rather than a failed
+/// assertion, etc.
 pub struct DelayedBugPanic;
 
 /// A `DiagCtxt` deals with errors and other compiler output.
@@ -428,10 +428,14 @@ pub struct DiagCtxt {
 struct DiagCtxtInner {
     flags: DiagCtxtFlags,
 
-    /// The number of lint errors that have been emitted, including duplicates.
-    lint_err_count: usize,
-    /// The number of non-lint errors that have been emitted, including duplicates.
-    err_count: usize,
+    /// The error guarantees from all emitted errors. The length gives the error count.
+    err_guars: Vec<ErrorGuaranteed>,
+    /// The error guarantee from all emitted lint errors. The length gives the
+    /// lint error count.
+    lint_err_guars: Vec<ErrorGuaranteed>,
+    /// The delayed bugs and their error guarantees.
+    delayed_bugs: Vec<(DelayedDiagnostic, ErrorGuaranteed)>,
+    good_path_delayed_bugs: Vec<DelayedDiagnostic>,
 
     /// The number of stashed errors. Unlike the other counts, this can go up
     /// and down, so it doesn't guarantee anything.
@@ -447,8 +451,6 @@ struct DiagCtxtInner {
     has_printed: bool,
 
     emitter: Box<DynEmitter>,
-    delayed_bugs: Vec<DelayedDiagnostic>,
-    good_path_delayed_bugs: Vec<DelayedDiagnostic>,
     /// This flag indicates that an expected diagnostic was emitted and suppressed.
     /// This is used for the `good_path_delayed_bugs` check.
     suppressed_expected_diag: bool,
@@ -560,7 +562,7 @@ impl Drop for DiagCtxtInner {
     fn drop(&mut self) {
         self.emit_stashed_diagnostics();
 
-        if !self.has_errors() {
+        if self.err_guars.is_empty() {
             self.flush_delayed(DelayedBugKind::Normal)
         }
 
@@ -604,15 +606,15 @@ impl DiagCtxt {
         Self {
             inner: Lock::new(DiagCtxtInner {
                 flags: DiagCtxtFlags { can_emit_warnings: true, ..Default::default() },
-                lint_err_count: 0,
-                err_count: 0,
+                err_guars: Vec::new(),
+                lint_err_guars: Vec::new(),
+                delayed_bugs: Vec::new(),
+                good_path_delayed_bugs: Vec::new(),
                 stashed_err_count: 0,
                 deduplicated_err_count: 0,
                 deduplicated_warn_count: 0,
                 has_printed: false,
                 emitter,
-                delayed_bugs: Vec::new(),
-                good_path_delayed_bugs: Vec::new(),
                 suppressed_expected_diag: false,
                 taught_diagnostics: Default::default(),
                 emitted_diagnostic_codes: Default::default(),
@@ -661,14 +663,14 @@ impl DiagCtxt {
     /// the overall count of emitted error diagnostics.
     pub fn reset_err_count(&self) {
         let mut inner = self.inner.borrow_mut();
-        inner.lint_err_count = 0;
-        inner.err_count = 0;
         inner.stashed_err_count = 0;
         inner.deduplicated_err_count = 0;
         inner.deduplicated_warn_count = 0;
         inner.has_printed = false;
 
         // actually free the underlying memory (which `clear` would not do)
+        inner.err_guars = Default::default();
+        inner.lint_err_guars = Default::default();
         inner.delayed_bugs = Default::default();
         inner.good_path_delayed_bugs = Default::default();
         inner.taught_diagnostics = Default::default();
@@ -718,221 +720,10 @@ impl DiagCtxt {
         self.inner.borrow_mut().emit_stashed_diagnostics()
     }
 
-    /// Construct a builder at the `Warning` level at the given `span` and with the `msg`.
-    ///
-    /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_warn(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, ()> {
-        self.struct_warn(msg).with_span(span)
-    }
-
-    /// Construct a builder at the `Warning` level with the `msg`.
-    ///
-    /// An `emit` call on the builder will only emit if `can_emit_warnings` is `true`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Warning, msg)
-    }
-
-    /// Construct a builder at the `Allow` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Allow, msg)
-    }
-
-    /// Construct a builder at the `Expect` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_expect(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-        id: LintExpectationId,
-    ) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Expect(id), msg)
-    }
-
-    /// Construct a builder at the `Error` level at the given `span` and with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_err(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_> {
-        self.struct_err(msg).with_span(span)
-    }
-
-    /// Construct a builder at the `Error` level with the `msg`.
-    // FIXME: This method should be removed (every error should have an associated error code).
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
-        DiagnosticBuilder::new(self, Error, msg)
-    }
-
-    /// Construct a builder at the `Fatal` level at the given `span` and with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_fatal(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        self.struct_fatal(msg).with_span(span)
-    }
-
-    /// Construct a builder at the `Fatal` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_fatal(
-        &self,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, FatalAbort> {
-        DiagnosticBuilder::new(self, Fatal, msg)
-    }
-
-    /// Construct a builder at the `Help` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Help, msg)
-    }
-
-    /// Construct a builder at the `Note` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Note, msg)
-    }
-
-    /// Construct a builder at the `Bug` level with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_bug(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, BugAbort> {
-        DiagnosticBuilder::new(self, Bug, msg)
-    }
-
-    /// Construct a builder at the `Bug` level at the given `span` with the `msg`.
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn struct_span_bug(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, BugAbort> {
-        self.struct_bug(msg).with_span(span)
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.struct_span_fatal(span, msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_err(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> ErrorGuaranteed {
-        self.struct_span_err(span, msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    #[track_caller]
-    pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.struct_span_warn(span, msg).emit()
-    }
-
-    #[track_caller]
-    pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.struct_span_bug(span, msg).emit()
-    }
-
-    /// Ensures that compilation cannot succeed.
-    ///
-    /// If this function has been called but no errors have been emitted and
-    /// compilation succeeds, it will cause an internal compiler error (ICE).
-    ///
-    /// This can be used in code paths that should never run on successful compilations.
-    /// For example, it can be used to create an [`ErrorGuaranteed`]
-    /// (but you should prefer threading through the [`ErrorGuaranteed`] from an error emission
-    /// directly).
-    #[track_caller]
-    pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
-    }
-
-    /// Like `delayed_bug`, but takes an additional span.
-    ///
-    /// Note: this function used to be called `delay_span_bug`. It was renamed
-    /// to match similar functions like `span_err`, `span_warn`, etc.
-    #[track_caller]
-    pub fn span_delayed_bug(
-        &self,
-        sp: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> ErrorGuaranteed {
-        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
-    }
-
-    /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
-    pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
-        DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
-    }
-
-    #[track_caller]
-    #[rustc_lint_diagnostics]
-    pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
-        self.struct_span_note(span, msg).emit()
-    }
-
-    #[track_caller]
-    #[rustc_lint_diagnostics]
-    pub fn struct_span_note(
-        &self,
-        span: impl Into<MultiSpan>,
-        msg: impl Into<DiagnosticMessage>,
-    ) -> DiagnosticBuilder<'_, ()> {
-        DiagnosticBuilder::new(self, Note, msg).with_span(span)
-    }
-
-    #[rustc_lint_diagnostics]
-    pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.struct_fatal(msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
-        self.struct_err(msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
-        self.struct_warn(msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
-        self.struct_note(msg).emit()
-    }
-
-    #[rustc_lint_diagnostics]
-    pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
-        self.struct_bug(msg).emit()
-    }
-
     /// This excludes lint errors, delayed bugs, and stashed errors.
     #[inline]
     pub fn err_count(&self) -> usize {
-        self.inner.borrow().err_count
+        self.inner.borrow().err_guars.len()
     }
 
     /// This excludes normal errors, lint errors and delayed bugs. Unless
@@ -946,36 +737,19 @@ impl DiagCtxt {
 
     /// This excludes lint errors, delayed bugs, and stashed errors.
     pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
-        self.inner.borrow().has_errors().then(|| {
-            // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
-            #[allow(deprecated)]
-            ErrorGuaranteed::unchecked_error_guaranteed()
-        })
+        self.inner.borrow().has_errors()
     }
 
     /// This excludes delayed bugs and stashed errors. Unless absolutely
     /// necessary, prefer `has_errors` to this method.
     pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
-        let inner = self.inner.borrow();
-        let result = inner.has_errors() || inner.lint_err_count > 0;
-        result.then(|| {
-            // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
-            #[allow(deprecated)]
-            ErrorGuaranteed::unchecked_error_guaranteed()
-        })
+        self.inner.borrow().has_errors_or_lint_errors()
     }
 
     /// This excludes stashed errors. Unless absolutely necessary, prefer
     /// `has_errors` or `has_errors_or_lint_errors` to this method.
     pub fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
-        let inner = self.inner.borrow();
-        let result =
-            inner.has_errors() || inner.lint_err_count > 0 || !inner.delayed_bugs.is_empty();
-        result.then(|| {
-            // FIXME(nnethercote) find a way to store an `ErrorGuaranteed`.
-            #[allow(deprecated)]
-            ErrorGuaranteed::unchecked_error_guaranteed()
-        })
+        self.inner.borrow().has_errors_or_lint_errors_or_delayed_bugs()
     }
 
     pub fn print_error_count(&self, registry: &Registry) {
@@ -1008,10 +782,10 @@ impl DiagCtxt {
                     .emit_diagnostic(Diagnostic::new(Warning, DiagnosticMessage::Str(warnings)));
             }
             (_, 0) => {
-                inner.emit_diagnostic(Diagnostic::new(Fatal, errors));
+                inner.emit_diagnostic(Diagnostic::new(Error, errors));
             }
             (_, _) => {
-                inner.emit_diagnostic(Diagnostic::new(Fatal, format!("{errors}; {warnings}")));
+                inner.emit_diagnostic(Diagnostic::new(Error, format!("{errors}; {warnings}")));
             }
         }
 
@@ -1055,7 +829,7 @@ impl DiagCtxt {
     pub fn abort_if_errors(&self) {
         let mut inner = self.inner.borrow_mut();
         inner.emit_stashed_diagnostics();
-        if inner.has_errors() {
+        if !inner.err_guars.is_empty() {
             FatalError.raise();
         }
     }
@@ -1077,84 +851,6 @@ impl DiagCtxt {
         self.inner.borrow_mut().emit_diagnostic(diagnostic)
     }
 
-    #[track_caller]
-    pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
-        self.create_err(err).emit()
-    }
-
-    #[track_caller]
-    pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
-        err.into_diagnostic(self, Error)
-    }
-
-    #[track_caller]
-    pub fn create_warn<'a>(
-        &'a self,
-        warning: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        warning.into_diagnostic(self, Warning)
-    }
-
-    #[track_caller]
-    pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
-        self.create_warn(warning).emit()
-    }
-
-    #[track_caller]
-    pub fn create_almost_fatal<'a>(
-        &'a self,
-        fatal: impl IntoDiagnostic<'a, FatalError>,
-    ) -> DiagnosticBuilder<'a, FatalError> {
-        fatal.into_diagnostic(self, Fatal)
-    }
-
-    #[track_caller]
-    pub fn emit_almost_fatal<'a>(
-        &'a self,
-        fatal: impl IntoDiagnostic<'a, FatalError>,
-    ) -> FatalError {
-        self.create_almost_fatal(fatal).emit()
-    }
-
-    #[track_caller]
-    pub fn create_fatal<'a>(
-        &'a self,
-        fatal: impl IntoDiagnostic<'a, FatalAbort>,
-    ) -> DiagnosticBuilder<'a, FatalAbort> {
-        fatal.into_diagnostic(self, Fatal)
-    }
-
-    #[track_caller]
-    pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
-        self.create_fatal(fatal).emit()
-    }
-
-    #[track_caller]
-    pub fn create_bug<'a>(
-        &'a self,
-        bug: impl IntoDiagnostic<'a, BugAbort>,
-    ) -> DiagnosticBuilder<'a, BugAbort> {
-        bug.into_diagnostic(self, Bug)
-    }
-
-    #[track_caller]
-    pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, diagnostic_builder::BugAbort>) -> ! {
-        self.create_bug(bug).emit()
-    }
-
-    #[track_caller]
-    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
-        self.create_note(note).emit()
-    }
-
-    #[track_caller]
-    pub fn create_note<'a>(
-        &'a self,
-        note: impl IntoDiagnostic<'a, ()>,
-    ) -> DiagnosticBuilder<'a, ()> {
-        note.into_diagnostic(self, Note)
-    }
-
     pub fn emit_artifact_notification(&self, path: &Path, artifact_type: &str) {
         self.inner.borrow_mut().emitter.emit_artifact_notification(path, artifact_type);
     }
@@ -1175,8 +871,21 @@ impl DiagCtxt {
     ) {
         let mut inner = self.inner.borrow_mut();
 
+        // This "error" is an odd duck.
+        // - It's only produce with JSON output.
+        // - It's not emitted the usual way, via `emit_diagnostic`.
+        // - The `$message_type` field is "unused_externs" rather than the usual
+        //   "diagnosic".
+        //
+        // We count it as a lint error because it has a lint level. The value
+        // of `loud` (which comes from "unused-externs" or
+        // "unused-externs-silent"), also affects whether it's treated like a
+        // hard error or not.
         if loud && lint_level.is_error() {
-            inner.lint_err_count += 1;
+            // This `unchecked_error_guaranteed` is valid. It is where the
+            // `ErrorGuaranteed` for unused_extern errors originates.
+            #[allow(deprecated)]
+            inner.lint_err_guars.push(ErrorGuaranteed::unchecked_error_guaranteed());
             inner.panic_if_treat_err_as_bug();
         }
 
@@ -1229,6 +938,288 @@ impl DiagCtxt {
     }
 }
 
+// This `impl` block contains only the public diagnostic creation/emission API.
+//
+// Functions beginning with `struct_`/`create_` create a diagnostic. Other
+// functions create and emit a diagnostic all in one go.
+impl DiagCtxt {
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn struct_bug(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, BugAbort> {
+        DiagnosticBuilder::new(self, Bug, msg)
+    }
+
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn bug(&self, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.struct_bug(msg).emit()
+    }
+
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn struct_span_bug(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, BugAbort> {
+        self.struct_bug(msg).with_span(span)
+    }
+
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn span_bug(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.struct_span_bug(span, msg).emit()
+    }
+
+    #[track_caller]
+    pub fn create_bug<'a>(
+        &'a self,
+        bug: impl IntoDiagnostic<'a, BugAbort>,
+    ) -> DiagnosticBuilder<'a, BugAbort> {
+        bug.into_diagnostic(self, Bug)
+    }
+
+    #[track_caller]
+    pub fn emit_bug<'a>(&'a self, bug: impl IntoDiagnostic<'a, BugAbort>) -> ! {
+        self.create_bug(bug).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_fatal(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, FatalAbort> {
+        DiagnosticBuilder::new(self, Fatal, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn fatal(&self, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.struct_fatal(msg).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_span_fatal(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, FatalAbort> {
+        self.struct_fatal(msg).with_span(span)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn span_fatal(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) -> ! {
+        self.struct_span_fatal(span, msg).emit()
+    }
+
+    #[track_caller]
+    pub fn create_fatal<'a>(
+        &'a self,
+        fatal: impl IntoDiagnostic<'a, FatalAbort>,
+    ) -> DiagnosticBuilder<'a, FatalAbort> {
+        fatal.into_diagnostic(self, Fatal)
+    }
+
+    #[track_caller]
+    pub fn emit_fatal<'a>(&'a self, fatal: impl IntoDiagnostic<'a, FatalAbort>) -> ! {
+        self.create_fatal(fatal).emit()
+    }
+
+    #[track_caller]
+    pub fn create_almost_fatal<'a>(
+        &'a self,
+        fatal: impl IntoDiagnostic<'a, FatalError>,
+    ) -> DiagnosticBuilder<'a, FatalError> {
+        fatal.into_diagnostic(self, Fatal)
+    }
+
+    #[track_caller]
+    pub fn emit_almost_fatal<'a>(
+        &'a self,
+        fatal: impl IntoDiagnostic<'a, FatalError>,
+    ) -> FatalError {
+        self.create_almost_fatal(fatal).emit()
+    }
+
+    // FIXME: This method should be removed (every error should have an associated error code).
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_err(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_> {
+        DiagnosticBuilder::new(self, Error, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn err(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
+        self.struct_err(msg).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_span_err(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_> {
+        self.struct_err(msg).with_span(span)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn span_err(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> ErrorGuaranteed {
+        self.struct_span_err(span, msg).emit()
+    }
+
+    #[track_caller]
+    pub fn create_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> DiagnosticBuilder<'a> {
+        err.into_diagnostic(self, Error)
+    }
+
+    #[track_caller]
+    pub fn emit_err<'a>(&'a self, err: impl IntoDiagnostic<'a>) -> ErrorGuaranteed {
+        self.create_err(err).emit()
+    }
+
+    /// Ensures that an error is printed. See `Level::DelayedBug`.
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn delayed_bug(&self, msg: impl Into<DiagnosticMessage>) -> ErrorGuaranteed {
+        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).emit()
+    }
+
+    /// Ensures that an error is printed. See `Level::DelayedBug`.
+    ///
+    /// Note: this function used to be called `delay_span_bug`. It was renamed
+    /// to match similar functions like `span_err`, `span_warn`, etc.
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn span_delayed_bug(
+        &self,
+        sp: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> ErrorGuaranteed {
+        DiagnosticBuilder::<ErrorGuaranteed>::new(self, DelayedBug, msg).with_span(sp).emit()
+    }
+
+    /// Ensures that a diagnostic is printed. See `Level::GoodPathDelayedBug`.
+    // No `#[rustc_lint_diagnostics]` because bug messages aren't user-facing.
+    #[track_caller]
+    pub fn good_path_delayed_bug(&self, msg: impl Into<DiagnosticMessage>) {
+        DiagnosticBuilder::<()>::new(self, GoodPathDelayedBug, msg).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_warn(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Warning, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn warn(&self, msg: impl Into<DiagnosticMessage>) {
+        self.struct_warn(msg).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_span_warn(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, ()> {
+        self.struct_warn(msg).with_span(span)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn span_warn(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
+        self.struct_span_warn(span, msg).emit()
+    }
+
+    #[track_caller]
+    pub fn create_warn<'a>(
+        &'a self,
+        warning: impl IntoDiagnostic<'a, ()>,
+    ) -> DiagnosticBuilder<'a, ()> {
+        warning.into_diagnostic(self, Warning)
+    }
+
+    #[track_caller]
+    pub fn emit_warn<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) {
+        self.create_warn(warning).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_note(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Note, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn note(&self, msg: impl Into<DiagnosticMessage>) {
+        self.struct_note(msg).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_span_note(
+        &self,
+        span: impl Into<MultiSpan>,
+        msg: impl Into<DiagnosticMessage>,
+    ) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Note, msg).with_span(span)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn span_note(&self, span: impl Into<MultiSpan>, msg: impl Into<DiagnosticMessage>) {
+        self.struct_span_note(span, msg).emit()
+    }
+
+    #[track_caller]
+    pub fn create_note<'a>(
+        &'a self,
+        note: impl IntoDiagnostic<'a, ()>,
+    ) -> DiagnosticBuilder<'a, ()> {
+        note.into_diagnostic(self, Note)
+    }
+
+    #[track_caller]
+    pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, ()>) {
+        self.create_note(note).emit()
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_help(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Help, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_allow(&self, msg: impl Into<DiagnosticMessage>) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Allow, msg)
+    }
+
+    #[rustc_lint_diagnostics]
+    #[track_caller]
+    pub fn struct_expect(
+        &self,
+        msg: impl Into<DiagnosticMessage>,
+        id: LintExpectationId,
+    ) -> DiagnosticBuilder<'_, ()> {
+        DiagnosticBuilder::new(self, Expect(id), msg)
+    }
+}
+
 // Note: we prefer implementing operations on `DiagCtxt`, rather than
 // `DiagCtxtInner`, whenever possible. This minimizes functions where
 // `DiagCtxt::foo()` just borrows `inner` and forwards a call to
@@ -1236,7 +1227,7 @@ impl DiagCtxt {
 impl DiagCtxtInner {
     /// Emit all stashed diagnostics.
     fn emit_stashed_diagnostics(&mut self) {
-        let has_errors = self.has_errors();
+        let has_errors = !self.err_guars.is_empty();
         for (_, diag) in std::mem::take(&mut self.stashed_diagnostics).into_iter() {
             // Decrement the count tracking the stash; emitting will increment it.
             if diag.is_error() {
@@ -1298,9 +1289,13 @@ impl DiagCtxtInner {
                 // when an error is first emitted, also), but maybe there's a case
                 // in which that's not sound? otherwise this is really inefficient.
                 let backtrace = std::backtrace::Backtrace::capture();
-                self.delayed_bugs.push(DelayedDiagnostic::with_backtrace(diagnostic, backtrace));
+                // This `unchecked_error_guaranteed` is valid. It is where the
+                // `ErrorGuaranteed` for delayed bugs originates.
                 #[allow(deprecated)]
-                return Some(ErrorGuaranteed::unchecked_error_guaranteed());
+                let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+                self.delayed_bugs
+                    .push((DelayedDiagnostic::with_backtrace(diagnostic, backtrace), guar));
+                return Some(guar);
             }
             GoodPathDelayedBug => {
                 let backtrace = std::backtrace::Backtrace::capture();
@@ -1334,7 +1329,6 @@ impl DiagCtxtInner {
                 !self.emitted_diagnostics.insert(diagnostic_hash)
             };
 
-            let level = diagnostic.level;
             let is_error = diagnostic.is_error();
             let is_lint = diagnostic.is_lint.is_some();
 
@@ -1373,36 +1367,47 @@ impl DiagCtxtInner {
             }
 
             if is_error {
+                // This `unchecked_error_guaranteed` is valid. It is where the
+                // `ErrorGuaranteed` for errors and lint errors originates.
+                #[allow(deprecated)]
+                let guar = ErrorGuaranteed::unchecked_error_guaranteed();
+                guaranteed = Some(guar);
                 if is_lint {
-                    self.lint_err_count += 1;
+                    self.lint_err_guars.push(guar);
                 } else {
-                    self.err_count += 1;
+                    self.err_guars.push(guar);
                 }
                 self.panic_if_treat_err_as_bug();
             }
-
-            #[allow(deprecated)]
-            if level == Level::Error {
-                guaranteed = Some(ErrorGuaranteed::unchecked_error_guaranteed());
-            }
         });
 
         guaranteed
     }
 
     fn treat_err_as_bug(&self) -> bool {
-        self.flags.treat_err_as_bug.is_some_and(|c| self.err_count + self.lint_err_count >= c.get())
+        self.flags
+            .treat_err_as_bug
+            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() >= c.get())
     }
 
     // Use this one before incrementing `err_count`.
     fn treat_next_err_as_bug(&self) -> bool {
         self.flags
             .treat_err_as_bug
-            .is_some_and(|c| self.err_count + self.lint_err_count + 1 >= c.get())
+            .is_some_and(|c| self.err_guars.len() + self.lint_err_guars.len() + 1 >= c.get())
+    }
+
+    fn has_errors(&self) -> Option<ErrorGuaranteed> {
+        self.err_guars.get(0).copied()
+    }
+
+    fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
+        self.has_errors().or_else(|| self.lint_err_guars.get(0).copied())
     }
 
-    fn has_errors(&self) -> bool {
-        self.err_count > 0
+    fn has_errors_or_lint_errors_or_delayed_bugs(&self) -> Option<ErrorGuaranteed> {
+        self.has_errors_or_lint_errors()
+            .or_else(|| self.delayed_bugs.get(0).map(|(_, guar)| guar).copied())
     }
 
     fn failure_note(&mut self, msg: impl Into<DiagnosticMessage>) {
@@ -1412,7 +1417,7 @@ impl DiagCtxtInner {
     fn flush_delayed(&mut self, kind: DelayedBugKind) {
         let (bugs, note1) = match kind {
             DelayedBugKind::Normal => (
-                std::mem::take(&mut self.delayed_bugs),
+                std::mem::take(&mut self.delayed_bugs).into_iter().map(|(b, _)| b).collect(),
                 "no errors encountered even though delayed bugs were created",
             ),
             DelayedBugKind::GoodPath => (
@@ -1434,7 +1439,7 @@ impl DiagCtxtInner {
             {
                 let _ = write!(
                     &mut out,
-                    "delayed span bug: {}\n{}\n",
+                    "delayed bug: {}\n{}\n",
                     bug.inner
                         .messages
                         .iter()
@@ -1477,7 +1482,7 @@ impl DiagCtxtInner {
     fn panic_if_treat_err_as_bug(&self) {
         if self.treat_err_as_bug() {
             let n = self.flags.treat_err_as_bug.map(|c| c.get()).unwrap();
-            assert_eq!(n, self.err_count + self.lint_err_count);
+            assert_eq!(n, self.err_guars.len() + self.lint_err_guars.len());
             if n == 1 {
                 panic!("aborting due to `-Z treat-err-as-bug=1`");
             } else {
@@ -1584,6 +1589,7 @@ pub enum Level {
     ForceWarning(Option<LintExpectationId>),
 
     /// A warning about the code being compiled. Does not prevent compilation from finishing.
+    /// Will be skipped if `can_emit_warnings` is false.
     Warning,
 
     /// A message giving additional context.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index 019cc1c847e..6aedd2a5e33 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -806,7 +806,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
     rustc_attr!(
         TEST, rustc_error, Normal,
-        template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
+        template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
     ),
     rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index abf7a695fd2..a7a1c69b9be 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -3508,7 +3508,7 @@ impl<'hir> Node<'hir> {
     /// ```ignore (illustrative)
     /// ctor
     ///     .ctor_hir_id()
-    ///     .and_then(|ctor_id| tcx.hir().find_parent(ctor_id))
+    ///     .map(|ctor_id| tcx.parent_hir_node(ctor_id))
     ///     .and_then(|parent| parent.ident())
     /// ```
     pub fn ident(&self) -> Option<Ident> {
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index d438d3e7c60..1ae3ebaebbb 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -2749,14 +2749,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         arg_idx: Option<usize>,
     ) -> Option<Ty<'tcx>> {
         let tcx = self.tcx();
-        let hir = tcx.hir();
-
         let hir::Node::ImplItem(hir::ImplItem { kind: hir::ImplItemKind::Fn(..), ident, .. }) =
             tcx.hir_node(fn_hir_id)
         else {
             return None;
         };
-        let i = hir.get_parent(fn_hir_id).expect_item().expect_impl();
+        let i = tcx.parent_hir_node(fn_hir_id).expect_item().expect_impl();
 
         let trait_ref =
             self.instantiate_mono_trait_ref(i.of_trait.as_ref()?, self.ast_ty_to_ty(i.self_ty));
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 96b0cffc8a3..dc391ab5648 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -12,7 +12,7 @@ use rustc_errors::{codes::*, struct_span_code_err, DiagnosticMessage};
 use rustc_hir as hir;
 use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
 use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::symbol::{kw, sym};
 use rustc_target::spec::abi::Abi;
 
 fn equate_intrinsic_type<'tcx>(
@@ -133,7 +133,17 @@ pub fn intrinsic_operation_unsafety(tcx: TyCtxt<'_>, intrinsic_id: DefId) -> hir
 /// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`,
 /// and in `library/core/src/intrinsics.rs`.
 pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
-    let param = |n| Ty::new_param(tcx, n, Symbol::intern(&format!("P{n}")));
+    let generics = tcx.generics_of(it.owner_id);
+    let param = |n| {
+        if let Some(&ty::GenericParamDef {
+            name, kind: ty::GenericParamDefKind::Type { .. }, ..
+        }) = generics.opt_param_at(n as usize, tcx)
+        {
+            Ty::new_param(tcx, n, name)
+        } else {
+            Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
+        }
+    };
     let intrinsic_id = it.owner_id.to_def_id();
     let intrinsic_name = tcx.item_name(intrinsic_id);
     let name_str = intrinsic_name.as_str();
@@ -478,9 +488,16 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
 
 /// Type-check `extern "platform-intrinsic" { ... }` functions.
 pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
+    let generics = tcx.generics_of(it.owner_id);
     let param = |n| {
-        let name = Symbol::intern(&format!("P{n}"));
-        Ty::new_param(tcx, n, name)
+        if let Some(&ty::GenericParamDef {
+            name, kind: ty::GenericParamDefKind::Type { .. }, ..
+        }) = generics.opt_param_at(n as usize, tcx)
+        {
+            Ty::new_param(tcx, n, name)
+        } else {
+            Ty::new_error_with_message(tcx, tcx.def_span(it.owner_id), "expected param")
+        }
     };
 
     let name = it.ident.name;
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 1c0a1a69513..0f5fd7e99b7 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -16,7 +16,6 @@ use rustc_index::Idx;
 use rustc_middle::middle::region::*;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::source_map;
-use rustc_span::Span;
 
 use super::errs::{maybe_expr_static_mut, maybe_stmt_static_mut};
 
@@ -72,11 +71,7 @@ struct RegionResolutionVisitor<'tcx> {
 }
 
 /// Records the lifetime of a local variable as `cx.var_parent`
-fn record_var_lifetime(
-    visitor: &mut RegionResolutionVisitor<'_>,
-    var_id: hir::ItemLocalId,
-    _sp: Span,
-) {
+fn record_var_lifetime(visitor: &mut RegionResolutionVisitor<'_>, var_id: hir::ItemLocalId) {
     match visitor.cx.var_parent {
         None => {
             // this can happen in extern fn declarations like
@@ -210,7 +205,7 @@ fn resolve_pat<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, pat: &'tcx hir
 
     // If this is a binding then record the lifetime of that binding.
     if let PatKind::Binding(..) = pat.kind {
-        record_var_lifetime(visitor, pat.hir_id.local_id, pat.span);
+        record_var_lifetime(visitor, pat.hir_id.local_id);
     }
 
     debug!("resolve_pat - pre-increment {} pat = {:?}", visitor.expr_and_pat_count, pat);
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 646a84b043c..1bdfa452360 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -118,9 +118,9 @@ where
             return Err(err);
         } else {
             // HACK(oli-obk): tests/ui/specialization/min_specialization/specialize_on_type_error.rs
-            // causes an error (span_delayed_bug) during normalization, without reporting an error,
-            // so we need to act as if no error happened, in order to let our callers continue and
-            // report an error later in check_impl_items_against_trait.
+            // causes an delayed bug during normalization, without reporting an error, so we need
+            // to act as if no error happened, in order to let our callers continue and report an
+            // error later in check_impl_items_against_trait.
             return Ok(());
         }
     }
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 5a387844593..fc911ecdad2 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -25,9 +25,13 @@ use rustc_trait_selection::traits::ObligationCtxt;
 use rustc_trait_selection::traits::{self, ObligationCause};
 use std::collections::BTreeMap;
 
-pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuaranteed> {
+pub fn check_trait(
+    tcx: TyCtxt<'_>,
+    trait_def_id: DefId,
+    impl_def_id: LocalDefId,
+) -> Result<(), ErrorGuaranteed> {
     let lang_items = tcx.lang_items();
-    let checker = Checker { tcx, trait_def_id };
+    let checker = Checker { tcx, trait_def_id, impl_def_id };
     let mut res = checker.check(lang_items.drop_trait(), visit_implementation_of_drop);
     res = res.and(checker.check(lang_items.copy_trait(), visit_implementation_of_copy));
     res = res.and(
@@ -45,20 +49,16 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) -> Result<(), ErrorGuar
 struct Checker<'tcx> {
     tcx: TyCtxt<'tcx>,
     trait_def_id: DefId,
+    impl_def_id: LocalDefId,
 }
 
 impl<'tcx> Checker<'tcx> {
-    fn check<F>(&self, trait_def_id: Option<DefId>, mut f: F) -> Result<(), ErrorGuaranteed>
-    where
-        F: FnMut(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
-    {
-        let mut res = Ok(());
-        if Some(self.trait_def_id) == trait_def_id {
-            for &impl_def_id in self.tcx.hir().trait_impls(self.trait_def_id) {
-                res = res.and(f(self.tcx, impl_def_id));
-            }
-        }
-        res
+    fn check(
+        &self,
+        trait_def_id: Option<DefId>,
+        f: impl FnOnce(TyCtxt<'tcx>, LocalDefId) -> Result<(), ErrorGuaranteed>,
+    ) -> Result<(), ErrorGuaranteed> {
+        if Some(self.trait_def_id) == trait_def_id { f(self.tcx, self.impl_def_id) } else { Ok(()) }
     }
 }
 
@@ -92,10 +92,10 @@ fn visit_implementation_of_copy(
 
     debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
 
-    let span = match tcx.hir().expect_item(impl_did).expect_impl() {
-        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
-        hir::Impl { self_ty, .. } => self_ty.span,
-    };
+    if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
+        return Ok(());
+    }
+    let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
 
     let cause = traits::ObligationCause::misc(span, impl_did);
     match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
@@ -121,10 +121,10 @@ fn visit_implementation_of_const_param_ty(
 
     let param_env = tcx.param_env(impl_did);
 
-    let span = match tcx.hir().expect_item(impl_did).expect_impl() {
-        hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return Ok(()),
-        impl_ => impl_.self_ty.span,
-    };
+    if let ty::ImplPolarity::Negative = tcx.impl_polarity(impl_did) {
+        return Ok(());
+    }
+    let span = tcx.hir().expect_item(impl_did).expect_impl().self_ty.span;
 
     let cause = traits::ObligationCause::misc(span, impl_did);
     match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 817dab993a3..7f59763f2a0 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -124,22 +124,25 @@ pub fn provide(providers: &mut Providers) {
 }
 
 fn coherent_trait(tcx: TyCtxt<'_>, def_id: DefId) -> Result<(), ErrorGuaranteed> {
+    // If there are no impls for the trait, then "all impls" are trivially coherent and we won't check anything
+    // anyway. Thus we bail out even before the specialization graph, avoiding the dep_graph edge.
+    let Some(impls) = tcx.all_local_trait_impls(()).get(&def_id) else { return Ok(()) };
     // Trigger building the specialization graph for the trait. This will detect and report any
     // overlap errors.
     let mut res = tcx.ensure().specialization_graph_of(def_id);
 
-    let impls = tcx.hir().trait_impls(def_id);
     for &impl_def_id in impls {
         let trait_ref = tcx.impl_trait_ref(impl_def_id).unwrap().instantiate_identity();
 
         res = res.and(check_impl(tcx, impl_def_id, trait_ref));
         res = res.and(check_object_overlap(tcx, impl_def_id, trait_ref));
 
-        res = res.and(unsafety::check_item(tcx, impl_def_id));
+        res = res.and(unsafety::check_item(tcx, impl_def_id, trait_ref));
         res = res.and(tcx.ensure().orphan_check_impl(impl_def_id));
+        res = res.and(builtin::check_trait(tcx, def_id, impl_def_id));
     }
 
-    res.and(builtin::check_trait(tcx, def_id))
+    res
 }
 
 /// Checks whether an impl overlaps with the automatic `impl Trait for dyn Trait`.
diff --git a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
index e3b5c724cde..d217d53587d 100644
--- a/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/unsafety.rs
@@ -4,94 +4,91 @@
 use rustc_errors::{codes::*, struct_span_code_err};
 use rustc_hir as hir;
 use rustc_hir::Unsafety;
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::ty::{TraitRef, TyCtxt};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::ErrorGuaranteed;
 
-pub(super) fn check_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+pub(super) fn check_item(
+    tcx: TyCtxt<'_>,
+    def_id: LocalDefId,
+    trait_ref: TraitRef<'_>,
+) -> Result<(), ErrorGuaranteed> {
     let item = tcx.hir().expect_item(def_id);
     let impl_ = item.expect_impl();
+    let trait_def = tcx.trait_def(trait_ref.def_id);
+    let unsafe_attr = impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
+    match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
+        (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
+            return Err(struct_span_code_err!(
+                tcx.dcx(),
+                tcx.def_span(def_id),
+                E0199,
+                "implementing the trait `{}` is not unsafe",
+                trait_ref.print_trait_sugared()
+            )
+            .with_span_suggestion_verbose(
+                item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
+                "remove `unsafe` from this trait implementation",
+                "",
+                rustc_errors::Applicability::MachineApplicable,
+            )
+            .emit());
+        }
 
-    if let Some(trait_ref) = tcx.impl_trait_ref(item.owner_id) {
-        let trait_ref = trait_ref.instantiate_identity();
-        let trait_def = tcx.trait_def(trait_ref.def_id);
-        let unsafe_attr =
-            impl_.generics.params.iter().find(|p| p.pure_wrt_drop).map(|_| "may_dangle");
-        match (trait_def.unsafety, unsafe_attr, impl_.unsafety, impl_.polarity) {
-            (Unsafety::Normal, None, Unsafety::Unsafe, hir::ImplPolarity::Positive) => {
-                return Err(struct_span_code_err!(
-                    tcx.dcx(),
-                    tcx.def_span(def_id),
-                    E0199,
-                    "implementing the trait `{}` is not unsafe",
-                    trait_ref.print_trait_sugared()
-                )
-                .with_span_suggestion_verbose(
-                    item.span.with_hi(item.span.lo() + rustc_span::BytePos(7)),
-                    "remove `unsafe` from this trait implementation",
-                    "",
-                    rustc_errors::Applicability::MachineApplicable,
-                )
-                .emit());
-            }
-
-            (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                return Err(struct_span_code_err!(
-                    tcx.dcx(),
-                    tcx.def_span(def_id),
-                    E0200,
-                    "the trait `{}` requires an `unsafe impl` declaration",
-                    trait_ref.print_trait_sugared()
-                )
-                .with_note(format!(
-                    "the trait `{}` enforces invariants that the compiler can't check. \
+        (Unsafety::Unsafe, _, Unsafety::Normal, hir::ImplPolarity::Positive) => {
+            return Err(struct_span_code_err!(
+                tcx.dcx(),
+                tcx.def_span(def_id),
+                E0200,
+                "the trait `{}` requires an `unsafe impl` declaration",
+                trait_ref.print_trait_sugared()
+            )
+            .with_note(format!(
+                "the trait `{}` enforces invariants that the compiler can't check. \
                     Review the trait documentation and make sure this implementation \
                     upholds those invariants before adding the `unsafe` keyword",
-                    trait_ref.print_trait_sugared()
-                ))
-                .with_span_suggestion_verbose(
-                    item.span.shrink_to_lo(),
-                    "add `unsafe` to this trait implementation",
-                    "unsafe ",
-                    rustc_errors::Applicability::MaybeIncorrect,
-                )
-                .emit());
-            }
+                trait_ref.print_trait_sugared()
+            ))
+            .with_span_suggestion_verbose(
+                item.span.shrink_to_lo(),
+                "add `unsafe` to this trait implementation",
+                "unsafe ",
+                rustc_errors::Applicability::MaybeIncorrect,
+            )
+            .emit());
+        }
 
-            (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
-                return Err(struct_span_code_err!(
-                    tcx.dcx(),
-                    tcx.def_span(def_id),
-                    E0569,
-                    "requires an `unsafe impl` declaration due to `#[{}]` attribute",
-                    attr_name
-                )
-                .with_note(format!(
-                    "the trait `{}` enforces invariants that the compiler can't check. \
+        (Unsafety::Normal, Some(attr_name), Unsafety::Normal, hir::ImplPolarity::Positive) => {
+            return Err(struct_span_code_err!(
+                tcx.dcx(),
+                tcx.def_span(def_id),
+                E0569,
+                "requires an `unsafe impl` declaration due to `#[{}]` attribute",
+                attr_name
+            )
+            .with_note(format!(
+                "the trait `{}` enforces invariants that the compiler can't check. \
                     Review the trait documentation and make sure this implementation \
                     upholds those invariants before adding the `unsafe` keyword",
-                    trait_ref.print_trait_sugared()
-                ))
-                .with_span_suggestion_verbose(
-                    item.span.shrink_to_lo(),
-                    "add `unsafe` to this trait implementation",
-                    "unsafe ",
-                    rustc_errors::Applicability::MaybeIncorrect,
-                )
-                .emit());
-            }
+                trait_ref.print_trait_sugared()
+            ))
+            .with_span_suggestion_verbose(
+                item.span.shrink_to_lo(),
+                "add `unsafe` to this trait implementation",
+                "unsafe ",
+                rustc_errors::Applicability::MaybeIncorrect,
+            )
+            .emit());
+        }
 
-            (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
-                // Reported in AST validation
-                tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
-            }
-            (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
-            | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
-            | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
-            | (Unsafety::Normal, None, Unsafety::Normal, _) => {
-                // OK
-            }
+        (_, _, Unsafety::Unsafe, hir::ImplPolarity::Negative(_)) => {
+            // Reported in AST validation
+            tcx.dcx().span_delayed_bug(item.span, "unsafe negative impl");
+            Ok(())
         }
+        (_, _, Unsafety::Normal, hir::ImplPolarity::Negative(_))
+        | (Unsafety::Unsafe, _, Unsafety::Unsafe, hir::ImplPolarity::Positive)
+        | (Unsafety::Normal, Some(_), Unsafety::Unsafe, hir::ImplPolarity::Positive)
+        | (Unsafety::Normal, None, Unsafety::Normal, _) => Ok(()),
     }
-    Ok(())
 }
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index fbcebb7c87c..f458ff01c10 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -224,11 +224,8 @@ pub(crate) fn placeholder_type_error_diag<'tcx>(
             is_fn = true;
 
             // Check if parent is const or static
-            let parent_id = tcx.hir().parent_id(hir_ty.hir_id);
-            let parent_node = tcx.hir_node(parent_id);
-
             is_const_or_static = matches!(
-                parent_node,
+                tcx.parent_hir_node(hir_ty.hir_id),
                 Node::Item(&hir::Item {
                     kind: hir::ItemKind::Const(..) | hir::ItemKind::Static(..),
                     ..
@@ -1085,7 +1082,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<ty::PolyFnSig<
 
         ImplItem(hir::ImplItem { kind: ImplItemKind::Fn(sig, _), generics, .. }) => {
             // Do not try to infer the return type for a impl method coming from a trait
-            if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.hir().get_parent(hir_id)
+            if let Item(hir::Item { kind: ItemKind::Impl(i), .. }) = tcx.parent_hir_node(hir_id)
                 && i.of_trait.is_some()
             {
                 icx.astconv().ty_of_fn(
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 4860555de20..e5e731bbe8c 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -51,7 +51,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                 // of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
                 None
             } else if tcx.features().generic_const_exprs {
-                let parent_node = tcx.hir().get_parent(hir_id);
+                let parent_node = tcx.parent_hir_node(hir_id);
                 if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
                     && constant.hir_id == hir_id
                 {
@@ -113,7 +113,7 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
                     Some(parent_def_id.to_def_id())
                 }
             } else {
-                let parent_node = tcx.hir().get_parent(hir_id);
+                let parent_node = tcx.parent_hir_node(hir_id);
                 match parent_node {
                     // HACK(eddyb) this provides the correct generics for repeat
                     // expressions' count (i.e. `N` in `[x; N]`), and explicit
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index ab9ed6ef98d..05755f98f20 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -315,8 +315,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
     // We create bi-directional Outlives predicates between the original
     // and the duplicated parameter, to ensure that they do not get out of sync.
     if let Node::Item(&Item { kind: ItemKind::OpaqueTy(..), .. }) = node {
-        let opaque_ty_id = tcx.hir().parent_id(hir_id);
-        let opaque_ty_node = tcx.hir_node(opaque_ty_id);
+        let opaque_ty_node = tcx.parent_hir_node(hir_id);
         let Node::Ty(&Ty { kind: TyKind::OpaqueDef(_, lifetimes, _), .. }) = opaque_ty_node else {
             bug!("unexpected {opaque_ty_node:?}")
         };
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index 3849c0893f4..1aa9c6929f8 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -732,7 +732,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
                     let Some(def_id) = def_id.as_local() else { continue };
                     let hir_id = self.tcx.local_def_id_to_hir_id(def_id);
                     // Ensure that the parent of the def is an item, not HRTB
-                    let parent_id = self.tcx.hir().parent_id(hir_id);
+                    let parent_id = self.tcx.parent_hir_id(hir_id);
                     if !parent_id.is_owner() {
                         struct_span_code_err!(
                             self.tcx.dcx(),
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index 20a7663f864..c0128afe2bf 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -30,7 +30,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         );
     };
 
-    let parent_node_id = tcx.hir().parent_id(hir_id);
+    let parent_node_id = tcx.parent_hir_id(hir_id);
     let parent_node = tcx.hir_node(parent_node_id);
 
     let (generics, arg_idx) = match parent_node {
@@ -79,7 +79,7 @@ fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
         }
 
         Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
-            if let Node::TraitRef(trait_ref) = tcx.hir_node(tcx.hir().parent_id(binding_id)) =>
+            if let Node::TraitRef(trait_ref) = tcx.parent_hir_node(binding_id) =>
         {
             let Some(trait_def_id) = trait_ref.trait_def_id() else {
                 return Ty::new_error_with_message(
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index 1b6a39d8162..ec8ea77b749 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -425,9 +425,7 @@ fn check_predicates<'tcx>(
 
     let mut res = Ok(());
     for (clause, span) in impl1_predicates {
-        if !impl2_predicates
-            .iter()
-            .any(|pred2| trait_predicates_eq(tcx, clause.as_predicate(), *pred2, span))
+        if !impl2_predicates.iter().any(|pred2| trait_predicates_eq(clause.as_predicate(), *pred2))
         {
             res = res.and(check_specialization_on(tcx, clause, span))
         }
@@ -459,10 +457,8 @@ fn check_predicates<'tcx>(
 ///
 /// So we make that check in this function and try to raise a helpful error message.
 fn trait_predicates_eq<'tcx>(
-    _tcx: TyCtxt<'tcx>,
     predicate1: ty::Predicate<'tcx>,
     predicate2: ty::Predicate<'tcx>,
-    _span: Span,
 ) -> bool {
     // FIXME(effects)
     predicate1 == predicate2
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 3b1ee2975fd..52ff8b2e45d 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -135,7 +135,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             // Here we check if the reference to the generic type
             // is from the 'of_trait' field of the enclosing impl
 
-            let parent = self.tcx.hir().get_parent(self.path_segment.hir_id);
+            let parent = self.tcx.parent_hir_node(self.path_segment.hir_id);
             let parent_item = self.tcx.hir_node_by_def_id(
                 self.tcx.hir().get_parent_item(self.path_segment.hir_id).def_id,
             );
@@ -770,9 +770,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
             num = num_trait_generics_except_self,
         );
 
-        if let Some(parent_node) = self.tcx.hir().opt_parent_id(self.path_segment.hir_id)
-            && let hir::Node::Expr(expr) = self.tcx.hir_node(parent_node)
-        {
+        if let hir::Node::Expr(expr) = self.tcx.parent_hir_node(self.path_segment.hir_id) {
             match &expr.kind {
                 hir::ExprKind::Path(qpath) => self
                     .suggest_moving_args_from_assoc_fn_to_trait_for_qualified_path(
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 7ea0469dedd..0311aa94cd4 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -287,7 +287,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     {
         // If this `if` expr is the parent's function return expr,
         // the cause of the type coercion is the return type, point at it. (#25228)
-        let hir_id = self.tcx.hir().parent_id(self.tcx.hir().parent_id(then_expr.hir_id));
+        let hir_id = self.tcx.parent_hir_id(self.tcx.parent_hir_id(then_expr.hir_id));
         let ret_reason = self.maybe_get_coercion_reason(hir_id, if_span);
         let cause = self.cause(if_span, ObligationCauseCode::IfExpressionWithNoElse);
         let mut error = false;
@@ -396,7 +396,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let node = self.tcx.hir_node(hir_id);
         if let hir::Node::Block(block) = node {
             // check that the body's parent is an fn
-            let parent = self.tcx.hir().get_parent(self.tcx.hir().parent_id(block.hir_id));
+            let parent = self.tcx.parent_hir_node(self.tcx.parent_hir_id(block.hir_id));
             if let (Some(expr), hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(..), .. })) =
                 (&block.expr, parent)
             {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 299ee092a80..c4271c66e1c 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -361,7 +361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let fn_decl_span = if let hir::Node::Expr(hir::Expr {
             kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
             ..
-        }) = hir.get_parent(hir_id)
+        }) = self.tcx.parent_hir_node(hir_id)
         {
             fn_decl_span
         } else if let Some((
@@ -383,11 +383,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         {
             // Actually need to unwrap one more layer of HIR to get to
             // the _real_ closure...
-            let async_closure = hir.parent_id(parent_hir_id);
             if let hir::Node::Expr(hir::Expr {
                 kind: hir::ExprKind::Closure(&hir::Closure { fn_decl_span, .. }),
                 ..
-            }) = self.tcx.hir_node(async_closure)
+            }) = self.tcx.parent_hir_node(parent_hir_id)
             {
                 fn_decl_span
             } else {
@@ -415,8 +414,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         call_expr: &'tcx hir::Expr<'tcx>,
         callee_expr: &'tcx hir::Expr<'tcx>,
     ) -> bool {
-        let hir_id = self.tcx.hir().parent_id(call_expr.hir_id);
-        let parent_node = self.tcx.hir_node(hir_id);
+        let parent_node = self.tcx.parent_hir_node(call_expr.hir_id);
         if let (
             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Array(_), .. }),
             hir::ExprKind::Tup(exp),
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 2beabc0835d..549ad44d7e3 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -186,17 +186,6 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
         let b = self.shallow_resolve(b);
         debug!("Coerce.tys({:?} => {:?})", a, b);
 
-        // Just ignore error types.
-        if let Err(guar) = (a, b).error_reported() {
-            // Best-effort try to unify these types -- we're already on the error path,
-            // so this will have the side-effect of making sure we have no ambiguities
-            // due to `[type error]` and `_` not coercing together.
-            let _ = self.commit_if_ok(|_| {
-                self.at(&self.cause, self.param_env).eq(DefineOpaqueTypes::Yes, a, b)
-            });
-            return success(vec![], Ty::new_error(self.fcx.tcx, guar), vec![]);
-        }
-
         // Coercing from `!` to any type is allowed:
         if a.is_never() {
             return success(simple(Adjust::NeverToAny)(b), b, vec![]);
@@ -1605,7 +1594,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
                         err.span_label(cause.span, "return type is not `()`");
                     }
                     ObligationCauseCode::BlockTailExpression(blk_id, ..) => {
-                        let parent_id = fcx.tcx.hir().parent_id(blk_id);
+                        let parent_id = fcx.tcx.parent_hir_id(blk_id);
                         err = self.report_return_mismatched_types(
                             cause,
                             expected,
@@ -1796,7 +1785,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
     ) -> DiagnosticBuilder<'a> {
         let mut err = fcx.err_ctxt().report_mismatched_types(cause, expected, found, ty_err);
 
-        let parent_id = fcx.tcx.hir().parent_id(id);
+        let parent_id = fcx.tcx.parent_hir_id(id);
         let parent = fcx.tcx.hir_node(parent_id);
         if let Some(expr) = expression
             && let hir::Node::Expr(hir::Expr {
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index d8974251de0..fdb2cb69ee7 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -298,7 +298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(local_hir_id) else {
             return false;
         };
-        let (init_ty_hir_id, init) = match hir.get_parent(pat.hir_id) {
+        let (init_ty_hir_id, init) = match self.tcx.parent_hir_node(pat.hir_id) {
             hir::Node::Local(hir::Local { ty: Some(ty), init, .. }) => (ty.hir_id, *init),
             hir::Node::Local(hir::Local { init: Some(init), .. }) => (init.hir_id, Some(*init)),
             _ => return false,
@@ -445,7 +445,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 continue;
             }
 
-            if let hir::Node::Expr(parent_expr) = hir.get_parent(binding.hir_id)
+            if let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(binding.hir_id)
                 && let hir::ExprKind::MethodCall(segment, rcvr, args, _) = parent_expr.kind
                 && rcvr.hir_id == binding.hir_id
             {
@@ -557,7 +557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
             return;
         };
-        let mut parent_id = self.tcx.hir().parent_id(expr.hir_id);
+        let mut parent_id = self.tcx.parent_hir_id(expr.hir_id);
         let mut parent;
         'outer: loop {
             // Climb the HIR tree to see if the current `Expr` is part of a `break;` statement.
@@ -568,7 +568,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 break;
             };
             parent = p;
-            parent_id = self.tcx.hir().parent_id(parent_id);
+            parent_id = self.tcx.parent_hir_id(parent_id);
             let hir::ExprKind::Break(destination, _) = parent.kind else {
                 continue;
             };
@@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Climb the HIR tree to find the (desugared) `loop` this `break` corresponds to.
                 let parent = match self.tcx.hir_node(parent_id) {
                     hir::Node::Expr(&ref parent) => {
-                        parent_id = self.tcx.hir().parent_id(parent.hir_id);
+                        parent_id = self.tcx.parent_hir_id(parent.hir_id);
                         parent
                     }
                     hir::Node::Stmt(hir::Stmt {
@@ -586,11 +586,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         kind: hir::StmtKind::Semi(&ref parent) | hir::StmtKind::Expr(&ref parent),
                         ..
                     }) => {
-                        parent_id = self.tcx.hir().parent_id(*hir_id);
+                        parent_id = self.tcx.parent_hir_id(*hir_id);
                         parent
                     }
                     hir::Node::Block(_) => {
-                        parent_id = self.tcx.hir().parent_id(parent_id);
+                        parent_id = self.tcx.parent_hir_id(parent_id);
                         parent
                     }
                     _ => break,
@@ -677,8 +677,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         error: Option<TypeError<'tcx>>,
     ) {
-        let parent = self.tcx.hir().parent_id(expr.hir_id);
-        match (self.tcx.hir_node(parent), error) {
+        match (self.tcx.parent_hir_node(expr.hir_id), error) {
             (hir::Node::Local(hir::Local { ty: Some(ty), init: Some(init), .. }), _)
                 if init.hir_id == expr.hir_id =>
             {
@@ -724,16 +723,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let hir::Node::Pat(pat) = self.tcx.hir_node(*hir_id) {
                             primary_span = pat.span;
                             secondary_span = pat.span;
-                            match self.tcx.hir().find_parent(pat.hir_id) {
-                                Some(hir::Node::Local(hir::Local { ty: Some(ty), .. })) => {
+                            match self.tcx.parent_hir_node(pat.hir_id) {
+                                hir::Node::Local(hir::Local { ty: Some(ty), .. }) => {
                                     primary_span = ty.span;
                                     post_message = " type";
                                 }
-                                Some(hir::Node::Local(hir::Local { init: Some(init), .. })) => {
+                                hir::Node::Local(hir::Local { init: Some(init), .. }) => {
                                     primary_span = init.span;
                                     post_message = " value";
                                 }
-                                Some(hir::Node::Param(hir::Param { ty_span, .. })) => {
+                                hir::Node::Param(hir::Param { ty_span, .. }) => {
                                     primary_span = *ty_span;
                                     post_message = " parameter type";
                                 }
@@ -787,12 +786,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         error: Option<TypeError<'tcx>>,
     ) {
-        let parent = self.tcx.hir().parent_id(expr.hir_id);
         let Some(TypeError::Sorts(ExpectedFound { expected, .. })) = error else {
             return;
         };
         let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(lhs, rhs, _), .. }) =
-            self.tcx.hir_node(parent)
+            self.tcx.parent_hir_node(expr.hir_id)
         else {
             return;
         };
@@ -1017,7 +1015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         )) = expr.kind
         {
             let bind = self.tcx.hir_node(*bind_hir_id);
-            let parent = self.tcx.hir_node(self.tcx.hir().parent_id(*bind_hir_id));
+            let parent = self.tcx.parent_hir_node(*bind_hir_id);
             if let hir::Node::Pat(hir::Pat {
                 kind: hir::PatKind::Binding(_, _hir_id, _, _), ..
             }) = bind
@@ -1088,7 +1086,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         expr: &hir::Expr<'_>,
         checked_ty: Ty<'tcx>,
     ) {
-        let Some(hir::Node::Expr(parent_expr)) = self.tcx.hir().find_parent(expr.hir_id) else {
+        let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr.hir_id) else {
             return;
         };
         enum CallableKind {
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 292b85eb97f..124a94c498c 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -346,7 +346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ExprKind::DropTemps(e) => self.check_expr_with_expectation(e, expected),
             ExprKind::Array(args) => self.check_expr_array(args, expected, expr),
-            ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected, expr),
+            ExprKind::ConstBlock(ref block) => self.check_expr_const_block(block, expected),
             ExprKind::Repeat(element, ref count) => {
                 self.check_expr_repeat(element, count, expected, expr)
             }
@@ -1016,7 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         original_expr_id: HirId,
         then: impl FnOnce(&hir::Expr<'_>),
     ) {
-        let mut parent = self.tcx.hir().parent_id(original_expr_id);
+        let mut parent = self.tcx.parent_hir_id(original_expr_id);
         loop {
             let node = self.tcx.hir_node(parent);
             match node {
@@ -1038,15 +1038,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ),
                     ..
                 }) => {
-                    // Check if our original expression is a child of the condition of a while loop
-                    let expr_is_ancestor = std::iter::successors(Some(original_expr_id), |id| {
-                        self.tcx.hir().opt_parent_id(*id)
-                    })
-                    .take_while(|id| *id != parent)
-                    .any(|id| id == expr.hir_id);
-                    // if it is, then we have a situation like `while Some(0) = value.get(0) {`,
+                    // Check if our original expression is a child of the condition of a while loop.
+                    // If it is, then we have a situation like `while Some(0) = value.get(0) {`,
                     // where `while let` was more likely intended.
-                    if expr_is_ancestor {
+                    if self.tcx.hir().parent_id_iter(original_expr_id).any(|id| id == expr.hir_id) {
                         then(expr);
                     }
                     break;
@@ -1056,7 +1051,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 | hir::Node::TraitItem(_)
                 | hir::Node::Crate(_) => break,
                 _ => {
-                    parent = self.tcx.hir().parent_id(parent);
+                    parent = self.tcx.parent_hir_id(parent);
                 }
             }
         }
@@ -1199,9 +1194,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 && !matches!(lhs.kind, hir::ExprKind::Lit(_))
             {
                 // Do not suggest `if let x = y` as `==` is way more likely to be the intention.
-                let hir = self.tcx.hir();
                 if let hir::Node::Expr(hir::Expr { kind: ExprKind::If { .. }, .. }) =
-                    hir.get_parent(hir.parent_id(expr.hir_id))
+                    self.tcx.parent_hir_node(expr.hir_id)
                 {
                     err.span_suggestion_verbose(
                         expr.span.shrink_to_lo(),
@@ -1493,7 +1487,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         &self,
         block: &'tcx hir::ConstBlock,
         expected: Expectation<'tcx>,
-        _expr: &'tcx hir::Expr<'tcx>,
     ) -> Ty<'tcx> {
         let body = self.tcx.hir().body(block.body);
 
@@ -2645,7 +2638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         err.span_label(field.span, "method, not a field");
         let expr_is_call =
             if let hir::Node::Expr(hir::Expr { kind: ExprKind::Call(callee, _args), .. }) =
-                self.tcx.hir().get_parent(expr.hir_id)
+                self.tcx.parent_hir_node(expr.hir_id)
             {
                 expr.hir_id == callee.hir_id
             } else {
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 3ecf6c5e428..04fb7bcf4f3 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -142,7 +142,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
             let param_ty = return_if_err!(self.mc.pat_ty_adjusted(param.pat));
             debug!("consume_body: param_ty = {:?}", param_ty);
 
-            let param_place = self.mc.cat_rvalue(param.hir_id, param.pat.span, param_ty);
+            let param_place = self.mc.cat_rvalue(param.hir_id, param_ty);
 
             self.walk_irrefutable_pat(&param_place, param.pat);
         }
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 36c3eef82fc..7eb421ca8f5 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -764,7 +764,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let code = match lang_item {
             hir::LangItem::IntoFutureIntoFuture => {
-                if let hir::Node::Expr(into_future_call) = self.tcx.hir().get_parent(hir_id)
+                if let hir::Node::Expr(into_future_call) = self.tcx.parent_hir_node(hir_id)
                     && let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind
                 {
                     Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id))
@@ -956,12 +956,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 ..
             }) => Some((hir::HirId::make_owner(owner_id.def_id), &sig.decl, ident, false)),
             Node::Expr(&hir::Expr { hir_id, kind: hir::ExprKind::Closure(..), .. })
-                if let Some(Node::Item(&hir::Item {
+                if let Node::Item(&hir::Item {
                     ident,
                     kind: hir::ItemKind::Fn(ref sig, ..),
                     owner_id,
                     ..
-                })) = self.tcx.hir().find_parent(hir_id) =>
+                }) = self.tcx.parent_hir_node(hir_id) =>
             {
                 Some((
                     hir::HirId::make_owner(owner_id.def_id),
@@ -1574,7 +1574,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     pub(in super::super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool {
         let mut contained_in_place = false;
 
-        while let hir::Node::Expr(parent_expr) = self.tcx.hir().get_parent(expr_id) {
+        while let hir::Node::Expr(parent_expr) = self.tcx.parent_hir_node(expr_id) {
             match &parent_expr.kind {
                 hir::ExprKind::Assign(lhs, ..) | hir::ExprKind::AssignOp(_, lhs, ..) => {
                     if lhs.hir_id == expr_id {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index 1ad79cb78c4..6aa986b0df4 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -93,7 +93,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.find_ambiguous_parameter_in(def_id, error.root_obligation.predicate);
         }
 
-        let hir = self.tcx.hir();
         let (expr, qpath) = match self.tcx.hir_node(hir_id) {
             hir::Node::Expr(expr) => {
                 if self.closure_span_overlaps_error(error, expr.span) {
@@ -122,7 +121,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 hir_id: call_hir_id,
                 span: call_span,
                 ..
-            }) = hir.get_parent(hir_id)
+            }) = self.tcx.parent_hir_node(hir_id)
                 && callee.hir_id == hir_id
             {
                 if self.closure_span_overlaps_error(error, *call_span) {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index ed0bdb9bdaa..193c9a4b908 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -681,9 +681,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // Check if the parent expression is a call to Pin::new. If it
                 // is and we were expecting a Box, ergo Pin<Box<expected>>, we
                 // can suggest Box::pin.
-                let parent = self.tcx.hir().parent_id(expr.hir_id);
                 let Node::Expr(Expr { kind: ExprKind::Call(fn_name, _), .. }) =
-                    self.tcx.hir_node(parent)
+                    self.tcx.parent_hir_node(expr.hir_id)
                 else {
                     return false;
                 };
@@ -1687,7 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     return expr;
                 };
 
-                match self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id)) {
+                match self.tcx.parent_hir_node(*hir_id) {
                     // foo.clone()
                     hir::Node::Local(hir::Local { init: Some(init), .. }) => {
                         self.note_type_is_not_clone_inner_expr(init)
@@ -1699,7 +1698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         ..
                     }) => {
                         let hir::Node::Local(hir::Local { init: Some(init), .. }) =
-                            self.tcx.hir_node(self.tcx.hir().parent_id(*pat_hir_id))
+                            self.tcx.parent_hir_node(*pat_hir_id)
                         else {
                             return expr;
                         };
@@ -1733,7 +1732,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         call_expr_path
                     && let hir::Node::Pat(hir::Pat { hir_id, .. }) = self.tcx.hir_node(*binding)
                     && let hir::Node::Local(hir::Local { init: Some(init), .. }) =
-                        self.tcx.hir_node(self.tcx.hir().parent_id(*hir_id))
+                        self.tcx.parent_hir_node(*hir_id)
                     && let Expr {
                         kind: hir::ExprKind::Closure(hir::Closure { body: body_id, .. }),
                         ..
@@ -1899,8 +1898,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     ) -> bool {
         let map = self.tcx.hir();
         let returned = matches!(
-            map.find_parent(expr.hir_id),
-            Some(hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. }))
+            self.tcx.parent_hir_node(expr.hir_id),
+            hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Ret(_), .. })
         ) || map.get_return_block(expr.hir_id).is_some();
         if returned
             && let ty::Adt(e, args_e) = expected.kind()
@@ -1972,7 +1971,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
                 // Unroll desugaring, to make sure this works for `for` loops etc.
                 loop {
-                    parent = self.tcx.hir().parent_id(id);
+                    parent = self.tcx.parent_hir_id(id);
                     let parent_span = self.tcx.hir().span(parent);
                     if parent_span.find_ancestor_inside(expr.span).is_some() {
                         // The parent node is part of the same span, so is the result of the
@@ -2211,24 +2210,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return None;
         };
 
-        let local_parent = self.tcx.hir().parent_id(local_id);
-        let Node::Param(hir::Param { hir_id: param_hir_id, .. }) = self.tcx.hir_node(local_parent)
+        let Node::Param(hir::Param { hir_id: param_hir_id, .. }) =
+            self.tcx.parent_hir_node(local_id)
         else {
             return None;
         };
 
-        let param_parent = self.tcx.hir().parent_id(*param_hir_id);
         let Node::Expr(hir::Expr {
             hir_id: expr_hir_id,
             kind: hir::ExprKind::Closure(hir::Closure { fn_decl: closure_fn_decl, .. }),
             ..
-        }) = self.tcx.hir_node(param_parent)
+        }) = self.tcx.parent_hir_node(*param_hir_id)
         else {
             return None;
         };
 
-        let expr_parent = self.tcx.hir().parent_id(*expr_hir_id);
-        let hir = self.tcx.hir_node(expr_parent);
+        let hir = self.tcx.parent_hir_node(*expr_hir_id);
         let closure_params_len = closure_fn_decl.inputs.len();
         let (
             Node::Expr(hir::Expr {
@@ -2409,10 +2406,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         None => String::new(),
                     };
 
-                    if let Some(hir::Node::Expr(hir::Expr {
-                        kind: hir::ExprKind::Assign(..),
-                        ..
-                    })) = self.tcx.hir().find_parent(expr.hir_id)
+                    if let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Assign(..), .. }) =
+                        self.tcx.parent_hir_node(expr.hir_id)
                     {
                         if mutability.is_mut() {
                             // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
@@ -2443,10 +2438,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     };
 
                     // Suggest dereferencing the lhs for expressions such as `&T <= T`
-                    if let Some(hir::Node::Expr(hir::Expr {
+                    if let hir::Node::Expr(hir::Expr {
                         kind: hir::ExprKind::Binary(_, lhs, ..),
                         ..
-                    })) = self.tcx.hir().find_parent(expr.hir_id)
+                    }) = self.tcx.parent_hir_node(expr.hir_id)
                         && let &ty::Ref(..) = self.check_expr(lhs).kind()
                     {
                         let (sugg, verbose) = make_sugg(lhs, lhs.span, "*");
@@ -2602,7 +2597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         || (checked_ty.is_box() && steps == 1)
                         // We can always deref a binop that takes its arguments by ref.
                         || matches!(
-                            self.tcx.hir().get_parent(expr.hir_id),
+                            self.tcx.parent_hir_node(expr.hir_id),
                             hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
                                 if !op.node.is_by_value()
                         )
@@ -2664,10 +2659,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     /// Returns whether the given expression is an `else if`.
     fn is_else_if_block(&self, expr: &hir::Expr<'_>) -> bool {
         if let hir::ExprKind::If(..) = expr.kind {
-            let parent_id = self.tcx.hir().parent_id(expr.hir_id);
             if let Node::Expr(hir::Expr {
                 kind: hir::ExprKind::If(_, _, Some(else_expr)), ..
-            }) = self.tcx.hir_node(parent_id)
+            }) = self.tcx.parent_hir_node(expr.hir_id)
             {
                 return else_expr.hir_id == expr.hir_id;
             }
@@ -2704,7 +2698,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let mut sugg = vec![];
 
-        if let Some(hir::Node::ExprField(field)) = self.tcx.hir().find_parent(expr.hir_id) {
+        if let hir::Node::ExprField(field) = self.tcx.parent_hir_node(expr.hir_id) {
             // `expr` is a literal field for a struct, only suggest if appropriate
             if field.is_shorthand {
                 // This is a field literal
@@ -3056,8 +3050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         else {
             return;
         };
-        let parent = self.tcx.hir().parent_id(expr.hir_id);
-        if let hir::Node::ExprField(_) = self.tcx.hir_node(parent) {
+        if let hir::Node::ExprField(_) = self.tcx.parent_hir_node(expr.hir_id) {
             // Ignore `Foo { field: a..Default::default() }`
             return;
         }
@@ -3139,8 +3132,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
-            self.tcx.hir().find_parent(pat.hir_id)
+        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+            self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
         };
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 06a14613567..c1af4b5983e 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -220,7 +220,7 @@ fn typeck_with_fallback<'tcx>(
                 span,
             }))
         } else if let Node::AnonConst(_) = node {
-            match tcx.hir_node(tcx.hir().parent_id(id)) {
+            match tcx.parent_hir_node(id) {
                 Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. })
                     if anon_const.hir_id == id =>
                 {
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index f9297550c57..fefaf996725 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -273,7 +273,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                         deref.region,
                         ty::TypeAndMut { ty: target, mutbl: deref.mutbl },
                     );
-                    self.cat_rvalue(expr.hir_id, expr.span, ref_ty)
+                    self.cat_rvalue(expr.hir_id, ref_ty)
                 } else {
                     previous()?
                 };
@@ -285,7 +285,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | adjustment::Adjust::Borrow(_)
             | adjustment::Adjust::DynStar => {
                 // Result is an rvalue.
-                Ok(self.cat_rvalue(expr.hir_id, expr.span, target))
+                Ok(self.cat_rvalue(expr.hir_id, target))
             }
         }
     }
@@ -374,7 +374,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
             | hir::ExprKind::Repeat(..)
             | hir::ExprKind::InlineAsm(..)
             | hir::ExprKind::OffsetOf(..)
-            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
+            | hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr_ty)),
         }
     }
 
@@ -396,7 +396,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
                 | DefKind::AssocFn,
                 _,
             )
-            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, span, expr_ty)),
+            | Res::SelfCtor(..) => Ok(self.cat_rvalue(hir_id, expr_ty)),
 
             Res::Def(DefKind::Static(_), _) => {
                 Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::StaticItem, Vec::new()))
@@ -433,13 +433,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
     }
 
     #[instrument(level = "debug", skip(self), ret)]
-    pub(crate) fn cat_rvalue(
-        &self,
-        hir_id: hir::HirId,
-        // FIXME: remove
-        _span: Span,
-        expr_ty: Ty<'tcx>,
-    ) -> PlaceWithHirId<'tcx> {
+    pub(crate) fn cat_rvalue(&self, hir_id: hir::HirId, expr_ty: Ty<'tcx>) -> PlaceWithHirId<'tcx> {
         PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Rvalue, Vec::new())
     }
 
@@ -487,7 +481,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
         };
         let ref_ty = Ty::new_ref(self.tcx(), region, ty::TypeAndMut { ty: place_ty, mutbl });
 
-        let base = self.cat_rvalue(expr.hir_id, expr.span, ref_ty);
+        let base = self.cat_rvalue(expr.hir_id, ref_ty);
         self.cat_deref(expr, base)
     }
 
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 81b82393515..7fc51e36a2b 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -128,7 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let sugg_span = if let SelfSource::MethodCall(expr) = source {
             // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing.
-            self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id)).span
+            self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id)).span
         } else {
             span
         };
@@ -231,9 +231,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = kind
                             && let hir::def::Res::Local(hir_id) = path.res
                             && let hir::Node::Pat(b) = self.tcx.hir_node(hir_id)
-                            && let Some(hir::Node::Param(p)) = self.tcx.hir().find_parent(b.hir_id)
-                            && let Some(node) = self.tcx.hir().find_parent(p.hir_id)
-                            && let Some(decl) = node.fn_decl()
+                            && let hir::Node::Param(p) = self.tcx.parent_hir_node(b.hir_id)
+                            && let Some(decl) = self.tcx.parent_hir_node(p.hir_id).fn_decl()
                             && let Some(ty) = decl.inputs.iter().find(|ty| ty.span == p.ty_span)
                             && let hir::TyKind::Ref(_, mut_ty) = &ty.kind
                             && let hir::Mutability::Not = mut_ty.mutbl
@@ -471,7 +470,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let SelfSource::MethodCall(rcvr_expr) = source {
             self.suggest_fn_call(&mut err, rcvr_expr, rcvr_ty, |output_ty| {
                 let call_expr =
-                    self.tcx.hir().expect_expr(self.tcx.hir().parent_id(rcvr_expr.hir_id));
+                    self.tcx.hir().expect_expr(self.tcx.parent_hir_id(rcvr_expr.hir_id));
                 let probe = self.lookup_probe_for_diagnostic(
                     item_name,
                     output_ty,
@@ -1020,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         rcvr_ty,
                         &item_segment,
                         span,
-                        tcx.hir().get_parent(rcvr_expr.hir_id).expect_expr(),
+                        tcx.parent_hir_node(rcvr_expr.hir_id).expect_expr(),
                         rcvr_expr,
                     ) {
                         err.span_note(
@@ -1254,7 +1253,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let msg = "remove this method call";
             let mut fallback_span = true;
             if let SelfSource::MethodCall(expr) = source {
-                let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
+                let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
                 if let Some(span) = call_expr.span.trim_start(expr.span) {
                     err.span_suggestion(span, msg, "", Applicability::MachineApplicable);
                     fallback_span = false;
@@ -1753,7 +1752,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         Applicability::MachineApplicable,
                     );
                 } else {
-                    let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
+                    let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
 
                     if let Some(span) = call_expr.span.trim_start(item_name.span) {
                         err.span_suggestion(
@@ -1937,7 +1936,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let span = tcx.hir().span(hir_id);
                         let filename = tcx.sess.source_map().span_to_filename(span);
 
-                        let parent_node = self.tcx.hir().get_parent(hir_id);
+                        let parent_node = self.tcx.parent_hir_node(hir_id);
                         let msg = format!(
                             "you must specify a type for this binding, like `{concrete_type}`",
                         );
@@ -2016,8 +2015,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let mut visitor = LetVisitor { result: None, ident_name: seg1.ident.name };
         visitor.visit_body(body);
 
-        let parent = self.tcx.hir().parent_id(seg1.hir_id);
-        if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
+        if let Node::Expr(call_expr) = self.tcx.parent_hir_node(seg1.hir_id)
             && let Some(expr) = visitor.result
             && let Some(self_ty) = self.node_ty_opt(expr.hir_id)
         {
@@ -2056,7 +2054,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             for (fields, args) in
                 self.get_field_candidates_considering_privacy(span, actual, mod_id, expr.hir_id)
             {
-                let call_expr = self.tcx.hir().expect_expr(self.tcx.hir().parent_id(expr.hir_id));
+                let call_expr = self.tcx.hir().expect_expr(self.tcx.parent_hir_id(expr.hir_id));
 
                 let lang_items = self.tcx.lang_items();
                 let never_mention_traits = [
@@ -2133,7 +2131,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let SelfSource::MethodCall(expr) = source else {
             return;
         };
-        let call_expr = tcx.hir().expect_expr(tcx.hir().parent_id(expr.hir_id));
+        let call_expr = tcx.hir().expect_expr(tcx.parent_hir_id(expr.hir_id));
 
         let ty::Adt(kind, args) = actual.kind() else {
             return;
@@ -3250,8 +3248,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             return false;
         }
 
-        let parent = self.tcx.hir().parent_id(expr.hir_id);
-        if let Node::Expr(call_expr) = self.tcx.hir_node(parent)
+        if let Node::Expr(call_expr) = self.tcx.parent_hir_node(expr.hir_id)
             && let hir::ExprKind::MethodCall(
                 hir::PathSegment { ident: method_name, .. },
                 self_expr,
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index 9ce61898561..9a8444e6a2b 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -383,7 +383,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     }
                 };
                 if self.check_for_missing_semi(expr, &mut err)
-                    && let hir::Node::Expr(expr) = self.tcx.hir().get_parent(expr.hir_id)
+                    && let hir::Node::Expr(expr) = self.tcx.parent_hir_node(expr.hir_id)
                     && let hir::ExprKind::Assign(..) = expr.kind
                 {
                     // We defer to the later error produced by `check_lhs_assignable`.
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index fcf4b59e93f..67aa9218585 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -720,8 +720,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         if let PatKind::Ref(inner, mutbl) = pat.kind
             && let PatKind::Binding(_, _, binding, ..) = inner.kind
         {
-            let binding_parent_id = tcx.hir().parent_id(pat.hir_id);
-            let binding_parent = tcx.hir_node(binding_parent_id);
+            let binding_parent = tcx.parent_hir_node(pat.hir_id);
             debug!(?inner, ?pat, ?binding_parent);
 
             let mutability = match mutbl {
@@ -989,7 +988,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         res.descr(),
                     ),
                 );
-                match self.tcx.hir().get_parent(pat.hir_id) {
+                match self.tcx.parent_hir_node(pat.hir_id) {
                     hir::Node::PatField(..) => {
                         e.span_suggestion_verbose(
                             ident.span.shrink_to_hi(),
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index 156a4f71017..99882a42abc 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -191,7 +191,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
                 //
                 // rust-lang/rust#57464: `impl Trait` can leak local
                 // scopes (in manner violating typeck). Therefore, use
-                // `span_delayed_bug` to allow type error over an ICE.
+                // `delayed_bug` to allow type error over an ICE.
                 canonicalizer
                     .tcx
                     .dcx()
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index dd9ed80ca72..4d2d19b51e2 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -862,8 +862,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ) {
                         err.subdiagnostic(subdiag);
                     }
-                    if let Some(hir::Node::Expr(m)) = self.tcx.hir().find_parent(scrut_hir_id)
-                        && let Some(hir::Node::Stmt(stmt)) = self.tcx.hir().find_parent(m.hir_id)
+                    if let hir::Node::Expr(m) = self.tcx.parent_hir_node(scrut_hir_id)
+                        && let hir::Node::Stmt(stmt) = self.tcx.parent_hir_node(m.hir_id)
                         && let hir::StmtKind::Expr(_) = stmt.kind
                     {
                         err.span_suggestion_verbose(
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index f884ca83073..3c42f13141d 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -106,7 +106,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                                 }
                                 p_def_id.as_local().and_then(|id| {
                                     let local_id = tcx.local_def_id_to_hir_id(id);
-                                    let generics = tcx.hir().find_parent(local_id)?.generics()?;
+                                    let generics = tcx.parent_hir_node(local_id).generics()?;
                                     Some((id, generics))
                                 })
                             });
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index bbe07b8ed72..248e1c0fcc8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -735,30 +735,29 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             };
             local.pat.walk(&mut find_compatible_candidates);
         }
-        match hir.find_parent(blk.hir_id) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) {
-                Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+        match self.tcx.parent_hir_node(blk.hir_id) {
+            hir::Node::Expr(hir::Expr { hir_id, .. }) => match self.tcx.parent_hir_node(*hir_id) {
+                hir::Node::Arm(hir::Arm { pat, .. }) => {
                     pat.walk(&mut find_compatible_candidates);
                 }
-                Some(
-                    hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                    | hir::Node::ImplItem(hir::ImplItem {
-                        kind: hir::ImplItemKind::Fn(_, body), ..
-                    })
-                    | hir::Node::TraitItem(hir::TraitItem {
-                        kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                        ..
-                    })
-                    | hir::Node::Expr(hir::Expr {
-                        kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                        ..
-                    }),
-                ) => {
+
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+                | hir::Node::ImplItem(hir::ImplItem {
+                    kind: hir::ImplItemKind::Fn(_, body), ..
+                })
+                | hir::Node::TraitItem(hir::TraitItem {
+                    kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+                    ..
+                })
+                | hir::Node::Expr(hir::Expr {
+                    kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
+                    ..
+                }) => {
                     for param in hir.body(*body).params {
                         param.pat.walk(&mut find_compatible_candidates);
                     }
                 }
-                Some(hir::Node::Expr(hir::Expr {
+                hir::Node::Expr(hir::Expr {
                     kind:
                         hir::ExprKind::If(
                             hir::Expr { kind: hir::ExprKind::Let(let_), .. },
@@ -766,7 +765,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             _,
                         ),
                     ..
-                })) if then_block.hir_id == *hir_id => {
+                }) if then_block.hir_id == *hir_id => {
                     let_.pat.walk(&mut find_compatible_candidates);
                 }
                 _ => {}
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 7401654aea8..0253f5a2df2 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -65,10 +65,10 @@ pub fn report_object_safety_error<'tcx>(
         && let hir::TyKind::TraitObject([trait_ref, ..], ..) = ty.kind
     {
         let mut hir_id = hir_id;
-        while let hir::Node::Ty(ty) = tcx.hir().get_parent(hir_id) {
+        while let hir::Node::Ty(ty) = tcx.parent_hir_node(hir_id) {
             hir_id = ty.hir_id;
         }
-        if tcx.hir().get_parent(hir_id).fn_sig().is_some() {
+        if tcx.parent_hir_node(hir_id).fn_sig().is_some() {
             // Do not suggest `impl Trait` when dealing with things like super-traits.
             err.span_suggestion_verbose(
                 ty.span.until(trait_ref.span),
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index e66ea6f2ca9..2a4eefb7f77 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -194,16 +194,16 @@ impl<'tcx> Queries<'tcx> {
         let Some((def_id, _)) = tcx.entry_fn(()) else { return };
         for attr in tcx.get_attrs(def_id, sym::rustc_error) {
             match attr.meta_item_list() {
-                // Check if there is a `#[rustc_error(span_delayed_bug_from_inside_query)]`.
+                // Check if there is a `#[rustc_error(delayed_bug_from_inside_query)]`.
                 Some(list)
                     if list.iter().any(|list_item| {
                         matches!(
                             list_item.ident().map(|i| i.name),
-                            Some(sym::span_delayed_bug_from_inside_query)
+                            Some(sym::delayed_bug_from_inside_query)
                         )
                     }) =>
                 {
-                    tcx.ensure().trigger_span_delayed_bug(def_id);
+                    tcx.ensure().trigger_delayed_bug(def_id);
                 }
 
                 // Bare `#[rustc_error]`.
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index f10d3d4a68a..6ee1d1ca924 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -1416,8 +1416,7 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub {
     }
 
     fn check_field_def(&mut self, cx: &LateContext<'_>, field: &hir::FieldDef<'_>) {
-        let map = cx.tcx.hir();
-        if matches!(map.get_parent(field.hir_id), Node::Variant(_)) {
+        if matches!(cx.tcx.parent_hir_node(field.hir_id), Node::Variant(_)) {
             return;
         }
         self.perform_lint(cx, "field", field.def_id, field.vis_span, false);
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 1c480ec8f53..30f05444d21 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -933,7 +933,7 @@ impl<'tcx> LateContext<'tcx> {
 
         while let hir::ExprKind::Path(ref qpath) = expr.kind
             && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
-                Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id),
+                Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
                 _ => None,
             }
             && let Some(init) = match parent_node {
@@ -977,7 +977,7 @@ impl<'tcx> LateContext<'tcx> {
 
         while let hir::ExprKind::Path(ref qpath) = expr.kind
             && let Some(parent_node) = match self.qpath_res(qpath, expr.hir_id) {
-                Res::Local(hir_id) => self.tcx.hir().find_parent(hir_id),
+                Res::Local(hir_id) => Some(self.tcx.parent_hir_node(hir_id)),
                 Res::Def(_, def_id) => self.tcx.hir().get_if_local(def_id),
                 _ => None,
             }
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
index 9a31aa062f0..78ac7f9b235 100644
--- a/compiler/rustc_lint/src/drop_forget_useless.rs
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -214,8 +214,7 @@ fn is_single_call_in_arm<'tcx>(
     drop_expr: &'tcx Expr<'_>,
 ) -> bool {
     if arg.can_have_side_effects() {
-        let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id);
-        if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
+        if let Node::Arm(Arm { body, .. }) = cx.tcx.parent_hir_node(drop_expr.hir_id) {
             return body.hir_id == drop_expr.hir_id;
         }
     }
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 516df14c894..596221a8455 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -144,15 +144,14 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
         match &ty.kind {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
-                    let hir = cx.tcx.hir();
-                    let span = match hir.find_parent(ty.hir_id) {
-                        Some(Node::Pat(Pat {
+                    let span = match cx.tcx.parent_hir_node(ty.hir_id) {
+                        Node::Pat(Pat {
                             kind:
                                 PatKind::Path(qpath)
                                 | PatKind::TupleStruct(qpath, ..)
                                 | PatKind::Struct(qpath, ..),
                             ..
-                        })) => {
+                        }) => {
                             if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                 && qpath_ty.hir_id == ty.hir_id
                             {
@@ -161,7 +160,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                                 None
                             }
                         }
-                        Some(Node::Expr(Expr { kind: ExprKind::Path(qpath), .. })) => {
+                        Node::Expr(Expr { kind: ExprKind::Path(qpath), .. }) => {
                             if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                 && qpath_ty.hir_id == ty.hir_id
                             {
@@ -172,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
                         }
                         // Can't unify these two branches because qpath below is `&&` and above is `&`
                         // and `A | B` paths don't play well together with adjustments, apparently.
-                        Some(Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. })) => {
+                        Node::Expr(Expr { kind: ExprKind::Struct(qpath, ..), .. }) => {
                             if let QPath::TypeRelative(qpath_ty, ..) = qpath
                                 && qpath_ty.hir_id == ty.hir_id
                             {
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 05b39829a12..4ecd87e37d3 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -427,7 +427,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase {
 
     fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
         if let PatKind::Binding(_, hid, ident, _) = p.kind {
-            if let hir::Node::PatField(field) = cx.tcx.hir().get_parent(hid) {
+            if let hir::Node::PatField(field) = cx.tcx.parent_hir_node(hid) {
                 if !field.is_shorthand {
                     // Only check if a new name has been introduced, to avoid warning
                     // on both the struct definition and this pattern.
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index 1205395b890..e4ebae2a973 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -200,8 +200,7 @@ fn lint_overflowing_range_endpoint<'tcx>(
     ty: &str,
 ) -> bool {
     // Look past casts to support cases like `0..256 as u8`
-    let (expr, lit_span) = if let Node::Expr(par_expr) =
-        cx.tcx.hir_node(cx.tcx.hir().parent_id(expr.hir_id))
+    let (expr, lit_span) = if let Node::Expr(par_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && let ExprKind::Cast(_, _) = par_expr.kind
     {
         (par_expr, expr.span)
@@ -211,9 +210,8 @@ fn lint_overflowing_range_endpoint<'tcx>(
 
     // We only want to handle exclusive (`..`) ranges,
     // which are represented as `ExprKind::Struct`.
-    let par_id = cx.tcx.hir().parent_id(expr.hir_id);
-    let Node::ExprField(field) = cx.tcx.hir_node(par_id) else { return false };
-    let Node::Expr(struct_expr) = cx.tcx.hir().get_parent(field.hir_id) else { return false };
+    let Node::ExprField(field) = cx.tcx.parent_hir_node(expr.hir_id) else { return false };
+    let Node::Expr(struct_expr) = cx.tcx.parent_hir_node(field.hir_id) else { return false };
     if !is_range_literal(struct_expr) {
         return false;
     };
@@ -496,8 +494,7 @@ fn lint_uint_literal<'tcx>(
         _ => bug!(),
     };
     if lit_val < min || lit_val > max {
-        let parent_id = cx.tcx.hir().parent_id(e.hir_id);
-        if let Node::Expr(par_e) = cx.tcx.hir_node(parent_id) {
+        if let Node::Expr(par_e) = cx.tcx.parent_hir_node(e.hir_id) {
             match par_e.kind {
                 hir::ExprKind::Cast(..) => {
                     if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() {
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 7cd2f58779f..988388edfd5 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -250,6 +250,7 @@ provide! { tcx, def_id, other, cdata,
     asyncness => { table_direct }
     fn_arg_names => { table }
     coroutine_kind => { table_direct }
+    coroutine_for_closure => { table }
     trait_def => { table }
     deduced_param_attrs => { table }
     is_type_alias_impl_trait => {
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index 79aa9a547f7..6ca1973396f 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1447,6 +1447,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             {
                 self.tables.coroutine_kind.set(def_id.index, Some(coroutine_kind))
             }
+            if def_kind == DefKind::Closure
+                && tcx.type_of(def_id).skip_binder().is_coroutine_closure()
+            {
+                self.tables
+                    .coroutine_for_closure
+                    .set_some(def_id.index, self.tcx.coroutine_for_closure(def_id).into());
+            }
             if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind {
                 self.encode_info_for_adt(local_id);
             }
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 2f775882693..8205e995c19 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -443,6 +443,7 @@ define_tables! {
     asyncness: Table<DefIndex, ty::Asyncness>,
     fn_arg_names: Table<DefIndex, LazyArray<Ident>>,
     coroutine_kind: Table<DefIndex, hir::CoroutineKind>,
+    coroutine_for_closure: Table<DefIndex, RawDefId>,
     trait_def: Table<DefIndex, LazyValue<ty::TraitDef>>,
     trait_item_def_id: Table<DefIndex, RawDefId>,
     expn_that_defined: Table<DefIndex, LazyValue<ExpnId>>,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index bf72aac1033..50817dd0a80 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -82,7 +82,7 @@ impl<'hir> Iterator for ParentHirIterator<'hir> {
         }
 
         // There are nodes that do not have entries, so we need to skip them.
-        let parent_id = self.map.parent_id(self.current_id);
+        let parent_id = self.map.tcx.parent_hir_id(self.current_id);
 
         if parent_id == self.current_id {
             self.current_id = CRATE_HIR_ID;
@@ -175,6 +175,28 @@ impl<'tcx> TyCtxt<'tcx> {
         self.opt_hir_node_by_def_id(id)
             .unwrap_or_else(|| bug!("couldn't find HIR node for def id {id:?}"))
     }
+
+    /// Returns `HirId` of the parent HIR node of node with this `hir_id`.
+    /// Returns the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
+    ///
+    /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
+    pub fn parent_hir_id(self, hir_id: HirId) -> HirId {
+        let HirId { owner, local_id } = hir_id;
+        if local_id == ItemLocalId::from_u32(0) {
+            self.hir_owner_parent(owner)
+        } else {
+            let parent_local_id = self.hir_owner_nodes(owner).nodes[local_id].parent;
+            // HIR indexing should have checked that.
+            debug_assert_ne!(parent_local_id, local_id);
+            HirId { owner, local_id: parent_local_id }
+        }
+    }
+
+    /// Returns parent HIR node of node with this `hir_id`.
+    /// Returns HIR node of the same `hir_id` if and only if `hir_id == CRATE_HIR_ID`.
+    pub fn parent_hir_node(self, hir_id: HirId) -> Node<'tcx> {
+        self.hir_node(self.parent_hir_id(hir_id))
+    }
 }
 
 impl<'hir> Map<'hir> {
@@ -217,39 +239,6 @@ impl<'hir> Map<'hir> {
         self.tcx.definitions_untracked().def_path_hash(def_id)
     }
 
-    /// Finds the id of the parent node to this one.
-    ///
-    /// If calling repeatedly and iterating over parents, prefer [`Map::parent_iter`].
-    pub fn opt_parent_id(self, id: HirId) -> Option<HirId> {
-        if id.local_id == ItemLocalId::from_u32(0) {
-            // FIXME: This function never returns `None` right now, and the parent chain end is
-            // determined by checking for `parent(id) == id`. This function should return `None`
-            // for the crate root instead.
-            Some(self.tcx.hir_owner_parent(id.owner))
-        } else {
-            let owner = self.tcx.hir_owner_nodes(id.owner);
-            let node = &owner.nodes[id.local_id];
-            let hir_id = HirId { owner: id.owner, local_id: node.parent };
-            // HIR indexing should have checked that.
-            debug_assert_ne!(id.local_id, node.parent);
-            Some(hir_id)
-        }
-    }
-
-    #[track_caller]
-    pub fn parent_id(self, hir_id: HirId) -> HirId {
-        self.opt_parent_id(hir_id)
-            .unwrap_or_else(|| bug!("No parent for node {}", self.node_to_string(hir_id)))
-    }
-
-    pub fn get_parent(self, hir_id: HirId) -> Node<'hir> {
-        self.tcx.hir_node(self.parent_id(hir_id))
-    }
-
-    pub fn find_parent(self, hir_id: HirId) -> Option<Node<'hir>> {
-        Some(self.tcx.hir_node(self.opt_parent_id(hir_id)?))
-    }
-
     pub fn get_if_local(self, id: DefId) -> Option<Node<'hir>> {
         id.as_local()
             .and_then(|id| Some(self.tcx.hir_node(self.tcx.opt_local_def_id_to_hir_id(id)?)))
@@ -304,14 +293,13 @@ impl<'hir> Map<'hir> {
     /// which this is the body of, i.e., a `fn`, `const` or `static`
     /// item (possibly associated), a closure, or a `hir::AnonConst`.
     pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
-        let parent = self.parent_id(hir_id);
+        let parent = self.tcx.parent_hir_id(hir_id);
         assert!(is_body_owner(self.tcx.hir_node(parent), hir_id), "{hir_id:?}");
         parent
     }
 
     pub fn body_owner_def_id(self, BodyId { hir_id }: BodyId) -> LocalDefId {
-        let parent = self.parent_id(hir_id);
-        associated_body(self.tcx.hir_node(parent)).unwrap().0
+        associated_body(self.tcx.parent_hir_node(hir_id)).unwrap().0
     }
 
     /// Given a `LocalDefId`, returns the `BodyId` associated with it,
@@ -569,8 +557,8 @@ impl<'hir> Map<'hir> {
 
     /// Checks if the node is left-hand side of an assignment.
     pub fn is_lhs(self, id: HirId) -> bool {
-        match self.find_parent(id) {
-            Some(Node::Expr(expr)) => match expr.kind {
+        match self.tcx.parent_hir_node(id) {
+            Node::Expr(expr) => match expr.kind {
                 ExprKind::Assign(lhs, _rhs, _span) => lhs.hir_id == id,
                 _ => false,
             },
@@ -793,7 +781,7 @@ impl<'hir> Map<'hir> {
             Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident),
             // A `Ctor` doesn't have an identifier itself, but its parent
             // struct/variant does. Compare with `hir::Map::span`.
-            Node::Ctor(..) => match self.find_parent(id)? {
+            Node::Ctor(..) => match self.tcx.parent_hir_node(id) {
                 Node::Item(item) => Some(item.ident),
                 Node::Variant(variant) => Some(variant.ident),
                 _ => unreachable!(),
@@ -925,7 +913,7 @@ impl<'hir> Map<'hir> {
                 ForeignItemKind::Fn(decl, _, _) => until_within(item.span, decl.output.span()),
                 _ => named_span(item.span, item.ident, None),
             },
-            Node::Ctor(_) => return self.span(self.parent_id(hir_id)),
+            Node::Ctor(_) => return self.span(self.tcx.parent_hir_id(hir_id)),
             Node::Expr(Expr {
                 kind: ExprKind::Closure(Closure { fn_decl_span, .. }),
                 span,
@@ -968,7 +956,7 @@ impl<'hir> Map<'hir> {
             Node::PatField(field) => field.span,
             Node::Arm(arm) => arm.span,
             Node::Block(block) => block.span,
-            Node::Ctor(..) => self.span_with_body(self.parent_id(hir_id)),
+            Node::Ctor(..) => self.span_with_body(self.tcx.parent_hir_id(hir_id)),
             Node::Lifetime(lifetime) => lifetime.ident.span,
             Node::GenericParam(param) => param.span,
             Node::Infer(i) => i.span,
@@ -1001,7 +989,7 @@ impl<'hir> Map<'hir> {
     /// Returns the HirId of `N` in `struct Foo<const N: usize = { ... }>` when
     /// called with the HirId for the `{ ... }` anon const
     pub fn opt_const_param_default_param_def_id(self, anon_const: HirId) -> Option<LocalDefId> {
-        match self.get_parent(anon_const) {
+        match self.tcx.parent_hir_node(anon_const) {
             Node::GenericParam(GenericParam {
                 def_id: param_id,
                 kind: GenericParamKind::Const { .. },
@@ -1026,7 +1014,7 @@ impl<'hir> Map<'hir> {
             _ => None,
         }?;
 
-        match self.find_parent(expr.hir_id)? {
+        match self.tcx.parent_hir_node(expr.hir_id) {
             Node::ExprField(field) => {
                 if field.ident.name == local.name && field.is_shorthand {
                     return Some(local.name);
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index f66cd2370e3..4ef9bc16221 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -136,13 +136,14 @@ pub fn provide(providers: &mut Providers) {
     };
     providers.opt_hir_owner_nodes =
         |tcx, id| tcx.hir_crate(()).owners.get(id)?.as_owner().map(|i| &i.nodes);
-    providers.hir_owner_parent = |tcx, id| {
-        // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash.
-        tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| {
-            let mut parent_hir_id = tcx.local_def_id_to_hir_id(parent);
-            parent_hir_id.local_id =
-                tcx.hir_crate(()).owners[parent_hir_id.owner.def_id].unwrap().parenting[&id.def_id];
-            parent_hir_id
+    providers.hir_owner_parent = |tcx, owner_id| {
+        tcx.opt_local_parent(owner_id.def_id).map_or(CRATE_HIR_ID, |parent_def_id| {
+            let parent_owner_id = tcx.local_def_id_to_hir_id(parent_def_id).owner;
+            HirId {
+                owner: parent_owner_id,
+                local_id: tcx.hir_crate(()).owners[parent_owner_id.def_id].unwrap().parenting
+                    [&owner_id.def_id],
+            }
         })
     };
     providers.hir_attrs = |tcx, id| {
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index 66f448a451e..a1cdc794749 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -356,6 +356,8 @@ pub enum UndefinedBehaviorInfo<'tcx> {
     UninhabitedEnumVariantWritten(VariantIdx),
     /// An uninhabited enum variant is projected.
     UninhabitedEnumVariantRead(VariantIdx),
+    /// Trying to set discriminant to the niched variant, but the value does not match.
+    InvalidNichedEnumVariantWritten { enum_ty: Ty<'tcx> },
     /// ABI-incompatible argument types.
     AbiMismatchArgument { caller_ty: Ty<'tcx>, callee_ty: Ty<'tcx> },
     /// ABI-incompatible return types.
@@ -468,7 +470,7 @@ pub enum UnsupportedOpInfo {
     /// Accessing thread local statics
     ThreadLocalStatic(DefId),
     /// Accessing an unsupported extern static.
-    ReadExternStatic(DefId),
+    ExternStatic(DefId),
 }
 
 /// Error information for when the program exhausted the resources granted to it
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 938fba0ed09..5fe736c9047 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -108,9 +108,9 @@ pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue
 // Queries marked with `fatal_cycle` do not need the latter implementation,
 // as they will raise an fatal error on query cycles instead.
 rustc_queries! {
-    /// This exists purely for testing the interactions between span_delayed_bug and incremental.
-    query trigger_span_delayed_bug(key: DefId) {
-        desc { "triggering a span delayed bug for testing incremental" }
+    /// This exists purely for testing the interactions between delayed bugs and incremental.
+    query trigger_delayed_bug(key: DefId) {
+        desc { "triggering a delayed bug for testing incremental" }
     }
 
     /// Collects the list of all tools registered using `#![register_tool]`.
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index 13cc5cbed44..7cb326ce696 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -358,11 +358,17 @@ pub fn suggest_constraining_type_params<'a>(
         //      trait Foo<T=()> {... }
         //                     - insert: `where T: Zar`
         if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) {
+            // If we are here and the where clause span is of non-zero length
+            // it means we're dealing with an empty where clause like this:
+            //      fn foo<X>(x: X) where { ... }
+            // In that case we don't want to add another "where" (Fixes #120838)
+            let where_prefix = if generics.where_clause_span.is_empty() { " where" } else { "" };
+
             // Suggest a bound, but there is no existing `where` clause *and* the type param has a
             // default (`<T=Foo>`), so we suggest adding `where T: Bar`.
             suggestions.push((
                 generics.tail_span_for_predicate_suggestion(),
-                format!(" where {param_name}: {constraint}"),
+                format!("{where_prefix} {param_name}: {constraint}"),
                 SuggestChangingConstraintsMessage::RestrictTypeFurther { ty: param_name },
             ));
             continue;
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index f90703e6184..5cf90e94907 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -877,7 +877,24 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
             ty::CoroutineClosure(did, args) => {
                 p!(write("{{"));
                 if !self.should_print_verbose() {
-                    p!(write("coroutine-closure"));
+                    match self.tcx().coroutine_kind(self.tcx().coroutine_for_closure(did)).unwrap()
+                    {
+                        hir::CoroutineKind::Desugared(
+                            hir::CoroutineDesugaring::Async,
+                            hir::CoroutineSource::Closure,
+                        ) => p!("async closure"),
+                        hir::CoroutineKind::Desugared(
+                            hir::CoroutineDesugaring::AsyncGen,
+                            hir::CoroutineSource::Closure,
+                        ) => p!("async gen closure"),
+                        hir::CoroutineKind::Desugared(
+                            hir::CoroutineDesugaring::Gen,
+                            hir::CoroutineSource::Closure,
+                        ) => p!("gen closure"),
+                        _ => unreachable!(
+                            "coroutine from coroutine-closure should have CoroutineSource::Closure"
+                        ),
+                    }
                     // FIXME(eddyb) should use `def_span`.
                     if let Some(did) = did.as_local() {
                         if self.tcx().sess.opts.unstable_opts.span_free_formats {
diff --git a/compiler/rustc_middle/src/ty/region.rs b/compiler/rustc_middle/src/ty/region.rs
index 75be380704e..1191d7fca32 100644
--- a/compiler/rustc_middle/src/ty/region.rs
+++ b/compiler/rustc_middle/src/ty/region.rs
@@ -82,8 +82,8 @@ impl<'tcx> Region<'tcx> {
         tcx.intern_region(ty::ReError(reported))
     }
 
-    /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` to ensure it
-    /// gets used.
+    /// Constructs a `RegionKind::ReError` region and registers a delayed bug to ensure it gets
+    /// used.
     #[track_caller]
     pub fn new_error_misc(tcx: TyCtxt<'tcx>) -> Region<'tcx> {
         Region::new_error_with_message(
@@ -93,8 +93,8 @@ impl<'tcx> Region<'tcx> {
         )
     }
 
-    /// Constructs a `RegionKind::ReError` region and registers a `span_delayed_bug` with the given
-    /// `msg` to ensure it gets used.
+    /// Constructs a `RegionKind::ReError` region and registers a delayed bug with the given `msg`
+    /// to ensure it gets used.
     #[track_caller]
     pub fn new_error_with_message<S: Into<MultiSpan>>(
         tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index f2321e7e1d2..303f285b00c 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -435,7 +435,10 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
             Ok(a)
         }
 
-        (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => Ok(a),
+        (ty::Param(a_p), ty::Param(b_p)) if a_p.index == b_p.index => {
+            debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
+            Ok(a)
+        }
 
         (ty::Placeholder(p1), ty::Placeholder(p2)) if p1 == p2 => Ok(a),
 
@@ -593,7 +596,10 @@ pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
         (ty::ConstKind::Error(_), _) => return Ok(a),
         (_, ty::ConstKind::Error(_)) => return Ok(b),
 
-        (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) => a_p.index == b_p.index,
+        (ty::ConstKind::Param(a_p), ty::ConstKind::Param(b_p)) if a_p.index == b_p.index => {
+            debug_assert_eq!(a_p.name, b_p.name, "param types with same index differ in name");
+            true
+        }
         (ty::ConstKind::Placeholder(p1), ty::ConstKind::Placeholder(p2)) => p1 == p2,
         (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val,
 
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index a750a86d257..7acdb931f1a 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -55,7 +55,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
     }
     fn error_reported(&self) -> Result<(), ErrorGuaranteed> {
         if self.references_error() {
-            // We must include lint errors and span delayed bugs here.
+            // We must include lint errors and delayed bugs here.
             if let Some(reported) =
                 ty::tls::with(|tcx| tcx.dcx().has_errors_or_lint_errors_or_delayed_bugs())
             {
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index d1a3dbbf5d3..a67ec991582 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -38,16 +38,16 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
     })
 }
 
-/// A query to trigger a `span_delayed_bug`. Clearly, if one has a `tcx` one can already trigger a
-/// `span_delayed_bug`, so what is the point of this? It exists to help us test `span_delayed_bug`'s
-/// interactions with the query system and incremental.
-pub fn trigger_span_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
+/// A query to trigger a delayed bug. Clearly, if one has a `tcx` one can already trigger a
+/// delayed bug, so what is the point of this? It exists to help us test the interaction of delayed
+/// bugs with the query system and incremental.
+pub fn trigger_delayed_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
     tcx.dcx().span_delayed_bug(
         tcx.def_span(key),
-        "delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]",
+        "delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]",
     );
 }
 
 pub fn provide(providers: &mut crate::query::Providers) {
-    *providers = crate::query::Providers { trigger_span_delayed_bug, ..*providers };
+    *providers = crate::query::Providers { trigger_delayed_bug, ..*providers };
 }
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index 2d366948771..04740a96291 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -792,7 +792,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 return id;
             }
 
-            let next = hir.parent_id(id);
+            let next = self.tcx.parent_hir_id(id);
             if next == id {
                 bug!("lint traversal reached the root of the crate");
             }
diff --git a/compiler/rustc_mir_transform/src/coroutine.rs b/compiler/rustc_mir_transform/src/coroutine.rs
index 297b2fa143d..a0851aa557b 100644
--- a/compiler/rustc_mir_transform/src/coroutine.rs
+++ b/compiler/rustc_mir_transform/src/coroutine.rs
@@ -726,7 +726,7 @@ fn replace_resume_ty_local<'tcx>(
 /// The async lowering step and the type / lifetime inference / checking are
 /// still using the `resume` argument for the time being. After this transform,
 /// the coroutine body doesn't have the `resume` argument.
-fn transform_gen_context<'tcx>(_tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+fn transform_gen_context<'tcx>(body: &mut Body<'tcx>) {
     // This leaves the local representing the `resume` argument in place,
     // but turns it into a regular local variable. This is cheaper than
     // adjusting all local references in the body after removing it.
@@ -1733,7 +1733,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
 
         // Remove the context argument within generator bodies.
         if matches!(coroutine_kind, CoroutineKind::Desugared(CoroutineDesugaring::Gen, _)) {
-            transform_gen_context(tcx, body);
+            transform_gen_context(body);
         }
 
         // The original arguments to the function are no longer arguments, mark them as such.
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index be19bd8349e..956d855ab81 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -2,6 +2,7 @@
 use crate::deref_separator::deref_finder;
 use rustc_attr::InlineAttr;
 use rustc_const_eval::transform::validate::validate_types;
+use rustc_hir::def::DefKind;
 use rustc_hir::def_id::DefId;
 use rustc_index::bit_set::BitSet;
 use rustc_index::Idx;
@@ -384,6 +385,17 @@ impl<'tcx> Inliner<'tcx> {
                 }
 
                 let fn_sig = self.tcx.fn_sig(def_id).instantiate(self.tcx, args);
+
+                // Additionally, check that the body that we're inlining actually agrees
+                // with the ABI of the trait that the item comes from.
+                if let InstanceDef::Item(instance_def_id) = callee.def
+                    && self.tcx.def_kind(instance_def_id) == DefKind::AssocFn
+                    && let instance_fn_sig = self.tcx.fn_sig(instance_def_id).skip_binder()
+                    && instance_fn_sig.abi() != fn_sig.abi()
+                {
+                    return None;
+                }
+
                 let source_info = SourceInfo { span: fn_span, ..terminator.source_info };
 
                 return Some(CallSite { callee, fn_sig, block: bb, source_info });
diff --git a/compiler/rustc_mir_transform/src/instsimplify.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index f65eb5cbea9..06df89c1037 100644
--- a/compiler/rustc_mir_transform/src/instsimplify.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -29,17 +29,14 @@ impl<'tcx> MirPass<'tcx> for InstSimplify {
                         ctx.simplify_bool_cmp(&statement.source_info, rvalue);
                         ctx.simplify_ref_deref(&statement.source_info, rvalue);
                         ctx.simplify_len(&statement.source_info, rvalue);
-                        ctx.simplify_cast(&statement.source_info, rvalue);
+                        ctx.simplify_cast(rvalue);
                     }
                     _ => {}
                 }
             }
 
             ctx.simplify_primitive_clone(block.terminator.as_mut().unwrap(), &mut block.statements);
-            ctx.simplify_intrinsic_assert(
-                block.terminator.as_mut().unwrap(),
-                &mut block.statements,
-            );
+            ctx.simplify_intrinsic_assert(block.terminator.as_mut().unwrap());
             ctx.simplify_nounwind_call(block.terminator.as_mut().unwrap());
             simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
         }
@@ -143,7 +140,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
         }
     }
 
-    fn simplify_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+    fn simplify_cast(&self, rvalue: &mut Rvalue<'tcx>) {
         if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
             let operand_ty = operand.ty(self.local_decls, self.tcx);
             if operand_ty == *cast_ty {
@@ -277,11 +274,7 @@ impl<'tcx> InstSimplifyContext<'tcx, '_> {
         }
     }
 
-    fn simplify_intrinsic_assert(
-        &self,
-        terminator: &mut Terminator<'tcx>,
-        _statements: &mut Vec<Statement<'tcx>>,
-    ) {
+    fn simplify_intrinsic_assert(&self, terminator: &mut Terminator<'tcx>) {
         let TerminatorKind::Call { func, target, .. } = &mut terminator.kind else {
             return;
         };
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 7b6de3a5439..860d280be29 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -447,16 +447,13 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'t
 fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
     debug!("build_clone_shim(def_id={:?})", def_id);
 
-    let param_env = tcx.param_env_reveal_all_normalized(def_id);
-
     let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
-    let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
 
     let dest = Place::return_place();
     let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0)));
 
     match self_ty.kind() {
-        _ if is_copy => builder.copy_shim(),
+        ty::FnDef(..) | ty::FnPtr(_) => builder.copy_shim(),
         ty::Closure(_, args) => builder.tuple_like_shim(dest, src, args.as_closure().upvar_tys()),
         ty::Tuple(..) => builder.tuple_like_shim(dest, src, self_ty.tuple_fields()),
         ty::Coroutine(coroutine_def_id, args) => {
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 3376af98653..149e4c2cb08 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -666,7 +666,15 @@ impl<'a, 'tcx> MirUsedCollector<'a, 'tcx> {
         debug!(?def_id, ?fn_span);
 
         for arg in args {
-            if let Some(too_large_size) = self.operand_size_if_too_large(limit, &arg.node) {
+            // Moving args into functions is typically implemented with pointer
+            // passing at the llvm-ir level and not by memcpy's. So always allow
+            // moving args into functions.
+            let operand: &mir::Operand<'tcx> = &arg.node;
+            if let mir::Operand::Move(_) = operand {
+                continue;
+            }
+
+            if let Some(too_large_size) = self.operand_size_if_too_large(limit, operand) {
                 self.lint_large_assignment(limit.0, too_large_size, location, arg.span);
             };
         }
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index ec704dec352..d8ae82d11bc 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -197,7 +197,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
                 | sym::unstable
                 | sym::stable
                 | sym::rustc_allowed_through_unstable_modules
-                | sym::rustc_promotable => self.check_stability_promotable(attr, span, target),
+                | sym::rustc_promotable => self.check_stability_promotable(attr, target),
                 sym::link_ordinal => self.check_link_ordinal(attr, span, target),
                 sym::rustc_confusables => self.check_confusables(attr, target),
                 sym::rustc_safe_intrinsic => {
@@ -2069,14 +2069,11 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         span: Span,
         target: Target,
     ) -> bool {
-        let hir = self.tcx.hir();
-
         if let Target::ForeignFn = target
-            && let Some(parent) = hir.opt_parent_id(hir_id)
             && let hir::Node::Item(Item {
                 kind: ItemKind::ForeignMod { abi: Abi::RustIntrinsic | Abi::PlatformIntrinsic, .. },
                 ..
-            }) = self.tcx.hir_node(parent)
+            }) = self.tcx.parent_hir_node(hir_id)
         {
             return true;
         }
@@ -2102,7 +2099,7 @@ impl<'tcx> CheckAttrVisitor<'tcx> {
         }
     }
 
-    fn check_stability_promotable(&self, attr: &Attribute, _span: Span, target: Target) -> bool {
+    fn check_stability_promotable(&self, attr: &Attribute, target: Target) -> bool {
         match target {
             Target::Expression => {
                 self.dcx().emit_err(errors::StabilityPromotable { attr_span: attr.span });
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 7d95a0bc478..49ae9f16c8e 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -625,6 +625,13 @@ impl Span {
         span.lo < other.hi && other.lo < span.hi
     }
 
+    /// Returns `true` if `self` touches or adjoins `other`.
+    pub fn overlaps_or_adjacent(self, other: Span) -> bool {
+        let span = self.data();
+        let other = other.data();
+        span.lo <= other.hi && other.lo <= span.hi
+    }
+
     /// Returns `true` if the spans are equal with regards to the source text.
     ///
     /// Use this instead of `==` when either span could be generated code,
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index aa912c93c08..83eca6c032b 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -655,6 +655,7 @@ symbols! {
         default_method_body_is_const,
         default_type_parameter_fallback,
         default_type_params,
+        delayed_bug_from_inside_query,
         deny,
         deprecated,
         deprecated_safe,
@@ -1579,7 +1580,6 @@ symbols! {
         slice_patterns,
         slicing_syntax,
         soft,
-        span_delayed_bug_from_inside_query,
         specialization,
         speed,
         spotlight,
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 9d1b92e1068..1a1aed61fed 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -261,12 +261,7 @@ fn encode_predicates<'tcx>(
 }
 
 /// Encodes a region using the Itanium C++ ABI as a vendor extended type.
-fn encode_region<'tcx>(
-    _tcx: TyCtxt<'tcx>,
-    region: Region<'tcx>,
-    dict: &mut FxHashMap<DictKey<'tcx>, usize>,
-    _options: EncodeTyOptions,
-) -> String {
+fn encode_region<'tcx>(region: Region<'tcx>, dict: &mut FxHashMap<DictKey<'tcx>, usize>) -> String {
     // u6region[I[<region-disambiguator>][<region-index>]E] as vendor extended type
     let mut s = String::new();
     match region.kind() {
@@ -314,7 +309,7 @@ fn encode_args<'tcx>(
         for arg in args {
             match arg.unpack() {
                 GenericArgKind::Lifetime(region) => {
-                    s.push_str(&encode_region(tcx, region, dict, options));
+                    s.push_str(&encode_region(region, dict));
                 }
                 GenericArgKind::Type(ty) => {
                     s.push_str(&encode_ty(tcx, ty, dict, options));
@@ -703,7 +698,7 @@ fn encode_ty<'tcx>(
                 ty::DynStar => "u7dynstarI",
             });
             s.push_str(&encode_predicates(tcx, predicates, dict, options));
-            s.push_str(&encode_region(tcx, *region, dict, options));
+            s.push_str(&encode_region(*region, dict));
             s.push('E');
             compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
             typeid.push_str(&s);
@@ -735,7 +730,6 @@ fn encode_ty<'tcx>(
 fn transform_predicates<'tcx>(
     tcx: TyCtxt<'tcx>,
     predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
-    _options: EncodeTyOptions,
 ) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
     let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates
         .iter()
@@ -967,7 +961,7 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
         ty::Dynamic(predicates, _region, kind) => {
             ty = Ty::new_dynamic(
                 tcx,
-                transform_predicates(tcx, predicates, options),
+                transform_predicates(tcx, predicates),
                 tcx.lifetimes.re_erased,
                 *kind,
             );
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 81c0cfea85a..6833d2ae330 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -15,7 +15,7 @@ use rustc_middle::ty::fast_reject::{SimplifiedType, TreatParams};
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::ty::{fast_reject, TypeFoldable};
 use rustc_middle::ty::{ToPredicate, TypeVisitableExt};
-use rustc_span::ErrorGuaranteed;
+use rustc_span::{ErrorGuaranteed, DUMMY_SP};
 use std::fmt::Debug;
 
 pub(super) mod structural_traits;
@@ -612,7 +612,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
 
             ty::Alias(kind @ (ty::Projection | ty::Opaque), alias_ty) => (kind, alias_ty),
             ty::Alias(ty::Inherent | ty::Weak, _) => {
-                unreachable!("Weak and Inherent aliases should have been normalized away already")
+                self.tcx().sess.dcx().span_delayed_bug(
+                    DUMMY_SP,
+                    format!("could not normalize {self_ty}, it is not WF"),
+                );
+                return;
             }
         };
 
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index f68200b6f4d..eb75b04ed1c 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -1032,15 +1032,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         };
 
-        let hir = self.tcx.hir();
         let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?);
-        match hir.find_parent(hir_id) {
-            Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => {
+        match self.tcx.parent_hir_node(hir_id) {
+            hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. }) => {
                 get_name(err, &local.pat.kind)
             }
             // Different to previous arm because one is `&hir::Local` and the other
             // is `P<hir::Local>`.
-            Some(hir::Node::Local(local)) => get_name(err, &local.pat.kind),
+            hir::Node::Local(local) => get_name(err, &local.pat.kind),
             _ => None,
         }
     }
@@ -1202,8 +1201,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         let hir::Node::Pat(pat) = self.tcx.hir_node(hir_id) else {
             return;
         };
-        let Some(hir::Node::Local(hir::Local { ty: None, init: Some(init), .. })) =
-            self.tcx.hir().find_parent(pat.hir_id)
+        let hir::Node::Local(hir::Local { ty: None, init: Some(init), .. }) =
+            self.tcx.parent_hir_node(pat.hir_id)
         else {
             return;
         };
@@ -1790,7 +1789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let Res::Local(hir_id) = path.res
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(hir_id)
-                && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id)
+                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let None = local.ty
                 && let Some(binding_expr) = local.init
             {
@@ -3188,8 +3187,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
             ObligationCauseCode::VariableType(hir_id) => {
-                let parent_node = tcx.hir().parent_id(hir_id);
-                match tcx.hir_node(parent_node) {
+                match tcx.parent_hir_node(hir_id) {
                     Node::Local(hir::Local { ty: Some(ty), .. }) => {
                         err.span_suggestion_verbose(
                             ty.span.shrink_to_lo(),
@@ -3237,8 +3235,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                     types always have a known size";
                 if let Some(hir_id) = hir_id
                     && let hir::Node::Param(param) = self.tcx.hir_node(hir_id)
-                    && let Some(item) = self.tcx.hir().find_parent(hir_id)
-                    && let Some(decl) = item.fn_decl()
+                    && let Some(decl) = self.tcx.parent_hir_node(hir_id).fn_decl()
                     && let Some(t) = decl.inputs.iter().find(|t| param.ty_span.contains(t.span))
                 {
                     // We use `contains` because the type might be surrounded by parentheses,
@@ -4079,8 +4076,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: Res::Local(hir_id), .. } = path
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
-                && let parent_hir_id = self.tcx.hir().parent_id(binding.hir_id)
-                && let hir::Node::Local(local) = self.tcx.hir_node(parent_hir_id)
+                && let hir::Node::Local(local) = self.tcx.parent_hir_node(binding.hir_id)
                 && let Some(binding_expr) = local.init
             {
                 // If the expression we're calling on is a binding, we want to point at the
@@ -4338,8 +4334,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: Res::Local(hir_id), .. } = path
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
-                && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
             {
+                let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
                 if let hir::Node::Local(local) = parent
                     && let Some(binding_expr) = local.init
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
index 07e4fef9dd4..05c141ab2d3 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs
@@ -615,8 +615,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                         let UnsatisfiedConst(unsatisfied_const) = self
                             .maybe_add_note_for_unsatisfied_const(
-                                &obligation,
-                                trait_ref,
                                 &trait_predicate,
                                 &mut err,
                                 span,
@@ -1162,8 +1160,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
                 && let hir::Path { res: hir::def::Res::Local(hir_id), .. } = path
                 && let hir::Node::Pat(binding) = self.tcx.hir_node(*hir_id)
-                && let Some(parent) = self.tcx.hir().find_parent(binding.hir_id)
             {
+                let parent = self.tcx.parent_hir_node(binding.hir_id);
                 // We've reached the root of the method call chain...
                 if let hir::Node::Local(local) = parent
                     && let Some(binding_expr) = local.init
@@ -1480,8 +1478,6 @@ pub(super) trait InferCtxtPrivExt<'tcx> {
 
     fn maybe_add_note_for_unsatisfied_const(
         &self,
-        obligation: &PredicateObligation<'tcx>,
-        trait_ref: ty::PolyTraitRef<'tcx>,
         trait_predicate: &ty::PolyTraitPredicate<'tcx>,
         err: &mut Diagnostic,
         span: Span,
@@ -3359,8 +3355,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
     fn maybe_add_note_for_unsatisfied_const(
         &self,
-        _obligation: &PredicateObligation<'tcx>,
-        _trait_ref: ty::PolyTraitRef<'tcx>,
         _trait_predicate: &ty::PolyTraitPredicate<'tcx>,
         _err: &mut Diagnostic,
         _span: Span,
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index eae80199ce5..7fa416197b3 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -209,10 +209,8 @@ fn resolve_associated_item<'tcx>(
                 let name = tcx.item_name(trait_item_id);
                 if name == sym::clone {
                     let self_ty = trait_ref.self_ty();
-
-                    let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
                     match self_ty.kind() {
-                        _ if is_copy => (),
+                        ty::FnDef(..) | ty::FnPtr(_) => (),
                         ty::Coroutine(..)
                         | ty::CoroutineWitness(..)
                         | ty::Closure(..)
diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs
index f83c8f83cc9..3b29c144a89 100644
--- a/library/alloc/src/boxed/thin.rs
+++ b/library/alloc/src/boxed/thin.rs
@@ -67,6 +67,26 @@ impl<T> ThinBox<T> {
         let ptr = WithOpaqueHeader::new(meta, value);
         ThinBox { ptr, _marker: PhantomData }
     }
+
+    /// Moves a type to the heap with its [`Metadata`] stored in the heap allocation instead of on
+    /// the stack. Returns an error if allocation fails, instead of aborting.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    /// #![feature(thin_box)]
+    /// use std::boxed::ThinBox;
+    ///
+    /// let five = ThinBox::try_new(5)?;
+    /// # Ok::<(), std::alloc::AllocError>(())
+    /// ```
+    ///
+    /// [`Metadata`]: core::ptr::Pointee::Metadata
+    pub fn try_new(value: T) -> Result<Self, core::alloc::AllocError> {
+        let meta = ptr::metadata(&value);
+        WithOpaqueHeader::try_new(meta, value).map(|ptr| ThinBox { ptr, _marker: PhantomData })
+    }
 }
 
 #[unstable(feature = "thin_box", issue = "92791")]
@@ -179,6 +199,10 @@ impl WithOpaqueHeader {
         let ptr = WithHeader::new(header, value);
         Self(ptr.0)
     }
+
+    fn try_new<H, T>(header: H, value: T) -> Result<Self, core::alloc::AllocError> {
+        WithHeader::try_new(header, value).map(|ptr| Self(ptr.0))
+    }
 }
 
 impl<H> WithHeader<H> {
@@ -224,6 +248,46 @@ impl<H> WithHeader<H> {
         }
     }
 
+    /// Non-panicking version of `new`.
+    /// Any error is returned as `Err(core::alloc::AllocError)`.
+    fn try_new<T>(header: H, value: T) -> Result<WithHeader<H>, core::alloc::AllocError> {
+        let value_layout = Layout::new::<T>();
+        let Ok((layout, value_offset)) = Self::alloc_layout(value_layout) else {
+            return Err(core::alloc::AllocError);
+        };
+
+        unsafe {
+            // Note: It's UB to pass a layout with a zero size to `alloc::alloc`, so
+            // we use `layout.dangling()` for this case, which should have a valid
+            // alignment for both `T` and `H`.
+            let ptr = if layout.size() == 0 {
+                // Some paranoia checking, mostly so that the ThinBox tests are
+                // more able to catch issues.
+                debug_assert!(
+                    value_offset == 0 && mem::size_of::<T>() == 0 && mem::size_of::<H>() == 0
+                );
+                layout.dangling()
+            } else {
+                let ptr = alloc::alloc(layout);
+                if ptr.is_null() {
+                    return Err(core::alloc::AllocError);
+                }
+
+                // Safety:
+                // - The size is at least `aligned_header_size`.
+                let ptr = ptr.add(value_offset) as *mut _;
+
+                NonNull::new_unchecked(ptr)
+            };
+
+            let result = WithHeader(ptr, PhantomData);
+            ptr::write(result.header(), header);
+            ptr::write(result.value().cast(), value);
+
+            Ok(result)
+        }
+    }
+
     // Safety:
     // - Assumes that either `value` can be dereferenced, or is the
     //   `NonNull::dangling()` we use when both `T` and `H` are ZSTs.
diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs
index b585e2082f1..2b8ddf14ff3 100644
--- a/library/alloc/src/collections/btree/map.rs
+++ b/library/alloc/src/collections/btree/map.rs
@@ -2522,10 +2522,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         self.len() == 0
     }
 
-    /// Returns a [`Cursor`] pointing to the first gap above the given bound.
+    /// Returns a [`Cursor`] pointing at the gap before the smallest key
+    /// greater than the given bound.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
-    /// of the map.
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap before the smallest key greater than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap before the smallest key greater than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap before the smallest key in the map.
     ///
     /// # Examples
     ///
@@ -2535,17 +2542,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// use std::collections::BTreeMap;
     /// use std::ops::Bound;
     ///
-    /// let mut a = BTreeMap::new();
-    /// a.insert(1, "a");
-    /// a.insert(2, "b");
-    /// a.insert(3, "c");
-    /// a.insert(4, "d");
-    /// let cursor = a.lower_bound(Bound::Included(&2));
+    /// let map = BTreeMap::from([
+    ///     (1, "a"),
+    ///     (2, "b"),
+    ///     (3, "c"),
+    ///     (4, "d"),
+    /// ]);
+    ///
+    /// let cursor = map.lower_bound(Bound::Included(&2));
     /// assert_eq!(cursor.peek_prev(), Some((&1, &"a")));
     /// assert_eq!(cursor.peek_next(), Some((&2, &"b")));
-    /// let cursor = a.lower_bound(Bound::Excluded(&2));
+    ///
+    /// let cursor = map.lower_bound(Bound::Excluded(&2));
     /// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
     /// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
+    ///
+    /// let cursor = map.lower_bound(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), None);
+    /// assert_eq!(cursor.peek_next(), Some((&1, &"a")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn lower_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
@@ -2561,11 +2575,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         Cursor { current: Some(edge), root: self.root.as_ref() }
     }
 
-    /// Returns a [`CursorMut`] pointing to the first gap above the given bound.
+    /// Returns a [`CursorMut`] pointing at the gap before the smallest key
+    /// greater than the given bound.
     ///
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap before the smallest key greater than or equal to `x`.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the start
-    /// of the map.
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap before the smallest key greater than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap before the smallest key in the map.
     ///
     /// # Examples
     ///
@@ -2575,17 +2595,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// use std::collections::BTreeMap;
     /// use std::ops::Bound;
     ///
-    /// let mut a = BTreeMap::new();
-    /// a.insert(1, "a");
-    /// a.insert(2, "b");
-    /// a.insert(3, "c");
-    /// a.insert(4, "d");
-    /// let mut cursor = a.lower_bound_mut(Bound::Included(&2));
+    /// let mut map = BTreeMap::from([
+    ///     (1, "a"),
+    ///     (2, "b"),
+    ///     (3, "c"),
+    ///     (4, "d"),
+    /// ]);
+    ///
+    /// let mut cursor = map.lower_bound_mut(Bound::Included(&2));
     /// assert_eq!(cursor.peek_prev(), Some((&1, &mut "a")));
     /// assert_eq!(cursor.peek_next(), Some((&2, &mut "b")));
-    /// let mut cursor = a.lower_bound_mut(Bound::Excluded(&2));
+    ///
+    /// let mut cursor = map.lower_bound_mut(Bound::Excluded(&2));
     /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
     /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
+    ///
+    /// let mut cursor = map.lower_bound_mut(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), None);
+    /// assert_eq!(cursor.peek_next(), Some((&1, &mut "a")));
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn lower_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
@@ -2618,10 +2645,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         }
     }
 
-    /// Returns a [`Cursor`] pointing at the last gap below the given bound.
+    /// Returns a [`Cursor`] pointing at the gap after the greatest key
+    /// smaller than the given bound.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
-    /// of the map.
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap after the greatest key smaller than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap after the greatest key smaller than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap after the greatest key in the map.
     ///
     /// # Examples
     ///
@@ -2631,17 +2665,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// use std::collections::BTreeMap;
     /// use std::ops::Bound;
     ///
-    /// let mut a = BTreeMap::new();
-    /// a.insert(1, "a");
-    /// a.insert(2, "b");
-    /// a.insert(3, "c");
-    /// a.insert(4, "d");
-    /// let cursor = a.upper_bound(Bound::Included(&3));
+    /// let map = BTreeMap::from([
+    ///     (1, "a"),
+    ///     (2, "b"),
+    ///     (3, "c"),
+    ///     (4, "d"),
+    /// ]);
+    ///
+    /// let cursor = map.upper_bound(Bound::Included(&3));
     /// assert_eq!(cursor.peek_prev(), Some((&3, &"c")));
     /// assert_eq!(cursor.peek_next(), Some((&4, &"d")));
-    /// let cursor = a.upper_bound(Bound::Excluded(&3));
+    ///
+    /// let cursor = map.upper_bound(Bound::Excluded(&3));
     /// assert_eq!(cursor.peek_prev(), Some((&2, &"b")));
     /// assert_eq!(cursor.peek_next(), Some((&3, &"c")));
+    ///
+    /// let cursor = map.upper_bound(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), Some((&4, &"d")));
+    /// assert_eq!(cursor.peek_next(), None);
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn upper_bound<Q: ?Sized>(&self, bound: Bound<&Q>) -> Cursor<'_, K, V>
@@ -2657,10 +2698,17 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
         Cursor { current: Some(edge), root: self.root.as_ref() }
     }
 
-    /// Returns a [`CursorMut`] pointing at the last gap below the given bound.
+    /// Returns a [`CursorMut`] pointing at the gap after the greatest key
+    /// smaller than the given bound.
     ///
-    /// Passing [`Bound::Unbounded`] will return a cursor pointing to the end
-    /// of the map.
+    /// Passing `Bound::Included(x)` will return a cursor pointing to the
+    /// gap after the greatest key smaller than or equal to `x`.
+    ///
+    /// Passing `Bound::Excluded(x)` will return a cursor pointing to the
+    /// gap after the greatest key smaller than `x`.
+    ///
+    /// Passing `Bound::Unbounded` will return a cursor pointing to the
+    /// gap after the greatest key in the map.
     ///
     /// # Examples
     ///
@@ -2670,17 +2718,24 @@ impl<K, V, A: Allocator + Clone> BTreeMap<K, V, A> {
     /// use std::collections::BTreeMap;
     /// use std::ops::Bound;
     ///
-    /// let mut a = BTreeMap::new();
-    /// a.insert(1, "a");
-    /// a.insert(2, "b");
-    /// a.insert(3, "c");
-    /// a.insert(4, "d");
-    /// let mut cursor = a.upper_bound_mut(Bound::Included(&3));
+    /// let mut map = BTreeMap::from([
+    ///     (1, "a"),
+    ///     (2, "b"),
+    ///     (3, "c"),
+    ///     (4, "d"),
+    /// ]);
+    ///
+    /// let mut cursor = map.upper_bound_mut(Bound::Included(&3));
     /// assert_eq!(cursor.peek_prev(), Some((&3, &mut "c")));
     /// assert_eq!(cursor.peek_next(), Some((&4, &mut "d")));
-    /// let mut cursor = a.upper_bound_mut(Bound::Excluded(&3));
+    ///
+    /// let mut cursor = map.upper_bound_mut(Bound::Excluded(&3));
     /// assert_eq!(cursor.peek_prev(), Some((&2, &mut "b")));
     /// assert_eq!(cursor.peek_next(), Some((&3, &mut "c")));
+    ///
+    /// let mut cursor = map.upper_bound_mut(Bound::Unbounded);
+    /// assert_eq!(cursor.peek_prev(), Some((&4, &mut "d")));
+    /// assert_eq!(cursor.peek_next(), None);
     /// ```
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn upper_bound_mut<Q: ?Sized>(&mut self, bound: Bound<&Q>) -> CursorMut<'_, K, V, A>
@@ -3040,8 +3095,8 @@ impl<'a, K, V, A> CursorMutKey<'a, K, V, A> {
 
 // Now the tree editing operations
 impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMutKey` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap before the
     /// newly inserted element.
@@ -3083,8 +3138,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
         *self.length += 1;
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMutKey` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap after the
     /// newly inserted element.
@@ -3129,19 +3184,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
         *self.length += 1;
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMutKey` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap before the
     /// newly inserted element.
     ///
-    /// # Panics
-    ///
-    /// This function panics if:
-    /// - the given key compares less than or equal to the current element (if
-    ///   any).
-    /// - the given key compares greater than or equal to the next element (if
-    ///   any).
+    /// If the inserted key is not greater than the key before the cursor
+    /// (if any), or if it not less than the key after the cursor (if any),
+    /// then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the keys of the map.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
         if let Some((prev, _)) = self.peek_prev() {
@@ -3160,19 +3212,16 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
         Ok(())
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMutKey` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap after the
     /// newly inserted element.
     ///
-    /// # Panics
-    ///
-    /// This function panics if:
-    /// - the given key compares greater than or equal to the current element
-    ///   (if any).
-    /// - the given key compares less than or equal to the previous element (if
-    ///   any).
+    /// If the inserted key is not greater than the key before the cursor
+    /// (if any), or if it not less than the key after the cursor (if any),
+    /// then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the keys of the map.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
         if let Some((prev, _)) = self.peek_prev() {
@@ -3239,10 +3288,10 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMutKey<'a, K, V, A> {
 }
 
 impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMut` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
-    /// After the insertion the cursor will be pointing at the gap before the
+    /// After the insertion the cursor will be pointing at the gap after the
     /// newly inserted element.
     ///
     /// # Safety
@@ -3257,8 +3306,8 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
         unsafe { self.inner.insert_after_unchecked(key, value) }
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMut` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap after the
     /// newly inserted element.
@@ -3275,37 +3324,31 @@ impl<'a, K: Ord, V, A: Allocator + Clone> CursorMut<'a, K, V, A> {
         unsafe { self.inner.insert_before_unchecked(key, value) }
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMut` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap before the
     /// newly inserted element.
     ///
-    /// # Panics
-    ///
-    /// This function panics if:
-    /// - the given key compares less than or equal to the current element (if
-    ///   any).
-    /// - the given key compares greater than or equal to the next element (if
-    ///   any).
+    /// If the inserted key is not greater than the key before the cursor
+    /// (if any), or if it not less than the key after the cursor (if any),
+    /// then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the keys of the map.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn insert_after(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
         self.inner.insert_after(key, value)
     }
 
-    /// Inserts a new element into the `BTreeMap` in the gap that the
-    /// `CursorMut` is currently pointing to.
+    /// Inserts a new key-value pair into the map in the gap that the
+    /// cursor is currently pointing to.
     ///
     /// After the insertion the cursor will be pointing at the gap after the
     /// newly inserted element.
     ///
-    /// # Panics
-    ///
-    /// This function panics if:
-    /// - the given key compares greater than or equal to the current element
-    ///   (if any).
-    /// - the given key compares less than or equal to the previous element (if
-    ///   any).
+    /// If the inserted key is not greater than the key before the cursor
+    /// (if any), or if it not less than the key after the cursor (if any),
+    /// then an [`UnorderedKeyError`] is returned since this would
+    /// invalidate the [`Ord`] invariant between the keys of the map.
     #[unstable(feature = "btree_cursors", issue = "107540")]
     pub fn insert_before(&mut self, key: K, value: V) -> Result<(), UnorderedKeyError> {
         self.inner.insert_before(key, value)
diff --git a/library/alloc/src/fmt.rs b/library/alloc/src/fmt.rs
index 5b50ef7bf6c..fce2585cbf5 100644
--- a/library/alloc/src/fmt.rs
+++ b/library/alloc/src/fmt.rs
@@ -188,6 +188,10 @@
 //!     * `#X` - precedes the argument with a `0x`
 //!     * `#b` - precedes the argument with a `0b`
 //!     * `#o` - precedes the argument with a `0o`
+//!
+//!   See [Formatting traits](#formatting-traits) for a description of what the `?`, `x`, `X`,
+//!   `b`, and `o` flags do.
+//!
 //! * `0` - This is used to indicate for integer formats that the padding to `width` should
 //!         both be done with a `0` character as well as be sign-aware. A format
 //!         like `{:08}` would yield `00000001` for the integer `1`, while the
@@ -197,6 +201,7 @@
 //!         and before the digits. When used together with the `#` flag, a similar
 //!         rule applies: padding zeros are inserted after the prefix but before
 //!         the digits. The prefix is included in the total width.
+//!         This flag overrides the [fill character and alignment flag](#fillalignment).
 //!
 //! ## Precision
 //!
diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs
index 030040ba09a..c77fa371cc7 100644
--- a/library/core/src/cell.rs
+++ b/library/core/src/cell.rs
@@ -237,9 +237,9 @@
 
 use crate::cmp::Ordering;
 use crate::fmt::{self, Debug, Display};
-use crate::intrinsics::is_nonoverlapping;
+use crate::intrinsics;
 use crate::marker::{PhantomData, Unsize};
-use crate::mem;
+use crate::mem::{self, size_of};
 use crate::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
 use crate::ptr::{self, NonNull};
 
@@ -435,11 +435,15 @@ impl<T> Cell<T> {
     #[inline]
     #[stable(feature = "move_cell", since = "1.17.0")]
     pub fn swap(&self, other: &Self) {
+        fn is_nonoverlapping<T>(src: *const T, dst: *const T) -> bool {
+            intrinsics::is_nonoverlapping(src.cast(), dst.cast(), size_of::<T>(), 1)
+        }
+
         if ptr::eq(self, other) {
             // Swapping wouldn't change anything.
             return;
         }
-        if !is_nonoverlapping(self, other, 1) {
+        if !is_nonoverlapping(self, other) {
             // See <https://github.com/rust-lang/rust/issues/80778> for why we need to stop here.
             panic!("`Cell::swap` on overlapping non-identical `Cell`s");
         }
diff --git a/library/core/src/ffi/c_str.rs b/library/core/src/ffi/c_str.rs
index bb839a71e90..248943cf022 100644
--- a/library/core/src/ffi/c_str.rs
+++ b/library/core/src/ffi/c_str.rs
@@ -88,6 +88,7 @@ use crate::str;
 // want `repr(transparent)` but we don't want it to show up in rustdoc, so we hide it under
 // `cfg(doc)`. This is an ad-hoc implementation of attribute privacy.
 #[cfg_attr(not(doc), repr(transparent))]
+#[allow(clippy::derived_hash_with_manual_eq)]
 pub struct CStr {
     // FIXME: this should not be represented with a DST slice but rather with
     //        just a raw `c_char` along with some form of marker to make
diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs
index 18c82f97c28..c8259c0024c 100644
--- a/library/core/src/intrinsics.rs
+++ b/library/core/src/intrinsics.rs
@@ -56,7 +56,7 @@
 
 use crate::marker::DiscriminantKind;
 use crate::marker::Tuple;
-use crate::mem::{self, align_of};
+use crate::mem::align_of;
 
 pub mod mir;
 pub mod simd;
@@ -1027,7 +1027,7 @@ extern "rust-intrinsic" {
 
     /// The size of the referenced value in bytes.
     ///
-    /// The stabilized version of this intrinsic is [`mem::size_of_val`].
+    /// The stabilized version of this intrinsic is [`crate::mem::size_of_val`].
     #[rustc_const_unstable(feature = "const_size_of_val", issue = "46571")]
     #[rustc_nounwind]
     pub fn size_of_val<T: ?Sized>(_: *const T) -> usize;
@@ -1107,7 +1107,7 @@ extern "rust-intrinsic" {
 
     /// Moves a value out of scope without running drop glue.
     ///
-    /// This exists solely for [`mem::forget_unsized`]; normal `forget` uses
+    /// This exists solely for [`crate::mem::forget_unsized`]; normal `forget` uses
     /// `ManuallyDrop` instead.
     ///
     /// Note that, unlike most intrinsics, this is safe to call;
@@ -1233,7 +1233,7 @@ extern "rust-intrinsic" {
     /// Depending on what the code is doing, the following alternatives are preferable to
     /// pointer-to-integer transmutation:
     /// - If the code just wants to store data of arbitrary type in some buffer and needs to pick a
-    ///   type for that buffer, it can use [`MaybeUninit`][mem::MaybeUninit].
+    ///   type for that buffer, it can use [`MaybeUninit`][crate::mem::MaybeUninit].
     /// - If the code actually wants to work on the address the pointer points to, it can use `as`
     ///   casts or [`ptr.addr()`][pointer::addr].
     ///
@@ -2317,7 +2317,7 @@ extern "rust-intrinsic" {
     /// Therefore, implementations must not require the user to uphold
     /// any safety invariants.
     ///
-    /// The to-be-stabilized version of this intrinsic is [`mem::variant_count`].
+    /// The to-be-stabilized version of this intrinsic is [`crate::mem::variant_count`].
     #[rustc_const_unstable(feature = "variant_count", issue = "73662")]
     #[rustc_safe_intrinsic]
     #[rustc_nounwind]
@@ -2569,6 +2569,19 @@ extern "rust-intrinsic" {
     #[rustc_nounwind]
     pub fn is_val_statically_known<T: Copy>(arg: T) -> bool;
 
+    /// Returns the value of `cfg!(debug_assertions)`, but after monomorphization instead of in
+    /// macro expansion.
+    ///
+    /// This always returns `false` in const eval and Miri. The interpreter provides better
+    /// diagnostics than the checks that this is used to implement. However, this means
+    /// you should only be using this intrinsic to guard requirements that, if violated,
+    /// immediately lead to UB. Otherwise, const-eval and Miri will miss out on those
+    /// checks entirely.
+    ///
+    /// Since this is evaluated after monomorphization, branching on this value can be used to
+    /// implement debug assertions that are included in the precompiled standard library, but can
+    /// be optimized out by builds that monomorphize the standard library code with debug
+    /// assertions disabled. This intrinsic is primarily used by [`assert_unsafe_precondition`].
     #[rustc_const_unstable(feature = "delayed_debug_assertions", issue = "none")]
     #[rustc_safe_intrinsic]
     #[cfg(not(bootstrap))]
@@ -2597,7 +2610,7 @@ pub(crate) const fn debug_assertions() -> bool {
 /// These checks are behind a condition which is evaluated at codegen time, not expansion time like
 /// [`debug_assert`]. This means that a standard library built with optimizations and debug
 /// assertions disabled will have these checks optimized out of its monomorphizations, but if a
-/// a caller of the standard library has debug assertions enabled and monomorphizes an expansion of
+/// caller of the standard library has debug assertions enabled and monomorphizes an expansion of
 /// this macro, that monomorphization will contain the check.
 ///
 /// Since these checks cannot be optimized out in MIR, some care must be taken in both call and
@@ -2606,8 +2619,8 @@ pub(crate) const fn debug_assertions() -> bool {
 /// combination of properties ensures that the code for the checks is only compiled once, and has a
 /// minimal impact on the caller's code size.
 ///
-/// Caller should also introducing any other `let` bindings or any code outside this macro in order
-/// to call it. Since the precompiled standard library is built with full debuginfo and these
+/// Callers should also avoid introducing any other `let` bindings or any code outside this macro in
+/// order to call it. Since the precompiled standard library is built with full debuginfo and these
 /// variables cannot be optimized out in MIR, an innocent-looking `let` can produce enough
 /// debuginfo to have a measurable compile-time impact on debug builds.
 ///
@@ -2659,33 +2672,12 @@ pub(crate) fn is_valid_allocation_size(size: usize, len: usize) -> bool {
     len <= max_len
 }
 
-pub(crate) fn is_nonoverlapping_mono(
-    src: *const (),
-    dst: *const (),
-    size: usize,
-    count: usize,
-) -> bool {
-    let src_usize = src.addr();
-    let dst_usize = dst.addr();
-    let Some(size) = size.checked_mul(count) else {
-        crate::panicking::panic_nounwind(
-            "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
-        )
-    };
-    let diff = src_usize.abs_diff(dst_usize);
-    // If the absolute distance between the ptrs is at least as big as the size of the buffer,
-    // they do not overlap.
-    diff >= size
-}
-
 /// Checks whether the regions of memory starting at `src` and `dst` of size
-/// `count * size_of::<T>()` do *not* overlap.
-#[inline]
-pub(crate) fn is_nonoverlapping<T>(src: *const T, dst: *const T, count: usize) -> bool {
+/// `count * size` do *not* overlap.
+pub(crate) fn is_nonoverlapping(src: *const (), dst: *const (), size: usize, count: usize) -> bool {
     let src_usize = src.addr();
     let dst_usize = dst.addr();
-    let Some(size) = mem::size_of::<T>().checked_mul(count) else {
-        // Use panic_nounwind instead of Option::expect, so that this function is nounwind.
+    let Some(size) = size.checked_mul(count) else {
         crate::panicking::panic_nounwind(
             "is_nonoverlapping: `size_of::<T>() * count` overflows a usize",
         )
@@ -2809,7 +2801,7 @@ pub const unsafe fn copy_nonoverlapping<T>(src: *const T, dst: *mut T, count: us
             ) =>
             is_aligned_and_not_null(src, align)
                 && is_aligned_and_not_null(dst, align)
-                && is_nonoverlapping_mono(src, dst, size, count)
+                && is_nonoverlapping(src, dst, size, count)
         );
         copy_nonoverlapping(src, dst, count)
     }
diff --git a/library/core/src/intrinsics/simd.rs b/library/core/src/intrinsics/simd.rs
index 0fd27974dce..ef4c65639eb 100644
--- a/library/core/src/intrinsics/simd.rs
+++ b/library/core/src/intrinsics/simd.rs
@@ -190,14 +190,27 @@ extern "platform-intrinsic" {
     ///
     /// `T` must be a vector.
     ///
-    /// `U` must be a const array of `i32`s.
+    /// `U` must be a **const** array of `i32`s. This means it must either refer to a named
+    /// const or be given as an inline const expression (`const { ... }`).
     ///
     /// `V` must be a vector with the same element type as `T` and the same length as `U`.
     ///
-    /// Concatenates `x` and `y`, then returns a new vector such that each element is selected from
-    /// the concatenation by the matching index in `idx`.
+    /// Returns a new vector such that element `i` is selected from `xy[idx[i]]`, where `xy`
+    /// is the concatenation of `x` and `y`. It is a compile-time error if `idx[i]` is out-of-bounds
+    /// of `xy`.
     pub fn simd_shuffle<T, U, V>(x: T, y: T, idx: U) -> V;
 
+    /// Shuffle two vectors by const indices.
+    ///
+    /// `T` must be a vector.
+    ///
+    /// `U` must be a vector with the same element type as `T` and the same length as `IDX`.
+    ///
+    /// Returns a new vector such that element `i` is selected from `xy[IDX[i]]`, where `xy`
+    /// is the concatenation of `x` and `y`. It is a compile-time error if `IDX[i]` is out-of-bounds
+    /// of `xy`.
+    pub fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
+
     /// Read a vector of pointers.
     ///
     /// `T` must be a vector.
@@ -232,6 +245,9 @@ extern "platform-intrinsic" {
     /// corresponding value in `val` to the pointer.
     /// Otherwise if the corresponding value in `mask` is `0`, do nothing.
     ///
+    /// The stores happen in left-to-right order.
+    /// (This is relevant in case two of the stores overlap.)
+    ///
     /// # Safety
     /// Unmasked values in `T` must be writeable as if by `<ptr>::write` (e.g. aligned to the element
     /// type).
@@ -468,4 +484,36 @@ extern "platform-intrinsic" {
     ///
     /// `T` must be a vector of integers.
     pub fn simd_cttz<T>(x: T) -> T;
+
+    /// Round up each element to the next highest integer-valued float.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_ceil<T>(x: T) -> T;
+
+    /// Round down each element to the next lowest integer-valued float.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_floor<T>(x: T) -> T;
+
+    /// Round each element to the closest integer-valued float.
+    /// Ties are resolved by rounding away from 0.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_round<T>(x: T) -> T;
+
+    /// Return the integer part of each element as an integer-valued float.
+    /// In other words, non-integer values are truncated towards zero.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_trunc<T>(x: T) -> T;
+
+    /// Takes the square root of each element.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_fsqrt<T>(x: T) -> T;
+
+    /// Computes `(x*y) + z` for each element, but without any intermediate rounding.
+    ///
+    /// `T` must be a vector of floats.
+    pub fn simd_fma<T>(x: T, y: T, z: T) -> T;
 }
diff --git a/library/core/src/num/f32.rs b/library/core/src/num/f32.rs
index 709eba2ffc9..047cb64ce50 100644
--- a/library/core/src/num/f32.rs
+++ b/library/core/src/num/f32.rs
@@ -462,6 +462,7 @@ impl f32 {
     /// and target platforms isn't guaranteed.
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
     #[rustc_diagnostic_item = "f32_nan"]
+    #[allow(clippy::eq_op)]
     pub const NAN: f32 = 0.0_f32 / 0.0_f32;
     /// Infinity (∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
@@ -483,6 +484,7 @@ impl f32 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     #[inline]
+    #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
     pub const fn is_nan(self) -> bool {
         self != self
     }
diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs
index 73fa61574cc..16d81941935 100644
--- a/library/core/src/num/f64.rs
+++ b/library/core/src/num/f64.rs
@@ -461,6 +461,7 @@ impl f64 {
     /// and target platforms isn't guaranteed.
     #[rustc_diagnostic_item = "f64_nan"]
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
+    #[allow(clippy::eq_op)]
     pub const NAN: f64 = 0.0_f64 / 0.0_f64;
     /// Infinity (∞).
     #[stable(feature = "assoc_int_consts", since = "1.43.0")]
@@ -482,6 +483,7 @@ impl f64 {
     #[stable(feature = "rust1", since = "1.0.0")]
     #[rustc_const_unstable(feature = "const_float_classify", issue = "72505")]
     #[inline]
+    #[allow(clippy::eq_op)] // > if you intended to check if the operand is NaN, use `.is_nan()` instead :)
     pub const fn is_nan(self) -> bool {
         self != self
     }
diff --git a/library/core/src/option.rs b/library/core/src/option.rs
index d4c40c49934..0e5eb03239c 100644
--- a/library/core/src/option.rs
+++ b/library/core/src/option.rs
@@ -567,6 +567,7 @@ use crate::{
 #[rustc_diagnostic_item = "Option"]
 #[lang = "Option"]
 #[stable(feature = "rust1", since = "1.0.0")]
+#[allow(clippy::derived_hash_with_manual_eq)] // PartialEq is specialized
 pub enum Option<T> {
     /// No value.
     #[lang = "None"]
diff --git a/library/core/src/primitive_docs.rs b/library/core/src/primitive_docs.rs
index 85595b059ad..eb3f93a6e96 100644
--- a/library/core/src/primitive_docs.rs
+++ b/library/core/src/primitive_docs.rs
@@ -1660,6 +1660,11 @@ mod prim_ref {}
 /// * [`UnwindSafe`]
 /// * [`RefUnwindSafe`]
 ///
+/// Note that while this type implements `PartialEq`, comparing function pointers is unreliable:
+/// pointers to the same function can compare inequal (because functions are duplicated in multiple
+/// codegen units), and pointers to *different* functions can compare equal (since identical
+/// functions can be deduplicated within a codegen unit).
+///
 /// [`Hash`]: hash::Hash
 /// [`Pointer`]: fmt::Pointer
 /// [`UnwindSafe`]: panic::UnwindSafe
diff --git a/library/core/src/ptr/metadata.rs b/library/core/src/ptr/metadata.rs
index a6a390db043..c7b0fe5694a 100644
--- a/library/core/src/ptr/metadata.rs
+++ b/library/core/src/ptr/metadata.rs
@@ -175,6 +175,11 @@ impl<T: ?Sized> Clone for PtrComponents<T> {
 ///
 /// It is possible to name this struct with a type parameter that is not a `dyn` trait object
 /// (for example `DynMetadata<u64>`) but not to obtain a meaningful value of that struct.
+///
+/// Note that while this type implements `PartialEq`, comparing vtable pointers is unreliable:
+/// pointers to vtables of the same type for the same trait can compare inequal (because vtables are
+/// duplicated in multiple codegen units), and pointers to vtables of *different* types/traits can
+/// compare equal (since identical vtables can be deduplicated within a codegen unit).
 #[lang = "dyn_metadata"]
 pub struct DynMetadata<Dyn: ?Sized> {
     vtable_ptr: &'static VTable,
diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs
index 0fb9017e6d9..2bd14f357d8 100644
--- a/library/core/src/ptr/mod.rs
+++ b/library/core/src/ptr/mod.rs
@@ -376,12 +376,14 @@
 //! [Stacked Borrows]: https://plv.mpi-sws.org/rustbelt/stacked-borrows/
 
 #![stable(feature = "rust1", since = "1.0.0")]
+// There are many unsafe functions taking pointers that don't dereference them.
+#![allow(clippy::not_unsafe_ptr_arg_deref)]
 
 use crate::cmp::Ordering;
 use crate::fmt;
 use crate::hash;
 use crate::intrinsics::{
-    self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping_mono,
+    self, assert_unsafe_precondition, is_aligned_and_not_null, is_nonoverlapping,
 };
 use crate::marker::FnPtr;
 
@@ -976,7 +978,7 @@ pub const unsafe fn swap_nonoverlapping<T>(x: *mut T, y: *mut T, count: usize) {
             ) =>
             is_aligned_and_not_null(x, align)
                 && is_aligned_and_not_null(y, align)
-                && is_nonoverlapping_mono(x, y, size, count)
+                && is_nonoverlapping(x, y, size, count)
         );
     }
 
diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs
index d9654973b84..1dec2bf40cc 100644
--- a/library/core/src/sync/atomic.rs
+++ b/library/core/src/sync/atomic.rs
@@ -216,6 +216,10 @@
 #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(dead_code))]
 #![cfg_attr(not(target_has_atomic_load_store = "8"), allow(unused_imports))]
 #![rustc_diagnostic_item = "atomic_mod"]
+// Clippy complains about the pattern of "safe function calling unsafe function taking pointers".
+// This happens with AtomicPtr intrinsics but is fine, as the pointers clippy is concerned about
+// are just normal values that get loaded/stored, but not dereferenced.
+#![allow(clippy::not_unsafe_ptr_arg_deref)]
 
 use self::Ordering::*;
 
diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs
index 9ad71e394ea..09f3f2f02ea 100644
--- a/library/core/src/task/wake.rs
+++ b/library/core/src/task/wake.rs
@@ -99,6 +99,12 @@ impl RawWaker {
 /// [`RawWaker`] implementation. Calling one of the contained functions using
 /// any other `data` pointer will cause undefined behavior.
 ///
+/// Note that while this type implements `PartialEq`, comparing function pointers, and hence
+/// comparing structs like this that contain function pointers, is unreliable: pointers to the same
+/// function can compare inequal (because functions are duplicated in multiple codegen units), and
+/// pointers to *different* functions can compare equal (since identical functions can be
+/// deduplicated within a codegen unit).
+///
 /// # Thread safety
 /// If the [`RawWaker`] will be used to construct a [`Waker`] then
 /// these functions must all be thread-safe (even though [`RawWaker`] is
diff --git a/library/core/src/time.rs b/library/core/src/time.rs
index e4f29942966..b533f539938 100644
--- a/library/core/src/time.rs
+++ b/library/core/src/time.rs
@@ -28,6 +28,14 @@ const NANOS_PER_MILLI: u32 = 1_000_000;
 const NANOS_PER_MICRO: u32 = 1_000;
 const MILLIS_PER_SEC: u64 = 1_000;
 const MICROS_PER_SEC: u64 = 1_000_000;
+#[unstable(feature = "duration_units", issue = "120301")]
+const SECS_PER_MINUTE: u64 = 60;
+#[unstable(feature = "duration_units", issue = "120301")]
+const MINS_PER_HOUR: u64 = 60;
+#[unstable(feature = "duration_units", issue = "120301")]
+const HOURS_PER_DAY: u64 = 24;
+#[unstable(feature = "duration_units", issue = "120301")]
+const DAYS_PER_WEEK: u64 = 7;
 
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
 #[repr(transparent)]
@@ -273,6 +281,11 @@ impl Duration {
 
     /// Creates a new `Duration` from the specified number of nanoseconds.
     ///
+    /// Note: Using this on the return value of `as_nanos()` might cause unexpected behavior:
+    /// `as_nanos()` returns a u128, and can return values that do not fit in u64, e.g. 585 years.
+    /// Instead, consider using the pattern `Duration::new(d.as_secs(), d.subsec_nanos())`
+    /// if you cannot copy/clone the Duration directly.
+    ///
     /// # Examples
     ///
     /// ```
@@ -291,6 +304,118 @@ impl Duration {
         Duration::new(nanos / (NANOS_PER_SEC as u64), (nanos % (NANOS_PER_SEC as u64)) as u32)
     }
 
+    /// Creates a new `Duration` from the specified number of weeks.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the given number of weeks overflows the `Duration` size.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constructors)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_weeks(4);
+    ///
+    /// assert_eq!(4 * 7 * 24 * 60 * 60, duration.as_secs());
+    /// assert_eq!(0, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_constructors", issue = "120301")]
+    #[must_use]
+    #[inline]
+    pub const fn from_weeks(weeks: u64) -> Duration {
+        if weeks > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR * HOURS_PER_DAY * DAYS_PER_WEEK) {
+            panic!("overflow in Duration::from_days");
+        }
+
+        Duration::from_secs(weeks * MINS_PER_HOUR * SECS_PER_MINUTE * HOURS_PER_DAY * DAYS_PER_WEEK)
+    }
+
+    /// Creates a new `Duration` from the specified number of days.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the given number of days overflows the `Duration` size.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constructors)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_days(7);
+    ///
+    /// assert_eq!(7 * 24 * 60 * 60, duration.as_secs());
+    /// assert_eq!(0, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_constructors", issue = "120301")]
+    #[must_use]
+    #[inline]
+    pub const fn from_days(days: u64) -> Duration {
+        if days > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR * HOURS_PER_DAY) {
+            panic!("overflow in Duration::from_days");
+        }
+
+        Duration::from_secs(days * MINS_PER_HOUR * SECS_PER_MINUTE * HOURS_PER_DAY)
+    }
+
+    /// Creates a new `Duration` from the specified number of hours.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the given number of hours overflows the `Duration` size.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constructors)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_hours(6);
+    ///
+    /// assert_eq!(6 * 60 * 60, duration.as_secs());
+    /// assert_eq!(0, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_constructors", issue = "120301")]
+    #[must_use]
+    #[inline]
+    pub const fn from_hours(hours: u64) -> Duration {
+        if hours > u64::MAX / (SECS_PER_MINUTE * MINS_PER_HOUR) {
+            panic!("overflow in Duration::from_hours");
+        }
+
+        Duration::from_secs(hours * MINS_PER_HOUR * SECS_PER_MINUTE)
+    }
+
+    /// Creates a new `Duration` from the specified number of minutes.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the given number of minutes overflows the `Duration` size.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(duration_constructors)]
+    /// use std::time::Duration;
+    ///
+    /// let duration = Duration::from_mins(10);
+    ///
+    /// assert_eq!(10 * 60, duration.as_secs());
+    /// assert_eq!(0, duration.subsec_nanos());
+    /// ```
+    #[unstable(feature = "duration_constructors", issue = "120301")]
+    #[must_use]
+    #[inline]
+    pub const fn from_mins(mins: u64) -> Duration {
+        if mins > u64::MAX / SECS_PER_MINUTE {
+            panic!("overflow in Duration::from_mins");
+        }
+
+        Duration::from_secs(mins * SECS_PER_MINUTE)
+    }
+
     /// Returns true if this `Duration` spans no time.
     ///
     /// # Examples
diff --git a/library/core/src/tuple.rs b/library/core/src/tuple.rs
index 44fac589d4c..8e961d8adc3 100644
--- a/library/core/src/tuple.rs
+++ b/library/core/src/tuple.rs
@@ -154,18 +154,6 @@ macro_rules! maybe_tuple_doc {
     };
 }
 
-#[inline]
-const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
-    // FIXME: Just use `==` once that's const-stable on `Option`s.
-    // This is mapping `None` to 2 and then doing the comparison afterwards
-    // because it optimizes better (`None::<Ordering>` is represented as 2).
-    x as i8
-        == match c {
-            Some(c) => c as i8,
-            None => 2,
-        }
-}
-
 // Constructs an expression that performs a lexical ordering using method `$rel`.
 // The values are interleaved, so the macro invocation for
 // `(a1, a2, a3) < (b1, b2, b3)` would be `lexical_ord!(lt, opt_is_lt, a1, b1,
@@ -176,7 +164,7 @@ const fn ordering_is_some(c: Option<Ordering>, x: Ordering) -> bool {
 macro_rules! lexical_ord {
     ($rel: ident, $ne_rel: ident, $a:expr, $b:expr, $($rest_a:expr, $rest_b:expr),+) => {{
         let c = PartialOrd::partial_cmp(&$a, &$b);
-        if !ordering_is_some(c, Equal) { ordering_is_some(c, $ne_rel) }
+        if c != Some(Equal) { c == Some($ne_rel) }
         else { lexical_ord!($rel, $ne_rel, $($rest_a, $rest_b),+) }
     }};
     ($rel: ident, $ne_rel: ident, $a:expr, $b:expr) => {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index 6deebc0d263..2fe79650dbf 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -32,6 +32,7 @@
 #![feature(duration_abs_diff)]
 #![feature(duration_consts_float)]
 #![feature(duration_constants)]
+#![feature(duration_constructors)]
 #![feature(exact_size_is_empty)]
 #![feature(extern_types)]
 #![feature(flt2dec)]
diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs
index 23f07bf84b3..fe7bb11c675 100644
--- a/library/core/tests/time.rs
+++ b/library/core/tests/time.rs
@@ -18,6 +18,49 @@ fn new_overflow() {
 }
 
 #[test]
+#[should_panic]
+fn from_mins_overflow() {
+    let overflow = u64::MAX / 60 + 1;
+    let _ = Duration::from_mins(overflow);
+}
+
+#[test]
+#[should_panic]
+fn from_hours_overflow() {
+    let overflow = u64::MAX / (60 * 60) + 1;
+    let _ = Duration::from_hours(overflow);
+}
+
+#[test]
+#[should_panic]
+fn from_days_overflow() {
+    let overflow = u64::MAX / (24 * 60 * 60) + 1;
+    let _ = Duration::from_days(overflow);
+}
+
+#[test]
+#[should_panic]
+fn from_weeks_overflow() {
+    let overflow = u64::MAX / (7 * 24 * 60 * 60) + 1;
+    let _ = Duration::from_weeks(overflow);
+}
+
+#[test]
+fn constructors() {
+    assert_eq!(Duration::from_weeks(1), Duration::from_secs(7 * 24 * 60 * 60));
+    assert_eq!(Duration::from_weeks(0), Duration::ZERO);
+
+    assert_eq!(Duration::from_days(1), Duration::from_secs(86_400));
+    assert_eq!(Duration::from_days(0), Duration::ZERO);
+
+    assert_eq!(Duration::from_hours(1), Duration::from_secs(3_600));
+    assert_eq!(Duration::from_hours(0), Duration::ZERO);
+
+    assert_eq!(Duration::from_mins(1), Duration::from_secs(60));
+    assert_eq!(Duration::from_mins(0), Duration::ZERO);
+}
+
+#[test]
 fn secs() {
     assert_eq!(Duration::new(0, 0).as_secs(), 0);
     assert_eq!(Duration::new(0, 500_000_005).as_secs(), 0);
diff --git a/library/proc_macro/src/bridge/arena.rs b/library/proc_macro/src/bridge/arena.rs
index fa72d2816eb..c2b046ae41e 100644
--- a/library/proc_macro/src/bridge/arena.rs
+++ b/library/proc_macro/src/bridge/arena.rs
@@ -102,6 +102,7 @@ impl Arena {
         }
     }
 
+    #[allow(clippy::mut_from_ref)] // arena allocator
     pub(crate) fn alloc_str<'a>(&'a self, string: &str) -> &'a mut str {
         let alloc = self.alloc_raw(string.len());
         let bytes = MaybeUninit::write_slice(alloc, string.as_bytes());
diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs
index 87e89a464bc..90b76cbc26e 100644
--- a/library/proc_macro/src/lib.rs
+++ b/library/proc_macro/src/lib.rs
@@ -201,6 +201,7 @@ impl ToString for TokenStream {
 /// `TokenTree::Punct`, or `TokenTree::Literal`.
 #[stable(feature = "proc_macro_lib", since = "1.15.0")]
 impl fmt::Display for TokenStream {
+    #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(&self.to_string())
     }
@@ -776,6 +777,7 @@ impl ToString for TokenTree {
 /// `TokenTree::Punct`, or `TokenTree::Literal`.
 #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
 impl fmt::Display for TokenTree {
+    #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(&self.to_string())
     }
@@ -906,6 +908,7 @@ impl ToString for Group {
 /// with `Delimiter::None` delimiters.
 #[stable(feature = "proc_macro_lib2", since = "1.29.0")]
 impl fmt::Display for Group {
+    #[allow(clippy::recursive_format_impl)] // clippy doesn't see the specialization
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         f.write_str(&self.to_string())
     }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 571e475c336..cab3e399ffa 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -339,12 +339,14 @@
 #![feature(portable_simd)]
 #![feature(prelude_2024)]
 #![feature(ptr_as_uninit)]
+#![feature(ptr_mask)]
 #![feature(slice_internals)]
 #![feature(slice_ptr_get)]
 #![feature(slice_range)]
 #![feature(std_internals)]
 #![feature(str_internals)]
 #![feature(strict_provenance)]
+#![feature(strict_provenance_atomic_ptr)]
 // tidy-alphabetical-end
 //
 // Library features (alloc):
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 24f2bdcf421..a4c2dc8b1ed 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -288,6 +288,7 @@ impl AsFd for fs::File {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<fs::File> for OwnedFd {
+    /// Takes ownership of a [`File`](fs::File)'s underlying file descriptor.
     #[inline]
     fn from(file: fs::File) -> OwnedFd {
         file.into_inner().into_inner().into_inner()
@@ -296,6 +297,8 @@ impl From<fs::File> for OwnedFd {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<OwnedFd> for fs::File {
+    /// Returns a [`File`](fs::File) that takes ownership of the given
+    /// file descriptor.
     #[inline]
     fn from(owned_fd: OwnedFd) -> Self {
         Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned_fd)))
@@ -312,6 +315,7 @@ impl AsFd for crate::net::TcpStream {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::TcpStream> for OwnedFd {
+    /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket file descriptor.
     #[inline]
     fn from(tcp_stream: crate::net::TcpStream) -> OwnedFd {
         tcp_stream.into_inner().into_socket().into_inner().into_inner().into()
@@ -338,6 +342,7 @@ impl AsFd for crate::net::TcpListener {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::TcpListener> for OwnedFd {
+    /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket file descriptor.
     #[inline]
     fn from(tcp_listener: crate::net::TcpListener) -> OwnedFd {
         tcp_listener.into_inner().into_socket().into_inner().into_inner().into()
@@ -364,6 +369,7 @@ impl AsFd for crate::net::UdpSocket {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::UdpSocket> for OwnedFd {
+    /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s file descriptor.
     #[inline]
     fn from(udp_socket: crate::net::UdpSocket) -> OwnedFd {
         udp_socket.into_inner().into_socket().into_inner().into_inner().into()
diff --git a/library/std/src/os/unix/net/datagram.rs b/library/std/src/os/unix/net/datagram.rs
index 34db54235f1..3b7b610fdf9 100644
--- a/library/std/src/os/unix/net/datagram.rs
+++ b/library/std/src/os/unix/net/datagram.rs
@@ -1024,6 +1024,7 @@ impl AsFd for UnixDatagram {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<UnixDatagram> for OwnedFd {
+    /// Takes ownership of a [`UnixDatagram`]'s socket file descriptor.
     #[inline]
     fn from(unix_datagram: UnixDatagram) -> OwnedFd {
         unsafe { OwnedFd::from_raw_fd(unix_datagram.into_raw_fd()) }
diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs
index ecc0bbce543..d64a43bc20b 100644
--- a/library/std/src/os/unix/net/listener.rs
+++ b/library/std/src/os/unix/net/listener.rs
@@ -346,6 +346,7 @@ impl From<OwnedFd> for UnixListener {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<UnixListener> for OwnedFd {
+    /// Takes ownership of a [`UnixListener`]'s socket file descriptor.
     #[inline]
     fn from(listener: UnixListener) -> OwnedFd {
         listener.0.into_inner().into_inner()
diff --git a/library/std/src/os/unix/net/stream.rs b/library/std/src/os/unix/net/stream.rs
index 41290e0017a..e117f616caf 100644
--- a/library/std/src/os/unix/net/stream.rs
+++ b/library/std/src/os/unix/net/stream.rs
@@ -752,6 +752,7 @@ impl AsFd for UnixStream {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<UnixStream> for OwnedFd {
+    /// Takes ownership of a [`UnixStream`]'s socket file descriptor.
     #[inline]
     fn from(unix_stream: UnixStream) -> OwnedFd {
         unsafe { OwnedFd::from_raw_fd(unix_stream.into_raw_fd()) }
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index ac551030492..e45457b2e42 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -362,6 +362,8 @@ impl FromRawFd for process::Stdio {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<OwnedFd> for process::Stdio {
+    /// Takes ownership of a file descriptor and returns a [`Stdio`](process::Stdio)
+    /// that can attach a stream to it.
     #[inline]
     fn from(fd: OwnedFd) -> process::Stdio {
         let fd = sys::fd::FileDesc::from_inner(fd);
@@ -428,6 +430,7 @@ impl AsFd for crate::process::ChildStdin {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStdin> for OwnedFd {
+    /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file descriptor.
     #[inline]
     fn from(child_stdin: crate::process::ChildStdin) -> OwnedFd {
         child_stdin.into_inner().into_inner().into_inner()
@@ -458,6 +461,7 @@ impl AsFd for crate::process::ChildStdout {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStdout> for OwnedFd {
+    /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file descriptor.
     #[inline]
     fn from(child_stdout: crate::process::ChildStdout) -> OwnedFd {
         child_stdout.into_inner().into_inner().into_inner()
@@ -488,6 +492,7 @@ impl AsFd for crate::process::ChildStderr {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStderr> for OwnedFd {
+    /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file descriptor.
     #[inline]
     fn from(child_stderr: crate::process::ChildStderr) -> OwnedFd {
         child_stderr.into_inner().into_inner().into_inner()
diff --git a/library/std/src/os/windows/io/handle.rs b/library/std/src/os/windows/io/handle.rs
index b0540872c0b..458c3bb036d 100644
--- a/library/std/src/os/windows/io/handle.rs
+++ b/library/std/src/os/windows/io/handle.rs
@@ -502,6 +502,7 @@ impl AsHandle for fs::File {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<fs::File> for OwnedHandle {
+    /// Takes ownership of a [`File`](fs::File)'s underlying file handle.
     #[inline]
     fn from(file: fs::File) -> OwnedHandle {
         file.into_inner().into_inner().into_inner()
@@ -510,6 +511,7 @@ impl From<fs::File> for OwnedHandle {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<OwnedHandle> for fs::File {
+    /// Returns a [`File`](fs::File) that takes ownership of the given handle.
     #[inline]
     fn from(owned: OwnedHandle) -> Self {
         Self::from_inner(FromInner::from_inner(FromInner::from_inner(owned)))
@@ -574,6 +576,7 @@ impl AsHandle for crate::process::ChildStdin {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStdin> for OwnedHandle {
+    /// Takes ownership of a [`ChildStdin`](crate::process::ChildStdin)'s file handle.
     #[inline]
     fn from(child_stdin: crate::process::ChildStdin) -> OwnedHandle {
         unsafe { OwnedHandle::from_raw_handle(child_stdin.into_raw_handle()) }
@@ -590,6 +593,7 @@ impl AsHandle for crate::process::ChildStdout {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStdout> for OwnedHandle {
+    /// Takes ownership of a [`ChildStdout`](crate::process::ChildStdout)'s file handle.
     #[inline]
     fn from(child_stdout: crate::process::ChildStdout) -> OwnedHandle {
         unsafe { OwnedHandle::from_raw_handle(child_stdout.into_raw_handle()) }
@@ -606,6 +610,7 @@ impl AsHandle for crate::process::ChildStderr {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::process::ChildStderr> for OwnedHandle {
+    /// Takes ownership of a [`ChildStderr`](crate::process::ChildStderr)'s file handle.
     #[inline]
     fn from(child_stderr: crate::process::ChildStderr) -> OwnedHandle {
         unsafe { OwnedHandle::from_raw_handle(child_stderr.into_raw_handle()) }
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 65f161f32e7..6ffdf907c8e 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -319,6 +319,7 @@ impl AsSocket for crate::net::TcpStream {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::TcpStream> for OwnedSocket {
+    /// Takes ownership of a [`TcpStream`](crate::net::TcpStream)'s socket.
     #[inline]
     fn from(tcp_stream: crate::net::TcpStream) -> OwnedSocket {
         unsafe { OwnedSocket::from_raw_socket(tcp_stream.into_raw_socket()) }
@@ -343,6 +344,7 @@ impl AsSocket for crate::net::TcpListener {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::TcpListener> for OwnedSocket {
+    /// Takes ownership of a [`TcpListener`](crate::net::TcpListener)'s socket.
     #[inline]
     fn from(tcp_listener: crate::net::TcpListener) -> OwnedSocket {
         unsafe { OwnedSocket::from_raw_socket(tcp_listener.into_raw_socket()) }
@@ -367,6 +369,7 @@ impl AsSocket for crate::net::UdpSocket {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<crate::net::UdpSocket> for OwnedSocket {
+    /// Takes ownership of a [`UdpSocket`](crate::net::UdpSocket)'s underlying socket.
     #[inline]
     fn from(udp_socket: crate::net::UdpSocket) -> OwnedSocket {
         unsafe { OwnedSocket::from_raw_socket(udp_socket.into_raw_socket()) }
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 5bf0154eae3..1be3acf5d43 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -24,6 +24,8 @@ impl FromRawHandle for process::Stdio {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<OwnedHandle> for process::Stdio {
+    /// Takes ownership of a handle and returns a [`Stdio`](process::Stdio)
+    /// that can attach a stream to it.
     fn from(handle: OwnedHandle) -> process::Stdio {
         let handle = sys::handle::Handle::from_inner(handle);
         let io = sys::process::Stdio::Handle(handle);
@@ -56,6 +58,7 @@ impl IntoRawHandle for process::Child {
 
 #[stable(feature = "io_safety", since = "1.63.0")]
 impl From<process::Child> for OwnedHandle {
+    /// Takes ownership of a [`Child`](process::Child)'s process handle.
     fn from(child: process::Child) -> OwnedHandle {
         child.into_inner().into_handle().into_inner()
     }
diff --git a/library/std/src/sys/cmath.rs b/library/std/src/sys/cmath.rs
new file mode 100644
index 00000000000..99df503b82d
--- /dev/null
+++ b/library/std/src/sys/cmath.rs
@@ -0,0 +1,88 @@
+#![cfg(not(test))]
+
+// These symbols are all defined by `libm`,
+// or by `compiler-builtins` on unsupported platforms.
+extern "C" {
+    pub fn acos(n: f64) -> f64;
+    pub fn asin(n: f64) -> f64;
+    pub fn atan(n: f64) -> f64;
+    pub fn atan2(a: f64, b: f64) -> f64;
+    pub fn cbrt(n: f64) -> f64;
+    pub fn cbrtf(n: f32) -> f32;
+    pub fn cosh(n: f64) -> f64;
+    pub fn expm1(n: f64) -> f64;
+    pub fn expm1f(n: f32) -> f32;
+    pub fn fdim(a: f64, b: f64) -> f64;
+    pub fn fdimf(a: f32, b: f32) -> f32;
+    #[cfg_attr(target_env = "msvc", link_name = "_hypot")]
+    pub fn hypot(x: f64, y: f64) -> f64;
+    #[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
+    pub fn hypotf(x: f32, y: f32) -> f32;
+    pub fn log1p(n: f64) -> f64;
+    pub fn log1pf(n: f32) -> f32;
+    pub fn sinh(n: f64) -> f64;
+    pub fn tan(n: f64) -> f64;
+    pub fn tanh(n: f64) -> f64;
+    pub fn tgamma(n: f64) -> f64;
+    pub fn tgammaf(n: f32) -> f32;
+    pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
+    pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
+
+    cfg_if::cfg_if! {
+    if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
+        pub fn acosf(n: f32) -> f32;
+        pub fn asinf(n: f32) -> f32;
+        pub fn atan2f(a: f32, b: f32) -> f32;
+        pub fn atanf(n: f32) -> f32;
+        pub fn coshf(n: f32) -> f32;
+        pub fn sinhf(n: f32) -> f32;
+        pub fn tanf(n: f32) -> f32;
+        pub fn tanhf(n: f32) -> f32;
+    }}
+}
+
+// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
+// which promote everything to f64, perform the calculation, and then demote
+// back to f32. While not precisely correct should be "correct enough" for now.
+cfg_if::cfg_if! {
+if #[cfg(all(target_os = "windows", target_env = "msvc", target_arch = "x86"))] {
+    #[inline]
+    pub unsafe fn acosf(n: f32) -> f32 {
+        f64::acos(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn asinf(n: f32) -> f32 {
+        f64::asin(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn atan2f(n: f32, b: f32) -> f32 {
+        f64::atan2(n as f64, b as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn atanf(n: f32) -> f32 {
+        f64::atan(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn coshf(n: f32) -> f32 {
+        f64::cosh(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn sinhf(n: f32) -> f32 {
+        f64::sinh(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn tanf(n: f32) -> f32 {
+        f64::tan(n as f64) as f32
+    }
+
+    #[inline]
+    pub unsafe fn tanhf(n: f32) -> f32 {
+        f64::tanh(n as f64) as f32
+    }
+}}
diff --git a/library/std/src/sys/cmath/builtins.rs b/library/std/src/sys/cmath/builtins.rs
deleted file mode 100644
index c680132efa4..00000000000
--- a/library/std/src/sys/cmath/builtins.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-// These symbols are all defined by `libm`,
-// or by `compiler-builtins` on unsupported platforms.
-
-extern "C" {
-    pub fn acos(n: f64) -> f64;
-    pub fn acosf(n: f32) -> f32;
-    pub fn asin(n: f64) -> f64;
-    pub fn asinf(n: f32) -> f32;
-    pub fn atan(n: f64) -> f64;
-    pub fn atan2(a: f64, b: f64) -> f64;
-    pub fn atan2f(a: f32, b: f32) -> f32;
-    pub fn atanf(n: f32) -> f32;
-    pub fn cbrt(n: f64) -> f64;
-    pub fn cbrtf(n: f32) -> f32;
-    pub fn cosh(n: f64) -> f64;
-    pub fn coshf(n: f32) -> f32;
-    pub fn expm1(n: f64) -> f64;
-    pub fn expm1f(n: f32) -> f32;
-    pub fn fdim(a: f64, b: f64) -> f64;
-    pub fn fdimf(a: f32, b: f32) -> f32;
-    pub fn hypot(x: f64, y: f64) -> f64;
-    pub fn hypotf(x: f32, y: f32) -> f32;
-    pub fn log1p(n: f64) -> f64;
-    pub fn log1pf(n: f32) -> f32;
-    pub fn sinh(n: f64) -> f64;
-    pub fn sinhf(n: f32) -> f32;
-    pub fn tan(n: f64) -> f64;
-    pub fn tanf(n: f32) -> f32;
-    pub fn tanh(n: f64) -> f64;
-    pub fn tanhf(n: f32) -> f32;
-    pub fn tgamma(n: f64) -> f64;
-    pub fn tgammaf(n: f32) -> f32;
-    pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
-    pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
-}
diff --git a/library/std/src/sys/cmath/mod.rs b/library/std/src/sys/cmath/mod.rs
deleted file mode 100644
index 79d5021dd8d..00000000000
--- a/library/std/src/sys/cmath/mod.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-#![cfg(not(test))]
-
-cfg_if::cfg_if! {
-    if #[cfg(target_os = "windows")] {
-        mod windows;
-        pub use windows::*;
-    } else {
-        mod builtins;
-        pub use builtins::*;
-    }
-}
diff --git a/library/std/src/sys/cmath/windows.rs b/library/std/src/sys/cmath/windows.rs
deleted file mode 100644
index 712097f06ff..00000000000
--- a/library/std/src/sys/cmath/windows.rs
+++ /dev/null
@@ -1,94 +0,0 @@
-use core::ffi::{c_double, c_float, c_int};
-
-extern "C" {
-    pub fn acos(n: c_double) -> c_double;
-    pub fn asin(n: c_double) -> c_double;
-    pub fn atan(n: c_double) -> c_double;
-    pub fn atan2(a: c_double, b: c_double) -> c_double;
-    pub fn cbrt(n: c_double) -> c_double;
-    pub fn cbrtf(n: c_float) -> c_float;
-    pub fn cosh(n: c_double) -> c_double;
-    pub fn expm1(n: c_double) -> c_double;
-    pub fn expm1f(n: c_float) -> c_float;
-    pub fn fdim(a: c_double, b: c_double) -> c_double;
-    pub fn fdimf(a: c_float, b: c_float) -> c_float;
-    #[cfg_attr(target_env = "msvc", link_name = "_hypot")]
-    pub fn hypot(x: c_double, y: c_double) -> c_double;
-    #[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
-    pub fn hypotf(x: c_float, y: c_float) -> c_float;
-    pub fn log1p(n: c_double) -> c_double;
-    pub fn log1pf(n: c_float) -> c_float;
-    pub fn sinh(n: c_double) -> c_double;
-    pub fn tan(n: c_double) -> c_double;
-    pub fn tanh(n: c_double) -> c_double;
-    pub fn tgamma(n: c_double) -> c_double;
-    pub fn tgammaf(n: c_float) -> c_float;
-    pub fn lgamma_r(n: c_double, s: &mut c_int) -> c_double;
-    pub fn lgammaf_r(n: c_float, s: &mut c_int) -> c_float;
-}
-
-pub use self::shims::*;
-
-#[cfg(not(all(target_env = "msvc", target_arch = "x86")))]
-mod shims {
-    use core::ffi::c_float;
-
-    extern "C" {
-        pub fn acosf(n: c_float) -> c_float;
-        pub fn asinf(n: c_float) -> c_float;
-        pub fn atan2f(a: c_float, b: c_float) -> c_float;
-        pub fn atanf(n: c_float) -> c_float;
-        pub fn coshf(n: c_float) -> c_float;
-        pub fn sinhf(n: c_float) -> c_float;
-        pub fn tanf(n: c_float) -> c_float;
-        pub fn tanhf(n: c_float) -> c_float;
-    }
-}
-
-// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
-// which promote everything to f64, perform the calculation, and then demote
-// back to f32. While not precisely correct should be "correct enough" for now.
-#[cfg(all(target_env = "msvc", target_arch = "x86"))]
-mod shims {
-    use core::ffi::c_float;
-
-    #[inline]
-    pub unsafe fn acosf(n: c_float) -> c_float {
-        f64::acos(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn asinf(n: c_float) -> c_float {
-        f64::asin(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
-        f64::atan2(n as f64, b as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn atanf(n: c_float) -> c_float {
-        f64::atan(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn coshf(n: c_float) -> c_float {
-        f64::cosh(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn sinhf(n: c_float) -> c_float {
-        f64::sinh(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn tanf(n: c_float) -> c_float {
-        f64::tan(n as f64) as c_float
-    }
-
-    #[inline]
-    pub unsafe fn tanhf(n: c_float) -> c_float {
-        f64::tanh(n as f64) as c_float
-    }
-}
diff --git a/library/std/src/sys/pal/unix/locks/mod.rs b/library/std/src/sys/pal/unix/locks/mod.rs
index b2e0e49ad73..a49247310b5 100644
--- a/library/std/src/sys/pal/unix/locks/mod.rs
+++ b/library/std/src/sys/pal/unix/locks/mod.rs
@@ -22,10 +22,10 @@ cfg_if::cfg_if! {
         pub(crate) use futex_condvar::Condvar;
     } else {
         mod pthread_mutex;
-        mod pthread_rwlock;
         mod pthread_condvar;
+        mod queue_rwlock;
         pub(crate) use pthread_mutex::Mutex;
-        pub(crate) use pthread_rwlock::RwLock;
+        pub(crate) use queue_rwlock::RwLock;
         pub(crate) use pthread_condvar::Condvar;
     }
 }
diff --git a/library/std/src/sys/pal/unix/locks/pthread_rwlock.rs b/library/std/src/sys/pal/unix/locks/pthread_rwlock.rs
deleted file mode 100644
index 04662be9d82..00000000000
--- a/library/std/src/sys/pal/unix/locks/pthread_rwlock.rs
+++ /dev/null
@@ -1,195 +0,0 @@
-use crate::cell::UnsafeCell;
-use crate::mem::forget;
-use crate::sync::atomic::{AtomicUsize, Ordering};
-use crate::sys_common::lazy_box::{LazyBox, LazyInit};
-
-struct AllocatedRwLock {
-    inner: UnsafeCell<libc::pthread_rwlock_t>,
-    write_locked: UnsafeCell<bool>, // guarded by the `inner` RwLock
-    num_readers: AtomicUsize,
-}
-
-unsafe impl Send for AllocatedRwLock {}
-unsafe impl Sync for AllocatedRwLock {}
-
-pub struct RwLock {
-    inner: LazyBox<AllocatedRwLock>,
-}
-
-impl LazyInit for AllocatedRwLock {
-    fn init() -> Box<Self> {
-        Box::new(AllocatedRwLock {
-            inner: UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER),
-            write_locked: UnsafeCell::new(false),
-            num_readers: AtomicUsize::new(0),
-        })
-    }
-
-    fn destroy(mut rwlock: Box<Self>) {
-        // We're not allowed to pthread_rwlock_destroy a locked rwlock,
-        // so check first if it's unlocked.
-        if *rwlock.write_locked.get_mut() || *rwlock.num_readers.get_mut() != 0 {
-            // The rwlock is locked. This happens if a RwLock{Read,Write}Guard is leaked.
-            // In this case, we just leak the RwLock too.
-            forget(rwlock);
-        }
-    }
-
-    fn cancel_init(_: Box<Self>) {
-        // In this case, we can just drop it without any checks,
-        // since it cannot have been locked yet.
-    }
-}
-
-impl AllocatedRwLock {
-    #[inline]
-    unsafe fn raw_unlock(&self) {
-        let r = libc::pthread_rwlock_unlock(self.inner.get());
-        debug_assert_eq!(r, 0);
-    }
-}
-
-impl Drop for AllocatedRwLock {
-    fn drop(&mut self) {
-        let r = unsafe { libc::pthread_rwlock_destroy(self.inner.get()) };
-        // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a
-        // rwlock that was just initialized with
-        // libc::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked)
-        // or pthread_rwlock_init() is called, this behaviour no longer occurs.
-        if cfg!(target_os = "dragonfly") {
-            debug_assert!(r == 0 || r == libc::EINVAL);
-        } else {
-            debug_assert_eq!(r, 0);
-        }
-    }
-}
-
-impl RwLock {
-    #[inline]
-    pub const fn new() -> RwLock {
-        RwLock { inner: LazyBox::new() }
-    }
-
-    #[inline]
-    pub fn read(&self) {
-        let lock = &*self.inner;
-        let r = unsafe { libc::pthread_rwlock_rdlock(lock.inner.get()) };
-
-        // According to POSIX, when a thread tries to acquire this read lock
-        // while it already holds the write lock
-        // (or vice versa, or tries to acquire the write lock twice),
-        // "the call shall either deadlock or return [EDEADLK]"
-        // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html,
-        // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html).
-        // So, in principle, all we have to do here is check `r == 0` to be sure we properly
-        // got the lock.
-        //
-        // However, (at least) glibc before version 2.25 does not conform to this spec,
-        // and can return `r == 0` even when this thread already holds the write lock.
-        // We thus check for this situation ourselves and panic when detecting that a thread
-        // got the write lock more than once, or got a read and a write lock.
-        if r == libc::EAGAIN {
-            panic!("rwlock maximum reader count exceeded");
-        } else if r == libc::EDEADLK || (r == 0 && unsafe { *lock.write_locked.get() }) {
-            // Above, we make sure to only access `write_locked` when `r == 0` to avoid
-            // data races.
-            if r == 0 {
-                // `pthread_rwlock_rdlock` succeeded when it should not have.
-                unsafe {
-                    lock.raw_unlock();
-                }
-            }
-            panic!("rwlock read lock would result in deadlock");
-        } else {
-            // POSIX does not make guarantees about all the errors that may be returned.
-            // See issue #94705 for more details.
-            assert_eq!(r, 0, "unexpected error during rwlock read lock: {:?}", r);
-            lock.num_readers.fetch_add(1, Ordering::Relaxed);
-        }
-    }
-
-    #[inline]
-    pub fn try_read(&self) -> bool {
-        let lock = &*self.inner;
-        let r = unsafe { libc::pthread_rwlock_tryrdlock(lock.inner.get()) };
-        if r == 0 {
-            if unsafe { *lock.write_locked.get() } {
-                // `pthread_rwlock_tryrdlock` succeeded when it should not have.
-                unsafe {
-                    lock.raw_unlock();
-                }
-                false
-            } else {
-                lock.num_readers.fetch_add(1, Ordering::Relaxed);
-                true
-            }
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub fn write(&self) {
-        let lock = &*self.inner;
-        let r = unsafe { libc::pthread_rwlock_wrlock(lock.inner.get()) };
-        // See comments above for why we check for EDEADLK and write_locked. For the same reason,
-        // we also need to check that there are no readers (tracked in `num_readers`).
-        if r == libc::EDEADLK
-            || (r == 0 && unsafe { *lock.write_locked.get() })
-            || lock.num_readers.load(Ordering::Relaxed) != 0
-        {
-            // Above, we make sure to only access `write_locked` when `r == 0` to avoid
-            // data races.
-            if r == 0 {
-                // `pthread_rwlock_wrlock` succeeded when it should not have.
-                unsafe {
-                    lock.raw_unlock();
-                }
-            }
-            panic!("rwlock write lock would result in deadlock");
-        } else {
-            // According to POSIX, for a properly initialized rwlock this can only
-            // return EDEADLK or 0. We rely on that.
-            debug_assert_eq!(r, 0);
-        }
-
-        unsafe {
-            *lock.write_locked.get() = true;
-        }
-    }
-
-    #[inline]
-    pub unsafe fn try_write(&self) -> bool {
-        let lock = &*self.inner;
-        let r = libc::pthread_rwlock_trywrlock(lock.inner.get());
-        if r == 0 {
-            if *lock.write_locked.get() || lock.num_readers.load(Ordering::Relaxed) != 0 {
-                // `pthread_rwlock_trywrlock` succeeded when it should not have.
-                lock.raw_unlock();
-                false
-            } else {
-                *lock.write_locked.get() = true;
-                true
-            }
-        } else {
-            false
-        }
-    }
-
-    #[inline]
-    pub unsafe fn read_unlock(&self) {
-        let lock = &*self.inner;
-        debug_assert!(!*lock.write_locked.get());
-        lock.num_readers.fetch_sub(1, Ordering::Relaxed);
-        lock.raw_unlock();
-    }
-
-    #[inline]
-    pub unsafe fn write_unlock(&self) {
-        let lock = &*self.inner;
-        debug_assert_eq!(lock.num_readers.load(Ordering::Relaxed), 0);
-        debug_assert!(*lock.write_locked.get());
-        *lock.write_locked.get() = false;
-        lock.raw_unlock();
-    }
-}
diff --git a/library/std/src/sys/pal/unix/locks/queue_rwlock.rs b/library/std/src/sys/pal/unix/locks/queue_rwlock.rs
new file mode 100644
index 00000000000..0f02a98dfdd
--- /dev/null
+++ b/library/std/src/sys/pal/unix/locks/queue_rwlock.rs
@@ -0,0 +1,557 @@
+//! Efficient read-write locking without `pthread_rwlock_t`.
+//!
+//! The readers-writer lock provided by the `pthread` library has a number of
+//! problems which make it a suboptimal choice for `std`:
+//!
+//! * It is non-movable, so it needs to be allocated (lazily, to make the
+//! constructor `const`).
+//! * `pthread` is an external library, meaning the fast path of acquiring an
+//! uncontended lock cannot be inlined.
+//! * Some platforms (at least glibc before version 2.25) have buggy implementations
+//! that can easily lead to undefined behaviour in safe Rust code when not properly
+//! guarded against.
+//! * On some platforms (e.g. macOS), the lock is very slow.
+//!
+//! Therefore, we implement our own `RwLock`! Naively, one might reach for a
+//! spinlock, but those [can be quite problematic] when the lock is contended.
+//! Instead, this readers-writer lock copies its implementation strategy from
+//! the Windows [SRWLOCK] and the [usync] library. Spinning is still used for the
+//! fast path, but it is bounded: after spinning fails, threads will locklessly
+//! add an information structure containing a [`Thread`] handle into a queue of
+//! waiters associated with the lock. The lock owner, upon releasing the lock,
+//! will scan through the queue and wake up threads as appropriate, which will
+//! then again try to acquire the lock. The resulting [`RwLock`] is:
+//!
+//! * adaptive, since it spins before doing any heavywheight parking operations
+//! * allocation-free, modulo the per-thread [`Thread`] handle, which is
+//! allocated regardless when using threads created by `std`
+//! * writer-preferring, even if some readers may still slip through
+//! * unfair, which reduces context-switching and thus drastically improves
+//! performance
+//!
+//! and also quite fast in most cases.
+//!
+//! [can be quite problematic]: https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html
+//! [SRWLOCK]: https://learn.microsoft.com/en-us/windows/win32/sync/slim-reader-writer--srw--locks
+//! [usync]: https://crates.io/crates/usync
+//!
+//! # Implementation
+//!
+//! ## State
+//!
+//! A single [`AtomicPtr`] is used as state variable. The lowest three bits are used
+//! to indicate the meaning of the remaining bits:
+//!
+//! | [`LOCKED`] | [`QUEUED`] | [`QUEUE_LOCKED`] | Remaining    |                                                                                                                             |
+//! |:-----------|:-----------|:-----------------|:-------------|:----------------------------------------------------------------------------------------------------------------------------|
+//! | 0          | 0          | 0                | 0            | The lock is unlocked, no threads are waiting                                                                                |
+//! | 1          | 0          | 0                | 0            | The lock is write-locked, no threads waiting                                                                                |
+//! | 1          | 0          | 0                | n > 0        | The lock is read-locked with n readers                                                                                      |
+//! | 0          | 1          | *                | `*mut Node`  | The lock is unlocked, but some threads are waiting. Only writers may lock the lock                                          |
+//! | 1          | 1          | *                | `*mut Node`  | The lock is locked, but some threads are waiting. If the lock is read-locked, the last queue node contains the reader count |
+//!
+//! ## Waiter queue
+//!
+//! When threads are waiting on the lock (`QUEUE` is set), the lock state
+//! points to a queue of waiters, which is implemented as a linked list of
+//! nodes stored on the stack to avoid memory allocation. To enable lockless
+//! enqueuing of new nodes to the queue, the linked list is single-linked upon
+//! creation. Since when the lock is read-locked, the lock count is stored in
+//! the last link of the queue, threads have to traverse the queue to find the
+//! last element upon releasing the lock. To avoid having to traverse the whole
+//! list again and again, a pointer to the found tail is cached in the (current)
+//! first element of the queue.
+//!
+//! Also, while the lock is unfair for performance reasons, it is still best to
+//! wake the tail node first, which requires backlinks to previous nodes to be
+//! created. This is done at the same time as finding the tail, and thus a set
+//! tail field indicates the remaining portion of the queue is initialized.
+//!
+//! TLDR: Here's a diagram of what the queue looks like:
+//!
+//! ```text
+//! state
+//!   │
+//!   ▼
+//! ╭───────╮ next ╭───────╮ next ╭───────╮ next ╭───────╮
+//! │       ├─────►│       ├─────►│       ├─────►│ count │
+//! │       │      │       │      │       │      │       │
+//! │       │      │       │◄─────┤       │◄─────┤       │
+//! ╰───────╯      ╰───────╯ prev ╰───────╯ prev ╰───────╯
+//!                      │                           ▲
+//!                      └───────────────────────────┘
+//!                                  tail
+//! ```
+//!
+//! Invariants:
+//! 1. At least one node must contain a non-null, current `tail` field.
+//! 2. The first non-null `tail` field must be valid and current.
+//! 3. All nodes preceding this node must have a correct, non-null `next` field.
+//! 4. All nodes following this node must have a correct, non-null `prev` field.
+//!
+//! Access to the queue is controlled by the `QUEUE_LOCKED` bit, which threads
+//! try to set both after enqueuing themselves to eagerly add backlinks to the
+//! queue, which drastically improves performance, and after unlocking the lock
+//! to wake the next waiter(s). This is done atomically at the same time as the
+//! enqueuing/unlocking operation. The thread releasing the `QUEUE_LOCK` bit
+//! will check the state of the lock and wake up waiters as appropriate. This
+//! guarantees forward-progress even if the unlocking thread could not acquire
+//! the queue lock.
+//!
+//! ## Memory orderings
+//!
+//! To properly synchronize changes to the data protected by the lock, the lock
+//! is acquired and released with [`Acquire`] and [`Release`] ordering, respectively.
+//! To propagate the initialization of nodes, changes to the queue lock are also
+//! performed using these orderings.
+
+#![forbid(unsafe_op_in_unsafe_fn)]
+
+use crate::cell::OnceCell;
+use crate::hint::spin_loop;
+use crate::mem;
+use crate::ptr::{self, invalid_mut, null_mut, NonNull};
+use crate::sync::atomic::{
+    AtomicBool, AtomicPtr,
+    Ordering::{AcqRel, Acquire, Relaxed, Release},
+};
+use crate::sys_common::thread_info;
+use crate::thread::Thread;
+
+// Locking uses exponential backoff. `SPIN_COUNT` indicates how many times the
+// locking operation will be retried.
+// `spin_loop` will be called `2.pow(SPIN_COUNT) - 1` times.
+const SPIN_COUNT: usize = 7;
+
+type State = *mut ();
+type AtomicState = AtomicPtr<()>;
+
+const UNLOCKED: State = invalid_mut(0);
+const LOCKED: usize = 1;
+const QUEUED: usize = 2;
+const QUEUE_LOCKED: usize = 4;
+const SINGLE: usize = 8;
+const MASK: usize = !(QUEUE_LOCKED | QUEUED | LOCKED);
+
+/// Marks the state as write-locked, if possible.
+#[inline]
+fn write_lock(state: State) -> Option<State> {
+    let state = state.wrapping_byte_add(LOCKED);
+    if state.addr() & LOCKED == LOCKED { Some(state) } else { None }
+}
+
+/// Marks the state as read-locked, if possible.
+#[inline]
+fn read_lock(state: State) -> Option<State> {
+    if state.addr() & QUEUED == 0 && state.addr() != LOCKED {
+        Some(invalid_mut(state.addr().checked_add(SINGLE)? | LOCKED))
+    } else {
+        None
+    }
+}
+
+/// Masks the state, assuming it points to a queue node.
+///
+/// # Safety
+/// The state must contain a valid pointer to a queue node.
+#[inline]
+unsafe fn to_node(state: State) -> NonNull<Node> {
+    unsafe { NonNull::new_unchecked(state.mask(MASK)).cast() }
+}
+
+/// An atomic node pointer with relaxed operations.
+struct AtomicLink(AtomicPtr<Node>);
+
+impl AtomicLink {
+    fn new(v: Option<NonNull<Node>>) -> AtomicLink {
+        AtomicLink(AtomicPtr::new(v.map_or(null_mut(), NonNull::as_ptr)))
+    }
+
+    fn get(&self) -> Option<NonNull<Node>> {
+        NonNull::new(self.0.load(Relaxed))
+    }
+
+    fn set(&self, v: Option<NonNull<Node>>) {
+        self.0.store(v.map_or(null_mut(), NonNull::as_ptr), Relaxed);
+    }
+}
+
+#[repr(align(8))]
+struct Node {
+    next: AtomicLink,
+    prev: AtomicLink,
+    tail: AtomicLink,
+    write: bool,
+    thread: OnceCell<Thread>,
+    completed: AtomicBool,
+}
+
+impl Node {
+    /// Create a new queue node.
+    fn new(write: bool) -> Node {
+        Node {
+            next: AtomicLink::new(None),
+            prev: AtomicLink::new(None),
+            tail: AtomicLink::new(None),
+            write,
+            thread: OnceCell::new(),
+            completed: AtomicBool::new(false),
+        }
+    }
+
+    /// Prepare this node for waiting.
+    fn prepare(&mut self) {
+        // Fall back to creating an unnamed `Thread` handle to allow locking in
+        // TLS destructors.
+        self.thread
+            .get_or_init(|| thread_info::current_thread().unwrap_or_else(|| Thread::new(None)));
+        self.completed = AtomicBool::new(false);
+    }
+
+    /// Wait until this node is marked as completed.
+    ///
+    /// # Safety
+    /// May only be called from the thread that created the node.
+    unsafe fn wait(&self) {
+        while !self.completed.load(Acquire) {
+            unsafe {
+                self.thread.get().unwrap().park();
+            }
+        }
+    }
+
+    /// Atomically mark this node as completed. The node may not outlive this call.
+    unsafe fn complete(this: NonNull<Node>) {
+        // Since the node may be destroyed immediately after the completed flag
+        // is set, clone the thread handle before that.
+        let thread = unsafe { this.as_ref().thread.get().unwrap().clone() };
+        unsafe {
+            this.as_ref().completed.store(true, Release);
+        }
+        thread.unpark();
+    }
+}
+
+struct PanicGuard;
+
+impl Drop for PanicGuard {
+    fn drop(&mut self) {
+        rtabort!("tried to drop node in intrusive list.");
+    }
+}
+
+/// Add backlinks to the queue, returning the tail.
+///
+/// May be called from multiple threads at the same time, while the queue is not
+/// modified (this happens when unlocking multiple readers).
+///
+/// # Safety
+/// * `head` must point to a node in a valid queue.
+/// * `head` must be or be in front of the head of the queue at the time of the
+/// last removal.
+/// * The part of the queue starting with `head` must not be modified during this
+/// call.
+unsafe fn add_backlinks_and_find_tail(head: NonNull<Node>) -> NonNull<Node> {
+    let mut current = head;
+    let tail = loop {
+        let c = unsafe { current.as_ref() };
+        match c.tail.get() {
+            Some(tail) => break tail,
+            // SAFETY:
+            // All `next` fields before the first node with a `set` tail are
+            // non-null and valid (invariant 3).
+            None => unsafe {
+                let next = c.next.get().unwrap_unchecked();
+                next.as_ref().prev.set(Some(current));
+                current = next;
+            },
+        }
+    };
+
+    unsafe {
+        head.as_ref().tail.set(Some(tail));
+        tail
+    }
+}
+
+pub struct RwLock {
+    state: AtomicState,
+}
+
+impl RwLock {
+    #[inline]
+    pub const fn new() -> RwLock {
+        RwLock { state: AtomicPtr::new(UNLOCKED) }
+    }
+
+    #[inline]
+    pub fn try_read(&self) -> bool {
+        self.state.fetch_update(Acquire, Relaxed, read_lock).is_ok()
+    }
+
+    #[inline]
+    pub fn read(&self) {
+        if !self.try_read() {
+            self.lock_contended(false)
+        }
+    }
+
+    #[inline]
+    pub fn try_write(&self) -> bool {
+        // Atomically set the `LOCKED` bit. This is lowered to a single atomic
+        // instruction on most modern processors (e.g. "lock bts" on x86 and
+        // "ldseta" on modern AArch64), and therefore is more efficient than
+        // `fetch_update(lock(true))`, which can spuriously fail if a new node
+        // is appended to the queue.
+        self.state.fetch_or(LOCKED, Acquire).addr() & LOCKED == 0
+    }
+
+    #[inline]
+    pub fn write(&self) {
+        if !self.try_write() {
+            self.lock_contended(true)
+        }
+    }
+
+    #[cold]
+    fn lock_contended(&self, write: bool) {
+        let update = if write { write_lock } else { read_lock };
+        let mut node = Node::new(write);
+        let mut state = self.state.load(Relaxed);
+        let mut count = 0;
+        loop {
+            if let Some(next) = update(state) {
+                // The lock is available, try locking it.
+                match self.state.compare_exchange_weak(state, next, Acquire, Relaxed) {
+                    Ok(_) => return,
+                    Err(new) => state = new,
+                }
+            } else if state.addr() & QUEUED == 0 && count < SPIN_COUNT {
+                // If the lock is not available and no threads are queued, spin
+                // for a while, using exponential backoff to decrease cache
+                // contention.
+                for _ in 0..(1 << count) {
+                    spin_loop();
+                }
+                state = self.state.load(Relaxed);
+                count += 1;
+            } else {
+                // Fall back to parking. First, prepare the node.
+                node.prepare();
+
+                // If there are threads queued, set the `next` field to a
+                // pointer to the next node in the queue. Otherwise set it to
+                // the lock count if the state is read-locked or to zero if it
+                // is write-locked.
+                node.next.0 = AtomicPtr::new(state.mask(MASK).cast());
+                node.prev = AtomicLink::new(None);
+                let mut next = ptr::from_ref(&node)
+                    .map_addr(|addr| addr | QUEUED | (state.addr() & LOCKED))
+                    as State;
+
+                if state.addr() & QUEUED == 0 {
+                    // If this is the first node in the queue, set the tail field to
+                    // the node itself to ensure there is a current `tail` field in
+                    // the queue (invariants 1 and 2). This needs to use `set` to
+                    // avoid invalidating the new pointer.
+                    node.tail.set(Some(NonNull::from(&node)));
+                } else {
+                    // Otherwise, the tail of the queue is not known.
+                    node.tail.set(None);
+                    // Try locking the queue to eagerly add backlinks.
+                    next = next.map_addr(|addr| addr | QUEUE_LOCKED);
+                }
+
+                // Register the node, using release ordering to propagate our
+                // changes to the waking thread.
+                if let Err(new) = self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
+                    // The state has changed, just try again.
+                    state = new;
+                    continue;
+                }
+
+                // The node is registered, so the structure must not be
+                // mutably accessed or destroyed while other threads may
+                // be accessing it. Guard against unwinds using a panic
+                // guard that aborts when dropped.
+                let guard = PanicGuard;
+
+                // If the current thread locked the queue, unlock it again,
+                // linking it in the process.
+                if state.addr() & (QUEUE_LOCKED | QUEUED) == QUEUED {
+                    unsafe {
+                        self.unlock_queue(next);
+                    }
+                }
+
+                // Wait until the node is removed from the queue.
+                // SAFETY: the node was created by the current thread.
+                unsafe {
+                    node.wait();
+                }
+
+                // The node was removed from the queue, disarm the guard.
+                mem::forget(guard);
+
+                // Reload the state and try again.
+                state = self.state.load(Relaxed);
+                count = 0;
+            }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn read_unlock(&self) {
+        match self.state.fetch_update(Release, Acquire, |state| {
+            if state.addr() & QUEUED == 0 {
+                let count = state.addr() - (SINGLE | LOCKED);
+                Some(if count > 0 { invalid_mut(count | LOCKED) } else { UNLOCKED })
+            } else {
+                None
+            }
+        }) {
+            Ok(_) => {}
+            // There are waiters queued and the lock count was moved to the
+            // tail of the queue.
+            Err(state) => unsafe { self.read_unlock_contended(state) },
+        }
+    }
+
+    #[cold]
+    unsafe fn read_unlock_contended(&self, state: State) {
+        // The state was observed with acquire ordering above, so the current
+        // thread will observe all node initializations.
+
+        // SAFETY:
+        // Because new read-locks cannot be acquired while threads are queued,
+        // all queue-lock owners will observe the set `LOCKED` bit. Because they
+        // do not modify the queue while there is a lock owner, the queue will
+        // not be removed from here.
+        let tail = unsafe { add_backlinks_and_find_tail(to_node(state)).as_ref() };
+        // The lock count is stored in the `next` field of `tail`.
+        // Decrement it, making sure to observe all changes made to the queue
+        // by the other lock owners by using acquire-release ordering.
+        let was_last = tail.next.0.fetch_byte_sub(SINGLE, AcqRel).addr() - SINGLE == 0;
+        if was_last {
+            // SAFETY:
+            // Other threads cannot read-lock while threads are queued. Also,
+            // the `LOCKED` bit is still set, so there are no writers. Therefore,
+            // the current thread exclusively owns the lock.
+            unsafe { self.unlock_contended(state) }
+        }
+    }
+
+    #[inline]
+    pub unsafe fn write_unlock(&self) {
+        if let Err(state) =
+            self.state.compare_exchange(invalid_mut(LOCKED), UNLOCKED, Release, Relaxed)
+        {
+            // SAFETY:
+            // Since other threads cannot acquire the lock, the state can only
+            // have changed because there are threads queued on the lock.
+            unsafe { self.unlock_contended(state) }
+        }
+    }
+
+    /// # Safety
+    /// * The lock must be exclusively owned by this thread.
+    /// * There must be threads queued on the lock.
+    #[cold]
+    unsafe fn unlock_contended(&self, mut state: State) {
+        loop {
+            // Atomically release the lock and try to acquire the queue lock.
+            let next = state.map_addr(|a| (a & !LOCKED) | QUEUE_LOCKED);
+            match self.state.compare_exchange_weak(state, next, AcqRel, Relaxed) {
+                // The queue lock was acquired. Release it, waking up the next
+                // waiter in the process.
+                Ok(_) if state.addr() & QUEUE_LOCKED == 0 => unsafe {
+                    return self.unlock_queue(next);
+                },
+                // Another thread already holds the queue lock, leave waking up
+                // waiters to it.
+                Ok(_) => return,
+                Err(new) => state = new,
+            }
+        }
+    }
+
+    /// Unlocks the queue. If the lock is unlocked, wakes up the next eligible
+    /// thread(s).
+    ///
+    /// # Safety
+    /// The queue lock must be held by the current thread.
+    unsafe fn unlock_queue(&self, mut state: State) {
+        debug_assert_eq!(state.addr() & (QUEUED | QUEUE_LOCKED), QUEUED | QUEUE_LOCKED);
+
+        loop {
+            let tail = unsafe { add_backlinks_and_find_tail(to_node(state)) };
+
+            if state.addr() & LOCKED == LOCKED {
+                // Another thread has locked the lock. Leave waking up waiters
+                // to them by releasing the queue lock.
+                match self.state.compare_exchange_weak(
+                    state,
+                    state.mask(!QUEUE_LOCKED),
+                    Release,
+                    Acquire,
+                ) {
+                    Ok(_) => return,
+                    Err(new) => {
+                        state = new;
+                        continue;
+                    }
+                }
+            }
+
+            let is_writer = unsafe { tail.as_ref().write };
+            if is_writer && let Some(prev) = unsafe { tail.as_ref().prev.get() } {
+                // `tail` is a writer and there is a node before `tail`.
+                // Split off `tail`.
+
+                // There are no set `tail` links before the node pointed to by
+                // `state`, so the first non-null tail field will be current
+                // (invariant 2). Invariant 4 is fullfilled since `find_tail`
+                // was called on this node, which ensures all backlinks are set.
+                unsafe {
+                    to_node(state).as_ref().tail.set(Some(prev));
+                }
+
+                // Release the queue lock. Doing this by subtraction is more
+                // efficient on modern processors since it is a single instruction
+                // instead of an update loop, which will fail if new threads are
+                // added to the list.
+                self.state.fetch_byte_sub(QUEUE_LOCKED, Release);
+
+                // The tail was split off and the lock released. Mark the node as
+                // completed.
+                unsafe {
+                    return Node::complete(tail);
+                }
+            } else {
+                // The next waiter is a reader or the queue only consists of one
+                // waiter. Just wake all threads.
+
+                // The lock cannot be locked (checked above), so mark it as
+                // unlocked to reset the queue.
+                if let Err(new) =
+                    self.state.compare_exchange_weak(state, UNLOCKED, Release, Acquire)
+                {
+                    state = new;
+                    continue;
+                }
+
+                let mut current = tail;
+                loop {
+                    let prev = unsafe { current.as_ref().prev.get() };
+                    unsafe {
+                        Node::complete(current);
+                    }
+                    match prev {
+                        Some(prev) => current = prev,
+                        None => return,
+                    }
+                }
+            }
+        }
+    }
+}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index 8498937809e..eb837c8f6c6 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -1063,7 +1063,7 @@ pub fn park() {
     let guard = PanicGuard;
     // SAFETY: park_timeout is called on the parker owned by this thread.
     unsafe {
-        current().inner.as_ref().parker().park();
+        current().park();
     }
     // No panic occurred, do not abort.
     forget(guard);
@@ -1290,6 +1290,15 @@ impl Thread {
         Thread { inner }
     }
 
+    /// Like the public [`park`], but callable on any handle. This is used to
+    /// allow parking in TLS destructors.
+    ///
+    /// # Safety
+    /// May only be called from the thread to which this handle belongs.
+    pub(crate) unsafe fn park(&self) {
+        unsafe { self.inner.as_ref().parker().park() }
+    }
+
     /// Atomically makes the handle's token available if it is not already.
     ///
     /// Every thread is equipped with some basic low-level blocking support, via
diff --git a/src/bootstrap/src/core/build_steps/check.rs b/src/bootstrap/src/core/build_steps/check.rs
index 5f0afdb1b36..4a04dbf44aa 100644
--- a/src/bootstrap/src/core/build_steps/check.rs
+++ b/src/bootstrap/src/core/build_steps/check.rs
@@ -4,7 +4,9 @@ use crate::core::build_steps::compile::{
     add_to_sysroot, run_cargo, rustc_cargo, rustc_cargo_env, std_cargo,
 };
 use crate::core::build_steps::tool::{prepare_tool_cargo, SourceType};
-use crate::core::builder::{crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step};
+use crate::core::builder::{
+    self, crate_description, Alias, Builder, Kind, RunConfig, ShouldRun, Step,
+};
 use crate::core::config::TargetSelection;
 use crate::utils::cache::Interned;
 use crate::INTERNER;
@@ -110,13 +112,15 @@ impl Step for Std {
         let target = self.target;
         let compiler = builder.compiler(builder.top_stage, builder.config.build);
 
-        let mut cargo = builder.cargo(
+        let mut cargo = builder::Cargo::new(
+            builder,
             compiler,
             Mode::Std,
             SourceType::InTree,
             target,
             cargo_subcommand(builder.kind),
         );
+
         std_cargo(builder, target, compiler.stage, &mut cargo);
         if matches!(builder.config.cmd, Subcommand::Fix { .. }) {
             // By default, cargo tries to fix all targets. Tell it not to fix tests until we've added `test` to the sysroot.
@@ -162,7 +166,8 @@ impl Step for Std {
         // since we initialize with an empty sysroot.
         //
         // Currently only the "libtest" tree of crates does this.
-        let mut cargo = builder.cargo(
+        let mut cargo = builder::Cargo::new(
+            builder,
             compiler,
             Mode::Std,
             SourceType::InTree,
@@ -256,13 +261,15 @@ impl Step for Rustc {
             builder.ensure(Std::new(target));
         }
 
-        let mut cargo = builder.cargo(
+        let mut cargo = builder::Cargo::new(
+            builder,
             compiler,
             Mode::Rustc,
             SourceType::InTree,
             target,
             cargo_subcommand(builder.kind),
         );
+
         rustc_cargo(builder, &mut cargo, target, compiler.stage);
 
         // For ./x.py clippy, don't run with --all-targets because
@@ -332,13 +339,15 @@ impl Step for CodegenBackend {
 
         builder.ensure(Rustc::new(target, builder));
 
-        let mut cargo = builder.cargo(
+        let mut cargo = builder::Cargo::new(
+            builder,
             compiler,
             Mode::Codegen,
             SourceType::InTree,
             target,
             cargo_subcommand(builder.kind),
         );
+
         cargo
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs
index 27b1d311864..64bef2d3015 100644
--- a/src/bootstrap/src/core/build_steps/compile.rs
+++ b/src/bootstrap/src/core/build_steps/compile.rs
@@ -22,6 +22,7 @@ use serde_derive::Deserialize;
 use crate::core::build_steps::dist;
 use crate::core::build_steps::llvm;
 use crate::core::build_steps::tool::SourceType;
+use crate::core::builder;
 use crate::core::builder::crate_description;
 use crate::core::builder::Cargo;
 use crate::core::builder::{Builder, Kind, PathSet, RunConfig, ShouldRun, Step, TaskPath};
@@ -239,12 +240,26 @@ impl Step for Std {
         // with -Zalways-encode-mir. This frees us from the need to have a target linker, and the
         // fact that this is a check build integrates nicely with run_cargo.
         let mut cargo = if self.is_for_mir_opt_tests {
-            let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "check");
+            let mut cargo = builder::Cargo::new_for_mir_opt_tests(
+                builder,
+                compiler,
+                Mode::Std,
+                SourceType::InTree,
+                target,
+                "check",
+            );
             cargo.rustflag("-Zalways-encode-mir");
             cargo.arg("--manifest-path").arg(builder.src.join("library/sysroot/Cargo.toml"));
             cargo
         } else {
-            let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "build");
+            let mut cargo = builder::Cargo::new(
+                builder,
+                compiler,
+                Mode::Std,
+                SourceType::InTree,
+                target,
+                "build",
+            );
             std_cargo(builder, target, compiler.stage, &mut cargo);
             for krate in &*self.crates {
                 cargo.arg("-p").arg(krate);
@@ -913,7 +928,15 @@ impl Step for Rustc {
             builder.config.build,
         ));
 
-        let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "build");
+        let mut cargo = builder::Cargo::new(
+            builder,
+            compiler,
+            Mode::Rustc,
+            SourceType::InTree,
+            target,
+            "build",
+        );
+
         rustc_cargo(builder, &mut cargo, target, compiler.stage);
 
         if builder.config.rust_profile_use.is_some()
@@ -1333,7 +1356,14 @@ impl Step for CodegenBackend {
 
         let out_dir = builder.cargo_out(compiler, Mode::Codegen, target);
 
-        let mut cargo = builder.cargo(compiler, Mode::Codegen, SourceType::InTree, target, "build");
+        let mut cargo = builder::Cargo::new(
+            builder,
+            compiler,
+            Mode::Codegen,
+            SourceType::InTree,
+            target,
+            "build",
+        );
         cargo
             .arg("--manifest-path")
             .arg(builder.src.join(format!("compiler/rustc_codegen_{backend}/Cargo.toml")));
diff --git a/src/bootstrap/src/core/build_steps/doc.rs b/src/bootstrap/src/core/build_steps/doc.rs
index 57e63927c95..fdb099e4ab1 100644
--- a/src/bootstrap/src/core/build_steps/doc.rs
+++ b/src/bootstrap/src/core/build_steps/doc.rs
@@ -13,7 +13,7 @@ use std::{fs, mem};
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::tool::{self, prepare_tool_cargo, SourceType, Tool};
-use crate::core::builder::crate_description;
+use crate::core::builder::{self, crate_description};
 use crate::core::builder::{Alias, Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::{Config, TargetSelection};
 use crate::utils::cache::{Interned, INTERNER};
@@ -684,7 +684,9 @@ fn doc_std(
     // as a function parameter.
     let out_dir = target_dir.join(target.triple).join("doc");
 
-    let mut cargo = builder.cargo(compiler, Mode::Std, SourceType::InTree, target, "doc");
+    let mut cargo =
+        builder::Cargo::new(builder, compiler, Mode::Std, SourceType::InTree, target, "doc");
+
     compile::std_cargo(builder, target, compiler.stage, &mut cargo);
     cargo
         .arg("--no-deps")
@@ -785,7 +787,9 @@ impl Step for Rustc {
         );
 
         // Build cargo command.
-        let mut cargo = builder.cargo(compiler, Mode::Rustc, SourceType::InTree, target, "doc");
+        let mut cargo =
+            builder::Cargo::new(builder, compiler, Mode::Rustc, SourceType::InTree, target, "doc");
+
         cargo.rustdocflag("--document-private-items");
         // Since we always pass --document-private-items, there's no need to warn about linking to private items.
         cargo.rustdocflag("-Arustdoc::private-intra-doc-links");
diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs
index d9e0da14a70..5fa5f2d4794 100644
--- a/src/bootstrap/src/core/build_steps/run.rs
+++ b/src/bootstrap/src/core/build_steps/run.rs
@@ -165,7 +165,7 @@ impl Step for Miri {
             SourceType::InTree,
             &[],
         );
-        miri.add_rustc_lib_path(builder, compiler);
+        miri.add_rustc_lib_path(builder);
         // Forward arguments.
         miri.arg("--").arg("--target").arg(target.rustc_target_arg());
         miri.args(builder.config.args());
diff --git a/src/bootstrap/src/core/build_steps/test.rs b/src/bootstrap/src/core/build_steps/test.rs
index baf1b5a4a1a..1dbda405128 100644
--- a/src/bootstrap/src/core/build_steps/test.rs
+++ b/src/bootstrap/src/core/build_steps/test.rs
@@ -20,6 +20,7 @@ use crate::core::build_steps::llvm;
 use crate::core::build_steps::synthetic_targets::MirOptPanicAbortSyntheticTarget;
 use crate::core::build_steps::tool::{self, SourceType, Tool};
 use crate::core::build_steps::toolstate::ToolState;
+use crate::core::builder;
 use crate::core::builder::crate_description;
 use crate::core::builder::{Builder, Compiler, Kind, RunConfig, ShouldRun, Step};
 use crate::core::config::flags::get_completion;
@@ -380,7 +381,7 @@ impl Step for RustAnalyzer {
         // work in Rust CI
         cargo.env("SKIP_SLOW_TESTS", "1");
 
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
         run_cargo_test(cargo, &[], &[], "rust-analyzer", "rust-analyzer", compiler, host, builder);
     }
 }
@@ -426,7 +427,7 @@ impl Step for Rustfmt {
         t!(fs::create_dir_all(&dir));
         cargo.env("RUSTFMT_TEST_DIR", dir);
 
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
 
         run_cargo_test(cargo, &[], &[], "rustfmt", "rustfmt", compiler, host, builder);
     }
@@ -476,7 +477,7 @@ impl Step for RustDemangler {
         t!(fs::create_dir_all(&dir));
 
         cargo.env("RUST_DEMANGLER_DRIVER_PATH", rust_demangler);
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
 
         run_cargo_test(
             cargo,
@@ -517,7 +518,7 @@ impl Miri {
             SourceType::InTree,
             &[],
         );
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
         cargo.arg("--").arg("miri").arg("setup");
         cargo.arg("--target").arg(target.rustc_target_arg());
 
@@ -618,7 +619,7 @@ impl Step for Miri {
         );
         let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "miri", host, target);
 
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
 
         // miri tests need to know about the stage sysroot
         cargo.env("MIRI_SYSROOT", &miri_sysroot);
@@ -671,7 +672,7 @@ impl Step for Miri {
             SourceType::Submodule,
             &[],
         );
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
         cargo.arg("--").arg("miri").arg("test");
         if builder.config.locked_deps {
             cargo.arg("--locked");
@@ -788,7 +789,7 @@ impl Step for Clippy {
         let host_libs = builder.stage_out(compiler, Mode::ToolRustc).join(builder.cargo_dir());
         cargo.env("HOST_LIBS", host_libs);
 
-        cargo.add_rustc_lib_path(builder, compiler);
+        cargo.add_rustc_lib_path(builder);
         let mut cargo = prepare_cargo_test(cargo, &[], &[], "clippy", compiler, host, builder);
 
         let _guard = builder.msg_sysroot_tool(Kind::Test, compiler.stage, "clippy", host, host);
@@ -2499,8 +2500,15 @@ impl Step for Crate {
         // we're working with automatically.
         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
 
-        let mut cargo =
-            builder.cargo(compiler, mode, SourceType::InTree, target, builder.kind.as_str());
+        let mut cargo = builder::Cargo::new(
+            builder,
+            compiler,
+            mode,
+            SourceType::InTree,
+            target,
+            builder.kind.as_str(),
+        );
+
         match mode {
             Mode::Std => {
                 compile::std_cargo(builder, target, compiler.stage, &mut cargo);
@@ -3134,13 +3142,15 @@ impl Step for CodegenCranelift {
         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
 
         let build_cargo = || {
-            let mut cargo = builder.cargo(
+            let mut cargo = builder::Cargo::new(
+                builder,
                 compiler,
                 Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
                 SourceType::InTree,
                 target,
                 "run",
             );
+
             cargo.current_dir(&builder.src.join("compiler/rustc_codegen_cranelift"));
             cargo
                 .arg("--manifest-path")
@@ -3260,13 +3270,15 @@ impl Step for CodegenGCC {
         let compiler = builder.compiler_for(compiler.stage, compiler.host, target);
 
         let build_cargo = || {
-            let mut cargo = builder.cargo(
+            let mut cargo = builder::Cargo::new(
+                builder,
                 compiler,
                 Mode::Codegen, // Must be codegen to ensure dlopen on compiled dylibs works
                 SourceType::InTree,
                 target,
                 "run",
             );
+
             cargo.current_dir(&builder.src.join("compiler/rustc_codegen_gcc"));
             cargo
                 .arg("--manifest-path")
diff --git a/src/bootstrap/src/core/build_steps/tool.rs b/src/bootstrap/src/core/build_steps/tool.rs
index 5d8d10a7deb..a3daf22c9a9 100644
--- a/src/bootstrap/src/core/build_steps/tool.rs
+++ b/src/bootstrap/src/core/build_steps/tool.rs
@@ -5,6 +5,7 @@ use std::process::Command;
 
 use crate::core::build_steps::compile;
 use crate::core::build_steps::toolstate::ToolState;
+use crate::core::builder;
 use crate::core::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step};
 use crate::core::config::TargetSelection;
 use crate::utils::channel::GitInfo;
@@ -142,7 +143,8 @@ pub fn prepare_tool_cargo(
     source_type: SourceType,
     extra_features: &[String],
 ) -> CargoCommand {
-    let mut cargo = builder.cargo(compiler, mode, source_type, target, command);
+    let mut cargo = builder::Cargo::new(builder, compiler, mode, source_type, target, command);
+
     let dir = builder.src.join(path);
     cargo.arg("--manifest-path").arg(dir.join("Cargo.toml"));
 
diff --git a/src/bootstrap/src/core/builder.rs b/src/bootstrap/src/core/builder.rs
index 83485abfa56..b21ffe868e1 100644
--- a/src/bootstrap/src/core/builder.rs
+++ b/src/bootstrap/src/core/builder.rs
@@ -1299,14 +1299,12 @@ impl<'a> Builder<'a> {
         cargo
     }
 
-    /// Prepares an invocation of `cargo` to be run.
-    ///
     /// This will create a `Command` that represents a pending execution of
     /// Cargo. This cargo will be configured to use `compiler` as the actual
     /// rustc compiler, its output will be scoped by `mode`'s output directory,
     /// it will pass the `--target` flag for the specified `target`, and will be
     /// executing the Cargo command `cmd`.
-    pub fn cargo(
+    fn cargo(
         &self,
         compiler: Compiler,
         mode: Mode,
@@ -1872,17 +1870,6 @@ impl<'a> Builder<'a> {
             rustflags.arg("-Wrustc::internal");
         }
 
-        if cmd != "check" {
-            self.configure_linker(
-                compiler,
-                target,
-                &mut cargo,
-                &mut rustflags,
-                &mut rustdocflags,
-                &mut hostflags,
-            );
-        }
-
         // If Control Flow Guard is enabled, pass the `control-flow-guard` flag to rustc
         // when compiling the standard library, since this might be linked into the final outputs
         // produced by rustc. Since this mitigation is only available on Windows, only enable it
@@ -2031,136 +2018,14 @@ impl<'a> Builder<'a> {
             cargo.env("RUSTFLAGS", &rustc_args.join(" "));
         }
 
-        Cargo { command: cargo, rustflags, rustdocflags, hostflags, allow_features }
-    }
-
-    fn configure_linker(
-        &self,
-        compiler: Compiler,
-        target: TargetSelection,
-        cargo: &mut Command,
-        rustflags: &mut Rustflags,
-        rustdocflags: &mut Rustflags,
-        hostflags: &mut HostFlags,
-    ) {
-        // Dealing with rpath here is a little special, so let's go into some
-        // detail. First off, `-rpath` is a linker option on Unix platforms
-        // which adds to the runtime dynamic loader path when looking for
-        // dynamic libraries. We use this by default on Unix platforms to ensure
-        // that our nightlies behave the same on Windows, that is they work out
-        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
-        // table of `config.toml`
-        //
-        // Ok, so the astute might be wondering "why isn't `-C rpath` used
-        // here?" and that is indeed a good question to ask. This codegen
-        // option is the compiler's current interface to generating an rpath.
-        // Unfortunately it doesn't quite suffice for us. The flag currently
-        // takes no value as an argument, so the compiler calculates what it
-        // should pass to the linker as `-rpath`. This unfortunately is based on
-        // the **compile time** directory structure which when building with
-        // Cargo will be very different than the runtime directory structure.
-        //
-        // All that's a really long winded way of saying that if we use
-        // `-Crpath` then the executables generated have the wrong rpath of
-        // something like `$ORIGIN/deps` when in fact the way we distribute
-        // rustc requires the rpath to be `$ORIGIN/../lib`.
-        //
-        // So, all in all, to set up the correct rpath we pass the linker
-        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
-        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
-        // to change a flag in a binary?
-        if self.config.rpath_enabled(target) && helpers::use_host_linker(target) {
-            let libdir = self.sysroot_libdir_relative(compiler).to_str().unwrap();
-            let rpath = if target.contains("apple") {
-                // Note that we need to take one extra step on macOS to also pass
-                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
-                // do that we pass a weird flag to the compiler to get it to do
-                // so. Note that this is definitely a hack, and we should likely
-                // flesh out rpath support more fully in the future.
-                rustflags.arg("-Zosx-rpath-install-name");
-                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
-            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
-                rustflags.arg("-Clink-args=-Wl,-z,origin");
-                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
-            } else {
-                None
-            };
-            if let Some(rpath) = rpath {
-                rustflags.arg(&format!("-Clink-args={rpath}"));
-            }
-        }
-
-        for arg in linker_args(self, compiler.host, LldThreads::Yes) {
-            hostflags.arg(&arg);
-        }
-
-        if let Some(target_linker) = self.linker(target) {
-            let target = crate::envify(&target.triple);
-            cargo.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
-        }
-        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
-        // `linker_args` here.
-        for flag in linker_flags(self, target, LldThreads::Yes) {
-            rustflags.arg(&flag);
-        }
-        for arg in linker_args(self, target, LldThreads::Yes) {
-            rustdocflags.arg(&arg);
-        }
-
-        if !self.config.dry_run() && self.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
-        {
-            rustflags.arg("-Clink-arg=-gz");
-        }
-
-        // Throughout the build Cargo can execute a number of build scripts
-        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
-        // obtained previously to those build scripts.
-        // Build scripts use either the `cc` crate or `configure/make` so we pass
-        // the options through environment variables that are fetched and understood by both.
-        //
-        // FIXME: the guard against msvc shouldn't need to be here
-        if target.is_msvc() {
-            if let Some(ref cl) = self.config.llvm_clang_cl {
-                cargo.env("CC", cl).env("CXX", cl);
-            }
-        } else {
-            let ccache = self.config.ccache.as_ref();
-            let ccacheify = |s: &Path| {
-                let ccache = match ccache {
-                    Some(ref s) => s,
-                    None => return s.display().to_string(),
-                };
-                // FIXME: the cc-rs crate only recognizes the literal strings
-                // `ccache` and `sccache` when doing caching compilations, so we
-                // mirror that here. It should probably be fixed upstream to
-                // accept a new env var or otherwise work with custom ccache
-                // vars.
-                match &ccache[..] {
-                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
-                    _ => s.display().to_string(),
-                }
-            };
-            let triple_underscored = target.triple.replace("-", "_");
-            let cc = ccacheify(&self.cc(target));
-            cargo.env(format!("CC_{triple_underscored}"), &cc);
-
-            let cflags = self.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
-            cargo.env(format!("CFLAGS_{triple_underscored}"), &cflags);
-
-            if let Some(ar) = self.ar(target) {
-                let ranlib = format!("{} s", ar.display());
-                cargo
-                    .env(format!("AR_{triple_underscored}"), ar)
-                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
-            }
-
-            if let Ok(cxx) = self.cxx(target) {
-                let cxx = ccacheify(&cxx);
-                let cxxflags = self.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
-                cargo
-                    .env(format!("CXX_{triple_underscored}"), &cxx)
-                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
-            }
+        Cargo {
+            command: cargo,
+            compiler,
+            target,
+            rustflags,
+            rustdocflags,
+            hostflags,
+            allow_features,
         }
     }
 
@@ -2363,6 +2228,8 @@ impl HostFlags {
 #[derive(Debug)]
 pub struct Cargo {
     command: Command,
+    compiler: Compiler,
+    target: TargetSelection,
     rustflags: Rustflags,
     rustdocflags: Rustflags,
     hostflags: HostFlags,
@@ -2370,10 +2237,37 @@ pub struct Cargo {
 }
 
 impl Cargo {
+    /// Calls `Builder::cargo` and `Cargo::configure_linker` to prepare an invocation of `cargo` to be run.
+    pub fn new(
+        builder: &Builder<'_>,
+        compiler: Compiler,
+        mode: Mode,
+        source_type: SourceType,
+        target: TargetSelection,
+        cmd: &str,
+    ) -> Cargo {
+        let mut cargo = builder.cargo(compiler, mode, source_type, target, cmd);
+        cargo.configure_linker(builder);
+        cargo
+    }
+
+    /// Same as `Cargo::new` except this one doesn't configure the linker with `Cargo::configure_linker`
+    pub fn new_for_mir_opt_tests(
+        builder: &Builder<'_>,
+        compiler: Compiler,
+        mode: Mode,
+        source_type: SourceType,
+        target: TargetSelection,
+        cmd: &str,
+    ) -> Cargo {
+        builder.cargo(compiler, mode, source_type, target, cmd)
+    }
+
     pub fn rustdocflag(&mut self, arg: &str) -> &mut Cargo {
         self.rustdocflags.arg(arg);
         self
     }
+
     pub fn rustflag(&mut self, arg: &str) -> &mut Cargo {
         self.rustflags.arg(arg);
         self
@@ -2403,8 +2297,8 @@ impl Cargo {
         self
     }
 
-    pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) {
-        builder.add_rustc_lib_path(compiler, &mut self.command);
+    pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>) {
+        builder.add_rustc_lib_path(self.compiler, &mut self.command);
     }
 
     pub fn current_dir(&mut self, dir: &Path) -> &mut Cargo {
@@ -2423,6 +2317,134 @@ impl Cargo {
         self.allow_features.push_str(features);
         self
     }
+
+    fn configure_linker(&mut self, builder: &Builder<'_>) -> &mut Cargo {
+        let target = self.target;
+        let compiler = self.compiler;
+
+        // Dealing with rpath here is a little special, so let's go into some
+        // detail. First off, `-rpath` is a linker option on Unix platforms
+        // which adds to the runtime dynamic loader path when looking for
+        // dynamic libraries. We use this by default on Unix platforms to ensure
+        // that our nightlies behave the same on Windows, that is they work out
+        // of the box. This can be disabled by setting `rpath = false` in `[rust]`
+        // table of `config.toml`
+        //
+        // Ok, so the astute might be wondering "why isn't `-C rpath` used
+        // here?" and that is indeed a good question to ask. This codegen
+        // option is the compiler's current interface to generating an rpath.
+        // Unfortunately it doesn't quite suffice for us. The flag currently
+        // takes no value as an argument, so the compiler calculates what it
+        // should pass to the linker as `-rpath`. This unfortunately is based on
+        // the **compile time** directory structure which when building with
+        // Cargo will be very different than the runtime directory structure.
+        //
+        // All that's a really long winded way of saying that if we use
+        // `-Crpath` then the executables generated have the wrong rpath of
+        // something like `$ORIGIN/deps` when in fact the way we distribute
+        // rustc requires the rpath to be `$ORIGIN/../lib`.
+        //
+        // So, all in all, to set up the correct rpath we pass the linker
+        // argument manually via `-C link-args=-Wl,-rpath,...`. Plus isn't it
+        // fun to pass a flag to a tool to pass a flag to pass a flag to a tool
+        // to change a flag in a binary?
+        if builder.config.rpath_enabled(target) && helpers::use_host_linker(target) {
+            let libdir = builder.sysroot_libdir_relative(compiler).to_str().unwrap();
+            let rpath = if target.contains("apple") {
+                // Note that we need to take one extra step on macOS to also pass
+                // `-Wl,-instal_name,@rpath/...` to get things to work right. To
+                // do that we pass a weird flag to the compiler to get it to do
+                // so. Note that this is definitely a hack, and we should likely
+                // flesh out rpath support more fully in the future.
+                self.rustflags.arg("-Zosx-rpath-install-name");
+                Some(format!("-Wl,-rpath,@loader_path/../{libdir}"))
+            } else if !target.is_windows() && !target.contains("aix") && !target.contains("xous") {
+                self.rustflags.arg("-Clink-args=-Wl,-z,origin");
+                Some(format!("-Wl,-rpath,$ORIGIN/../{libdir}"))
+            } else {
+                None
+            };
+            if let Some(rpath) = rpath {
+                self.rustflags.arg(&format!("-Clink-args={rpath}"));
+            }
+        }
+
+        for arg in linker_args(builder, compiler.host, LldThreads::Yes) {
+            self.hostflags.arg(&arg);
+        }
+
+        if let Some(target_linker) = builder.linker(target) {
+            let target = crate::envify(&target.triple);
+            self.command.env(&format!("CARGO_TARGET_{target}_LINKER"), target_linker);
+        }
+        // We want to set -Clinker using Cargo, therefore we only call `linker_flags` and not
+        // `linker_args` here.
+        for flag in linker_flags(builder, target, LldThreads::Yes) {
+            self.rustflags.arg(&flag);
+        }
+        for arg in linker_args(builder, target, LldThreads::Yes) {
+            self.rustdocflags.arg(&arg);
+        }
+
+        if !builder.config.dry_run()
+            && builder.cc.borrow()[&target].args().iter().any(|arg| arg == "-gz")
+        {
+            self.rustflags.arg("-Clink-arg=-gz");
+        }
+
+        // Throughout the build Cargo can execute a number of build scripts
+        // compiling C/C++ code and we need to pass compilers, archivers, flags, etc
+        // obtained previously to those build scripts.
+        // Build scripts use either the `cc` crate or `configure/make` so we pass
+        // the options through environment variables that are fetched and understood by both.
+        //
+        // FIXME: the guard against msvc shouldn't need to be here
+        if target.is_msvc() {
+            if let Some(ref cl) = builder.config.llvm_clang_cl {
+                self.command.env("CC", cl).env("CXX", cl);
+            }
+        } else {
+            let ccache = builder.config.ccache.as_ref();
+            let ccacheify = |s: &Path| {
+                let ccache = match ccache {
+                    Some(ref s) => s,
+                    None => return s.display().to_string(),
+                };
+                // FIXME: the cc-rs crate only recognizes the literal strings
+                // `ccache` and `sccache` when doing caching compilations, so we
+                // mirror that here. It should probably be fixed upstream to
+                // accept a new env var or otherwise work with custom ccache
+                // vars.
+                match &ccache[..] {
+                    "ccache" | "sccache" => format!("{} {}", ccache, s.display()),
+                    _ => s.display().to_string(),
+                }
+            };
+            let triple_underscored = target.triple.replace("-", "_");
+            let cc = ccacheify(&builder.cc(target));
+            self.command.env(format!("CC_{triple_underscored}"), &cc);
+
+            let cflags = builder.cflags(target, GitRepo::Rustc, CLang::C).join(" ");
+            self.command.env(format!("CFLAGS_{triple_underscored}"), &cflags);
+
+            if let Some(ar) = builder.ar(target) {
+                let ranlib = format!("{} s", ar.display());
+                self.command
+                    .env(format!("AR_{triple_underscored}"), ar)
+                    .env(format!("RANLIB_{triple_underscored}"), ranlib);
+            }
+
+            if let Ok(cxx) = builder.cxx(target) {
+                let cxx = ccacheify(&cxx);
+                let cxxflags = builder.cflags(target, GitRepo::Rustc, CLang::Cxx).join(" ");
+                self.command
+                    .env(format!("CXX_{triple_underscored}"), &cxx)
+                    .env(format!("CXXFLAGS_{triple_underscored}"), cxxflags);
+            }
+        }
+
+        self
+    }
 }
 
 impl From<Cargo> for Command {
diff --git a/src/bootstrap/src/core/config/config.rs b/src/bootstrap/src/core/config/config.rs
index c0dd1e12084..4c64850c0e0 100644
--- a/src/bootstrap/src/core/config/config.rs
+++ b/src/bootstrap/src/core/config/config.rs
@@ -1810,10 +1810,9 @@ impl Config {
                     target.llvm_config = Some(config.src.join(s));
                 }
                 if let Some(patches) = cfg.llvm_has_rust_patches {
-                    assert_eq!(
-                        config.submodules,
-                        Some(false),
-                        "cannot set `llvm-has-rust-patches` for a managed submodule (set `build.submodules = false` if you want to apply patches)"
+                    assert!(
+                        config.submodules == Some(false) || cfg.llvm_config.is_some(),
+                        "use of `llvm-has-rust-patches` is restricted to cases where either submodules are disabled or llvm-config been provided"
                     );
                     target.llvm_has_rust_patches = Some(patches);
                 }
diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml
index 43e48c01176..9b0f477409a 100644
--- a/src/ci/github-actions/ci.yml
+++ b/src/ci/github-actions/ci.yml
@@ -514,7 +514,7 @@ jobs:
               RUST_CONFIGURE_ARGS: --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set rust.lto=thin
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -528,7 +528,7 @@ jobs:
               RUST_CONFIGURE_ARGS: --enable-sanitizers --enable-profiler --set rust.jemalloc
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -541,6 +541,7 @@ jobs:
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
               MACOSX_DEPLOYMENT_TARGET: 10.12
               MACOSX_STD_DEPLOYMENT_TARGET: 10.12
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               NO_LLVM_ASSERTIONS: 1
               NO_DEBUG_ASSERTIONS: 1
               NO_OVERFLOW_CHECKS: 1
@@ -564,7 +565,7 @@ jobs:
                 --set llvm.ninja=false
                 --set rust.lto=thin
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
@@ -583,7 +584,7 @@ jobs:
                 --enable-profiler
                 --set rust.jemalloc
               RUSTC_RETRY_LINKER_ON_SEGFAULT: 1
-              SELECT_XCODE: /Applications/Xcode_13.4.1.app
+              SELECT_XCODE: /Applications/Xcode_14.3.1.app
               USE_XCODE_CLANG: 1
               MACOSX_DEPLOYMENT_TARGET: 11.0
               MACOSX_STD_DEPLOYMENT_TARGET: 11.0
diff --git a/src/ci/scripts/select-xcode.sh b/src/ci/scripts/select-xcode.sh
index 3b9c77d42ba..569c4a4136d 100755
--- a/src/ci/scripts/select-xcode.sh
+++ b/src/ci/scripts/select-xcode.sh
@@ -7,7 +7,5 @@ IFS=$'\n\t'
 source "$(cd "$(dirname "$0")" && pwd)/../shared.sh"
 
 if isMacOS; then
-    if [[ -s "${SELECT_XCODE-}" ]]; then
-        sudo xcode-select -s "${SELECT_XCODE}"
-    fi
+    sudo xcode-select -s "${SELECT_XCODE}"
 fi
diff --git a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
index 2ce0ccb7876..540e5a4af93 100644
--- a/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
+++ b/src/doc/rustc/src/platform-support/armv6k-nintendo-3ds.md
@@ -10,6 +10,9 @@ from nor used with any official Nintendo SDK.
 
 ## Target maintainers
 
+This target is maintained by members of the [@rust3ds](https://github.com/rust3ds)
+organization:
+
 - [@Meziu](https://github.com/Meziu)
 - [@AzureMarker](https://github.com/AzureMarker)
 - [@ian-h-chamberlain](https://github.com/ian-h-chamberlain)
@@ -35,8 +38,8 @@ Additionally, some helper crates provide implementations of some `libc` function
 use by `std` that may otherwise be missing. These, or an alternate implementation
 of the relevant functions, are required to use `std`:
 
-- [`pthread-3ds`](https://github.com/Meziu/pthread-3ds) provides pthread APIs for `std::thread`.
-- [`linker-fix-3ds`](https://github.com/Meziu/rust-linker-fix-3ds) fulfills some other missing libc APIs.
+- [`pthread-3ds`](https://github.com/rust3ds/pthread-3ds) provides pthread APIs for `std::thread`.
+- [`shim-3ds`](https://github.com/rust3ds/shim-3ds) fulfills some other missing libc APIs (e.g. `getrandom`).
 
 Binaries built for this target should be compatible with all variants of the
 3DS (and 2DS) hardware and firmware, but testing is limited and some versions may
@@ -74,8 +77,10 @@ export CFLAGS_armv6k_nintendo_3ds="-mfloat-abi=hard -mtune=mpcore -mtp=soft -mar
 Rust does not yet ship pre-compiled artifacts for this target.
 
 The recommended way to build binaries is by using the
-[cargo-3ds](https://github.com/Meziu/cargo-3ds) tool, which uses `build-std`
+[cargo-3ds](https://github.com/rust3ds/cargo-3ds) tool, which uses `build-std`
 and provides commands that work like the usual `cargo run`, `cargo build`, etc.
+The `cargo 3ds new` will automatically set up a new project with the dependencies
+needed to build a simple binary.
 
 You can also build Rust with the target enabled (see
 [Building the target](#building-the-target) above).
@@ -83,23 +88,16 @@ You can also build Rust with the target enabled (see
 As mentioned in [Requirements](#requirements), programs that use `std` must link
 against both the devkitARM toolchain and libraries providing the `libc` APIs used
 in `std`.  There is a general-purpose utility crate for working with nonstandard
-APIs provided by the OS: [`ctru-rs`](https://github.com/Meziu/ctru-rs).
+APIs provided by the OS: [`ctru-rs`](https://github.com/rust3ds/ctru-rs).
 Add it to Cargo.toml to use it in your program:
 
 ```toml
 [dependencies]
-ctru-rs = { git = "https://github.com/Meziu/ctru-rs.git" }
+ctru-rs = { git = "https://github.com/rust3ds/ctru-rs.git" }
 ```
 
-Using this library's `init()` function ensures the symbols needed to link
-against `std` are present (as mentioned in [Requirements](#requirements)
-above), as well as providing a runtime suitable for `std`:
-
-```rust,ignore (requires-3rd-party-library)
-fn main() {
-    ctru::init();
-}
-```
+Depending on `ctru-rs` ensures that all the necessary symbols are available at
+link time.
 
 ## Testing
 
diff --git a/src/doc/unstable-book/src/library-features/duration-constructors.md b/src/doc/unstable-book/src/library-features/duration-constructors.md
new file mode 100644
index 00000000000..098519c7c90
--- /dev/null
+++ b/src/doc/unstable-book/src/library-features/duration-constructors.md
@@ -0,0 +1,9 @@
+# `duration_constructors`
+
+The tracking issue for this feature is: [#120301]
+
+[#120301]: https://github.com/rust-lang/rust/issues/120301
+
+------------------------
+
+Add the methods `from_mins`, `from_hours` and `from_days` to `Duration`.
diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs
index 7ca4392233e..23a059c6e03 100644
--- a/src/librustdoc/clean/inline.rs
+++ b/src/librustdoc/clean/inline.rs
@@ -65,37 +65,49 @@ pub(crate) fn try_inline(
     let kind = match res {
         Res::Def(DefKind::Trait, did) => {
             record_extern_fqn(cx, did, ItemType::Trait);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::TraitItem(Box::new(build_external_trait(cx, did)))
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::TraitItem(Box::new(build_external_trait(cx, did)))
+            })
         }
         Res::Def(DefKind::Fn, did) => {
             record_extern_fqn(cx, did, ItemType::Function);
-            clean::FunctionItem(build_external_function(cx, did))
+            cx.with_param_env(did, |cx| clean::FunctionItem(build_external_function(cx, did)))
         }
         Res::Def(DefKind::Struct, did) => {
             record_extern_fqn(cx, did, ItemType::Struct);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::StructItem(build_struct(cx, did))
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::StructItem(build_struct(cx, did))
+            })
         }
         Res::Def(DefKind::Union, did) => {
             record_extern_fqn(cx, did, ItemType::Union);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::UnionItem(build_union(cx, did))
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::UnionItem(build_union(cx, did))
+            })
         }
         Res::Def(DefKind::TyAlias, did) => {
             record_extern_fqn(cx, did, ItemType::TypeAlias);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::TypeAliasItem(build_type_alias(cx, did, &mut ret))
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::TypeAliasItem(build_type_alias(cx, did, &mut ret))
+            })
         }
         Res::Def(DefKind::Enum, did) => {
             record_extern_fqn(cx, did, ItemType::Enum);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::EnumItem(build_enum(cx, did))
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::EnumItem(build_enum(cx, did))
+            })
         }
         Res::Def(DefKind::ForeignTy, did) => {
             record_extern_fqn(cx, did, ItemType::ForeignType);
-            build_impls(cx, did, attrs_without_docs, &mut ret);
-            clean::ForeignTypeItem
+            cx.with_param_env(did, |cx| {
+                build_impls(cx, did, attrs_without_docs, &mut ret);
+                clean::ForeignTypeItem
+            })
         }
         // Never inline enum variants but leave them shown as re-exports.
         Res::Def(DefKind::Variant, _) => return None,
@@ -108,11 +120,13 @@ pub(crate) fn try_inline(
         }
         Res::Def(DefKind::Static(_), did) => {
             record_extern_fqn(cx, did, ItemType::Static);
-            clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did)))
+            cx.with_param_env(did, |cx| {
+                clean::StaticItem(build_static(cx, did, cx.tcx.is_mutable_static(did)))
+            })
         }
         Res::Def(DefKind::Const, did) => {
             record_extern_fqn(cx, did, ItemType::Constant);
-            clean::ConstantItem(build_const(cx, did))
+            cx.with_param_env(did, |cx| clean::ConstantItem(build_const(cx, did)))
         }
         Res::Def(DefKind::Macro(kind), did) => {
             let mac = build_macro(cx, did, name, import_def_id, kind);
@@ -334,7 +348,9 @@ pub(crate) fn build_impls(
 
     // for each implementation of an item represented by `did`, build the clean::Item for that impl
     for &did in tcx.inherent_impls(did).into_iter().flatten() {
-        build_impl(cx, did, attrs, ret);
+        cx.with_param_env(did, |cx| {
+            build_impl(cx, did, attrs, ret);
+        });
     }
 
     // This pretty much exists expressly for `dyn Error` traits that exist in the `alloc` crate.
@@ -347,7 +363,9 @@ pub(crate) fn build_impls(
         let type_ =
             if tcx.is_trait(did) { SimplifiedType::Trait(did) } else { SimplifiedType::Adt(did) };
         for &did in tcx.incoherent_impls(type_).into_iter().flatten() {
-            build_impl(cx, did, attrs, ret);
+            cx.with_param_env(did, |cx| {
+                build_impl(cx, did, attrs, ret);
+            });
         }
     }
 }
@@ -549,7 +567,9 @@ pub(crate) fn build_impl(
     }
 
     if let Some(did) = trait_.as_ref().map(|t| t.def_id()) {
-        record_extern_trait(cx, did);
+        cx.with_param_env(did, |cx| {
+            record_extern_trait(cx, did);
+        });
     }
 
     let (merged_attrs, cfg) = merge_attrs(cx, load_attrs(cx, did), attrs);
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index b8e0d75e7dc..abd0b3562d2 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -947,7 +947,9 @@ fn clean_ty_alias_inner_type<'tcx>(
     };
 
     if !adt_def.did().is_local() {
-        inline::build_impls(cx, adt_def.did(), None, ret);
+        cx.with_param_env(adt_def.did(), |cx| {
+            inline::build_impls(cx, adt_def.did(), None, ret);
+        });
     }
 
     Some(if adt_def.is_enum() {
@@ -1838,7 +1840,9 @@ fn maybe_expand_private_type_alias<'tcx>(
         }
     }
 
-    Some(cx.enter_alias(args, def_id.to_def_id(), |cx| clean_ty(&ty, cx)))
+    Some(cx.enter_alias(args, def_id.to_def_id(), |cx| {
+        cx.with_param_env(def_id.to_def_id(), |cx| clean_ty(&ty, cx))
+    }))
 }
 
 pub(crate) fn clean_ty<'tcx>(ty: &hir::Ty<'tcx>, cx: &mut DocContext<'tcx>) -> Type {
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index b2b20c95a7e..0b7d35d7be4 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -295,12 +295,16 @@ pub(crate) fn build_deref_target_impls(
         if let Some(prim) = target.primitive_type() {
             let _prof_timer = tcx.sess.prof.generic_activity("build_primitive_inherent_impls");
             for did in prim.impls(tcx).filter(|did| !did.is_local()) {
-                inline::build_impl(cx, did, None, ret);
+                cx.with_param_env(did, |cx| {
+                    inline::build_impl(cx, did, None, ret);
+                });
             }
         } else if let Type::Path { path } = target {
             let did = path.def_id();
             if !did.is_local() {
-                inline::build_impls(cx, did, None, ret);
+                cx.with_param_env(did, |cx| {
+                    inline::build_impls(cx, did, None, ret);
+                });
             }
         }
     }
diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs
index e2a7ef8556e..53c08ef5e5c 100644
--- a/src/librustdoc/passes/collect_trait_impls.rs
+++ b/src/librustdoc/passes/collect_trait_impls.rs
@@ -49,7 +49,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
         let _prof_timer = tcx.sess.prof.generic_activity("build_extern_trait_impls");
         for &cnum in tcx.crates(()) {
             for &impl_def_id in tcx.trait_impls_in_crate(cnum) {
-                inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
+                cx.with_param_env(impl_def_id, |cx| {
+                    inline::build_impl(cx, impl_def_id, None, &mut new_items_external);
+                });
             }
         }
     }
@@ -74,7 +76,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
                 );
                 parent = tcx.opt_parent(did);
             }
-            inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local);
+            cx.with_param_env(impl_def_id, |cx| {
+                inline::build_impl(cx, impl_def_id, Some((&attr_buf, None)), &mut new_items_local);
+            });
             attr_buf.clear();
         }
     }
@@ -83,7 +87,9 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) ->
         for def_id in PrimitiveType::all_impls(tcx) {
             // Try to inline primitive impls from other crates.
             if !def_id.is_local() {
-                inline::build_impl(cx, def_id, None, &mut new_items_external);
+                cx.with_param_env(def_id, |cx| {
+                    inline::build_impl(cx, def_id, None, &mut new_items_external);
+                });
             }
         }
         for (prim, did) in PrimitiveType::primitive_locations(tcx) {
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
index 1e327f7a6df..9365fbfaed0 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs
@@ -46,11 +46,10 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants {
             return;
         };
         if let ConstantSource::Constant = source
-            && let Some(node) = cx.tcx.hir().find_parent(e.hir_id)
             && let Node::Item(Item {
                 kind: ItemKind::Const(..),
                 ..
-            }) = node
+            }) = cx.tcx.parent_hir_node(e.hir_id)
         {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 0f29743856a..a31943f0021 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -67,25 +67,20 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>, msrv: &Msrv
 }
 
 fn is_child_of_cast(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let map = cx.tcx.hir();
-    if let Some(parent_id) = map.opt_parent_id(expr.hir_id) {
-        let parent = cx.tcx.hir_node(parent_id);
-        let expr = match parent {
-            Node::Block(block) => {
-                if let Some(parent_expr) = block.expr {
-                    parent_expr
-                } else {
-                    return false;
-                }
-            },
-            Node::Expr(expr) => expr,
-            _ => return false,
-        };
+    let parent = cx.tcx.parent_hir_node(expr.hir_id);
+    let expr = match parent {
+        Node::Block(block) => {
+            if let Some(parent_expr) = block.expr {
+                parent_expr
+            } else {
+                return false;
+            }
+        },
+        Node::Expr(expr) => expr,
+        _ => return false,
+    };
 
-        matches!(expr.kind, ExprKind::Cast(..))
-    } else {
-        false
-    }
+    matches!(expr.kind, ExprKind::Cast(..))
 }
 
 /// Returns the type T of the pointed to *const [T] or *mut [T] and the mutability of the slice if
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 81d0def4322..b4a23d0d4db 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -65,7 +65,7 @@ pub(super) fn check<'tcx>(
         && let ExprKind::Path(qpath) = inner.kind
         && let QPath::Resolved(None, Path { res, .. }) = qpath
         && let Res::Local(hir_id) = res
-        && let parent = cx.tcx.hir().get_parent(*hir_id)
+        && let parent = cx.tcx.parent_hir_node(*hir_id)
         && let Node::Local(local) = parent
     {
         if let Some(ty) = local.ty
diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
index 9424a9103db..ec66556cebf 100644
--- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs
+++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs
@@ -63,7 +63,7 @@ impl LateLintPass<'_> for DbgMacro {
                 ExprKind::Block(..) => {
                     // If the `dbg!` macro is a "free" statement and not contained within other expressions,
                     // remove the whole statement.
-                    if let Some(Node::Stmt(_)) = cx.tcx.hir().find_parent(expr.hir_id)
+                    if let Node::Stmt(_) = cx.tcx.parent_hir_node(expr.hir_id)
                         && let Some(semi_span) = cx.sess().source_map().mac_call_stmt_semi_span(macro_call.span)
                     {
                         (macro_call.span.to(semi_span), String::new())
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index d8a070b785d..8789efcc994 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                 // only when assigning `... = Default::default()`
                 && is_expr_default(expr, cx)
                 && let binding_type = cx.typeck_results().node_type(binding_id)
-                && let Some(adt) = binding_type.ty_adt_def()
+                && let ty::Adt(adt, args) = *binding_type.kind()
                 && adt.is_struct()
                 && let variant = adt.non_enum_variant()
                 && (adt.did().is_local() || !variant.is_field_list_non_exhaustive())
@@ -144,7 +144,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
                     .fields
                     .iter()
                     .all(|field| {
-                        is_copy(cx, cx.tcx.type_of(field.did).instantiate_identity())
+                        is_copy(cx, cx.tcx.type_of(field.did).instantiate(cx.tcx, args))
                     })
                 && (!has_drop(cx, binding_type) || all_fields_are_copy)
             {
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 c4437a3c4b3..59d2df0295f 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -128,8 +128,7 @@ impl<'a, 'tcx> Visitor<'tcx> for NumericFallbackVisitor<'a, 'tcx> {
                 },
                 _,
             ) => {
-                if let Some(parent) = self.cx.tcx.hir().find_parent(expr.hir_id)
-                    && let Some(fn_sig) = parent.fn_sig()
+                if let Some(fn_sig) = self.cx.tcx.parent_hir_node(expr.hir_id).fn_sig()
                     && let FnRetTy::Return(_ty) = fn_sig.decl.output
                 {
                     // We cannot check the exact type since it's a `hir::Ty`` which does not implement `is_numeric`
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 194cf69ea7e..cdbb52f497b 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -1088,7 +1088,7 @@ fn report<'tcx>(
                 //
                 // e.g. `&mut x.y.z` where `x` is a union, and accessing `z` requires a
                 // deref through `ManuallyDrop<_>` will not compile.
-                let parent_id = cx.tcx.hir().parent_id(expr.hir_id);
+                let parent_id = cx.tcx.parent_hir_id(expr.hir_id);
                 if parent_id == data.first_expr.hir_id {
                     return;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index 218d7c6c01a..064bac2e7dc 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -131,7 +131,7 @@ fn is_argument(tcx: TyCtxt<'_>, id: HirId) -> bool {
         _ => return false,
     }
 
-    matches!(tcx.hir().find_parent(id), Some(Node::Param(_)))
+    matches!(tcx.parent_hir_node(id), Node::Param(_))
 }
 
 impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
@@ -156,8 +156,8 @@ impl<'a, 'tcx> Delegate<'tcx> for EscapeDelegate<'a, 'tcx> {
             let map = &self.cx.tcx.hir();
             if is_argument(self.cx.tcx, cmt.hir_id) {
                 // Skip closure arguments
-                let parent_id = map.parent_id(cmt.hir_id);
-                if let Some(Node::Expr(..)) = map.find_parent(parent_id) {
+                let parent_id = self.cx.tcx.parent_hir_id(cmt.hir_id);
+                if let Node::Expr(..) = self.cx.tcx.parent_hir_node(parent_id) {
                     return;
                 }
 
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 8fba41c0e24..6fb38a0d6dd 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -53,7 +53,7 @@ pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body:
 
 pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
     if let ImplItemKind::Fn(_, body_id) = impl_item.kind
-        && let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id())
+        && let hir::Node::Item(item) = cx.tcx.parent_hir_node(impl_item.hir_id())
         && let hir::ItemKind::Impl(impl_) = item.kind
         && let hir::Impl { of_trait, .. } = *impl_
         && of_trait.is_none()
@@ -72,7 +72,7 @@ pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
 pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
     if !avoid_breaking_exported_api
         && let TraitItemKind::Fn(_, _) = trait_item.kind
-        && let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id())
+        && let hir::Node::Item(item) = cx.tcx.parent_hir_node(trait_item.hir_id())
         // ^^ (Will always be a trait)
         && !item.vis_span.is_empty() // Is public
         && !is_in_test_function(cx.tcx, trait_item.hir_id())
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index 0a2fd0c663e..80a537b9f94 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -41,8 +41,8 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
             return;
         }
 
-        match cx.tcx.hir().get_parent(pat.hir_id) {
-            Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
+        match cx.tcx.parent_hir_node(pat.hir_id) {
+            Node::Param(param) if matches!(cx.tcx.parent_hir_node(param.hir_id), Node::Item(_)) => {
                 // Ignore function parameters
                 return;
             },
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index 252be30c4e2..51b4f26b6d1 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -242,12 +242,8 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
             } = *self;
 
             if let Some(use_info) = slice_lint_info.get_mut(&local_id)
-                // Check if this is even a local we're interested in
-
-                && let map = cx.tcx.hir()
-
                 // Checking for slice indexing
-                && let parent_id = map.parent_id(expr.hir_id)
+                && let parent_id = cx.tcx.parent_hir_id(expr.hir_id)
                 && let hir::Node::Expr(parent_expr) = cx.tcx.hir_node(parent_id)
                 && let hir::ExprKind::Index(_, index_expr, _) = parent_expr.kind
                 && let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr)
@@ -255,11 +251,10 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> {
                 && index_value < max_suggested_slice
 
                 // Make sure that this slice index is read only
-                && let maybe_addrof_id = map.parent_id(parent_id)
-                && let hir::Node::Expr(maybe_addrof_expr) = cx.tcx.hir_node(maybe_addrof_id)
+                && let hir::Node::Expr(maybe_addrof_expr) = cx.tcx.parent_hir_node(parent_id)
                 && let hir::ExprKind::AddrOf(_kind, hir::Mutability::Not, _inner_expr) = maybe_addrof_expr.kind
             {
-                use_info.index_use.push((index_value, map.span(parent_expr.hir_id)));
+                use_info.index_use.push((index_value, cx.tcx.hir().span(parent_expr.hir_id)));
                 return;
             }
 
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
index 82a37bb4f27..b5821d909f8 100644
--- a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -269,7 +269,7 @@ impl {self_ty_without_ref} {{
                     // }
                     let span_behind_impl = cx
                         .tcx
-                        .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id)
+                        .def_span(cx.tcx.parent_hir_id(item.hir_id()).owner.def_id)
                         .shrink_to_lo();
 
                     let sugg = format!(
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index f5636945f20..2b73663d229 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -285,7 +285,7 @@ fn elision_suggestions(
             .iter()
             .filter(|usage| named_lifetime(usage).map_or(false, |id| elidable_lts.contains(&id)))
             .map(|usage| {
-                match cx.tcx.hir().get_parent(usage.hir_id) {
+                match cx.tcx.parent_hir_node(usage.hir_id) {
                     Node::Ty(Ty {
                         kind: TyKind::Ref(..), ..
                     }) => {
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 5f015db2b33..0f35514b8ad 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
@@ -62,8 +62,7 @@ pub(super) fn check<'tcx>(
                         if let Node::Pat(pat) = node
                             && let PatKind::Binding(bind_ann, ..) = pat.kind
                             && !matches!(bind_ann, BindingAnnotation(_, Mutability::Mut))
-                            && let parent_node = cx.tcx.hir().parent_id(hir_id)
-                            && let Node::Local(parent_let_expr) = cx.tcx.hir_node(parent_node)
+                            && let Node::Local(parent_let_expr) = cx.tcx.parent_hir_node(hir_id)
                             && let Some(init) = parent_let_expr.init
                         {
                             match init.kind {
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
index 73687fbbe54..5cbab0ec977 100644
--- a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -68,8 +68,8 @@ impl LateLintPass<'_> for ManualHashOne {
             && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
             && seg.ident.name == sym!(build_hasher)
 
-            && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id)
-            && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id)
+            && let Node::Stmt(local_stmt) = cx.tcx.parent_hir_node(local.hir_id)
+            && let Node::Block(block) = cx.tcx.parent_hir_node(local_stmt.hir_id)
 
             && let mut stmts = block.stmts.iter()
                 .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id)
@@ -91,7 +91,7 @@ impl LateLintPass<'_> for ManualHashOne {
 
             // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block
             && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher)
-            && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id)
+            && let Node::Expr(finish_expr) = cx.tcx.parent_hir_node(path_expr.hir_id)
             && !finish_expr.span.from_expansion()
             && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
             && seg.ident.name == sym!(finish)
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index e1768c6d976..0bde62bd554 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -79,9 +79,9 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
             && let Node::Pat(_) = cx.tcx.hir_node(hir_id)
         {
             // Apply only to params or locals with annotated types
-            match cx.tcx.hir().find_parent(hir_id) {
-                Some(Node::Param(..)) => (),
-                Some(Node::Local(local)) => {
+            match cx.tcx.parent_hir_node(hir_id) {
+                Node::Param(..) => (),
+                Node::Local(local) => {
                     let Some(ty) = local.ty else { return };
                     if matches!(ty.kind, TyKind::Infer) {
                         return;
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
index 89da7a55cbd..61977045fd4 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_single_binding.rs
@@ -36,7 +36,7 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
     .to_string();
 
     // Do we need to add ';' to suggestion ?
-    if let Node::Stmt(stmt) = cx.tcx.hir().get_parent(expr.hir_id)
+    if let Node::Stmt(stmt) = cx.tcx.parent_hir_node(expr.hir_id)
         && let StmtKind::Expr(_) = stmt.kind
         && match match_body.kind {
             // We don't need to add a ; to blocks, unless that block is from a macro expansion
@@ -146,18 +146,16 @@ pub(crate) fn check<'a>(cx: &LateContext<'a>, ex: &Expr<'a>, arms: &[Arm<'_>], e
 
 /// Returns true if the `ex` match expression is in a local (`let`) or assign expression
 fn opt_parent_assign_span<'a>(cx: &LateContext<'a>, ex: &Expr<'a>) -> Option<AssignmentExpr> {
-    let map = &cx.tcx.hir();
-
-    if let Some(Node::Expr(parent_arm_expr)) = map.find_parent(ex.hir_id) {
-        return match map.find_parent(parent_arm_expr.hir_id) {
-            Some(Node::Local(parent_let_expr)) => Some(AssignmentExpr::Local {
+    if let Node::Expr(parent_arm_expr) = cx.tcx.parent_hir_node(ex.hir_id) {
+        return match cx.tcx.parent_hir_node(parent_arm_expr.hir_id) {
+            Node::Local(parent_let_expr) => Some(AssignmentExpr::Local {
                 span: parent_let_expr.span,
                 pat_span: parent_let_expr.pat.span(),
             }),
-            Some(Node::Expr(Expr {
+            Node::Expr(Expr {
                 kind: ExprKind::Assign(parent_assign_expr, match_expr, _),
                 ..
-            })) => Some(AssignmentExpr::Assign {
+            }) => Some(AssignmentExpr::Assign {
                 span: parent_assign_expr.span,
                 match_span: match_expr.span,
             }),
@@ -191,7 +189,7 @@ fn sugg_with_curlies<'a>(
 
     // If the parent is already an arm, and the body is another match statement,
     // we need curly braces around suggestion
-    if let Node::Arm(arm) = &cx.tcx.hir().get_parent(match_expr.hir_id) {
+    if let Node::Arm(arm) = &cx.tcx.parent_hir_node(match_expr.hir_id) {
         if let ExprKind::Match(..) = arm.body.kind {
             cbrace_end = format!("\n{indent}}}");
             // Fix body indent due to the match
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index dfaaeb14ca3..a1b82679f2e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -199,7 +199,7 @@ fn get_pat_binding<'tcx>(
             return span.map(|span| PatBindingInfo {
                 span,
                 byref_ident,
-                is_field: matches!(cx.tcx.hir().get_parent(local), Node::PatField(_)),
+                is_field: matches!(cx.tcx.parent_hir_node(local), Node::PatField(_)),
             });
         }
     }
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e8a7a321bf4..1452547807b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -4458,7 +4458,7 @@ impl Methods {
                     _ => {},
                 },
                 ("drain", ..) => {
-                    if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.hir().get_parent(expr.hir_id)
+                    if let Node::Stmt(Stmt { hir_id: _, kind, .. }) = cx.tcx.parent_hir_node(expr.hir_id)
                         && matches!(kind, StmtKind::Semi(_))
                         && args.len() <= 1
                     {
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index 1184dd4525a..6c6846c4b47 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -21,9 +21,9 @@ fn is_unwrap_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 
 pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver: &Expr<'_>) {
     if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver).peel_refs(), sym::RwLock)
-        && let Node::Expr(unwrap_call_expr) = cx.tcx.hir().get_parent(expr.hir_id)
+        && let Node::Expr(unwrap_call_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_unwrap_call(cx, unwrap_call_expr)
-        && let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
+        && let parent = cx.tcx.parent_hir_node(unwrap_call_expr.hir_id)
         && let Node::Local(local) = parent
         && let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
         && let Some((local, _)) = mir
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 2046692bbd0..988f3e86fcf 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -16,7 +16,7 @@ use super::UNNECESSARY_FOLD;
 /// Changing `fold` to `sum` needs it sometimes when the return type can't be
 /// inferred. This checks for some common cases where it can be safely omitted
 fn needs_turbofish(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
-    let parent = cx.tcx.hir().get_parent(expr.hir_id);
+    let parent = cx.tcx.parent_hir_node(expr.hir_id);
 
     // some common cases where turbofish isn't needed:
     // - assigned to a local variable with a type annotation
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index a1125d70db3..1b2bfbf4090 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -76,7 +76,7 @@ pub(super) fn check(
                     (expr.span.with_lo(call_args[0].span.hi()), String::new()),
                 ];
                 // try to also remove the unsafe block if present
-                if let hir::Node::Block(block) = cx.tcx.hir().get_parent(expr.hir_id)
+                if let hir::Node::Block(block) = cx.tcx.parent_hir_node(expr.hir_id)
                     && let hir::BlockCheckMode::UnsafeBlock(hir::UnsafeSource::UserProvided) = block.rules
                 {
                     suggs.extend([
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index b593e48ae2e..a1f7dc7b38c 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -206,10 +206,9 @@ impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
 ///
 /// When such a read is found, the lint is triggered.
 fn check_for_unsequenced_reads(vis: &mut ReadVisitor<'_, '_>) {
-    let map = &vis.cx.tcx.hir();
     let mut cur_id = vis.write_expr.hir_id;
     loop {
-        let parent_id = map.parent_id(cur_id);
+        let parent_id = vis.cx.tcx.parent_hir_id(cur_id);
         if parent_id == cur_id {
             break;
         }
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index d2eef6ae433..149d440ecac 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -161,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
         };
 
         // Exclude non-inherent impls
-        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+        if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 2c5c3dcaa75..384a402ce5b 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
         }
 
         // Exclude non-inherent impls
-        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+        if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 10ab380ba1b..ea73d9afa2e 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -449,7 +449,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
             let mut dereferenced_expr = expr;
             let mut needs_check_adjustment = true;
             loop {
-                let parent_id = cx.tcx.hir().parent_id(cur_expr.hir_id);
+                let parent_id = cx.tcx.parent_hir_id(cur_expr.hir_id);
                 if parent_id == cur_expr.hir_id {
                     break;
                 }
diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
index 40d4a842bef..2a933a11e12 100644
--- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs
@@ -34,7 +34,7 @@ pub(super) fn check<'tcx>(
 }
 
 fn used_in_comparison_with_zero(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    let Some(Node::Expr(parent_expr)) = cx.tcx.hir().find_parent(expr.hir_id) else {
+    let Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id) else {
         return false;
     };
     let ExprKind::Binary(op, lhs, rhs) = parent_expr.kind else {
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 57d37067e8f..ec03ab0e41a 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
@@ -301,7 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue {
         }
 
         // Exclude non-inherent impls
-        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+        if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
index 513a913f56a..bbecc39a813 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmutes_expressible_as_ptr_casts.rs
@@ -41,7 +41,7 @@ pub(super) fn check<'tcx>(
         _ => return false,
     };
 
-    if let Node::Expr(parent) = cx.tcx.hir().get_parent(e.hir_id)
+    if let Node::Expr(parent) = cx.tcx.parent_hir_node(e.hir_id)
         && parent.precedence().order() > ExprPrecedence::Cast.order()
     {
         sugg = format!("({sugg})");
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index e1cd82e18d5..c11504cd2d4 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -153,13 +153,10 @@ fn all_bindings_are_for_conv<'tcx>(
     let Some(locals) = locals.iter().map(|e| path_to_local(e)).collect::<Option<Vec<_>>>() else {
         return false;
     };
-    let Some(local_parents) = locals
+    let local_parents = locals
         .iter()
-        .map(|&l| cx.tcx.hir().find_parent(l))
-        .collect::<Option<Vec<_>>>()
-    else {
-        return false;
-    };
+        .map(|l| cx.tcx.parent_hir_node(*l))
+        .collect::<Vec<_>>();
 
     local_parents
         .iter()
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
index 44cff78a793..eba7fa7b993 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/unit_arg.rs
@@ -19,9 +19,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
     if is_questionmark_desugar_marked_call(expr) {
         return;
     }
-    let map = &cx.tcx.hir();
-    let opt_parent_node = map.find_parent(expr.hir_id);
-    if let Some(hir::Node::Expr(parent_expr)) = opt_parent_node
+    if let hir::Node::Expr(parent_expr) = cx.tcx.parent_hir_node(expr.hir_id)
         && is_questionmark_desugar_marked_call(parent_expr)
     {
         return;
@@ -183,8 +181,8 @@ fn fmt_stmts_and_call(
 
     let mut stmts_and_call_snippet = stmts_and_call.join(&format!("{}{}", ";\n", " ".repeat(call_expr_indent)));
     // expr is not in a block statement or result expression position, wrap in a block
-    let parent_node = cx.tcx.hir().find_parent(call_expr.hir_id);
-    if !matches!(parent_node, Some(Node::Block(_))) && !matches!(parent_node, Some(Node::Stmt(_))) {
+    let parent_node = cx.tcx.parent_hir_node(call_expr.hir_id);
+    if !matches!(parent_node, Node::Block(_)) && !matches!(parent_node, Node::Stmt(_)) {
         let block_indent = call_expr_indent + 4;
         stmts_and_call_snippet =
             reindent_multiline(stmts_and_call_snippet.into(), true, Some(block_indent)).into_owned();
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index f5af540fa14..c332cf076ae 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -116,7 +116,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns {
     fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
         // Ignore implementations of traits, because the lint should be on the
         // trait, not on the implementation of it.
-        let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else {
+        let Node::Item(parent) = cx.tcx.parent_hir_node(item.hir_id()) else {
             return;
         };
         let ItemKind::Impl(parent) = parent.kind else { return };
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index 446160f8e0f..9c8b0ae1727 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -92,7 +92,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps {
 
         // Abort if the method is implementing a trait or of it a trait method.
         let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
-        if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+        if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
             if matches!(
                 item.kind,
                 ItemKind::Impl(Impl { of_trait: Some(_), .. }) | ItemKind::Trait(..)
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index 1d42375ba8e..738fba54fa8 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -156,7 +156,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync {
             && let Some(local_def_id) = def_id.as_local()
             && cx.tcx.def_kind(def_id) == DefKind::Fn
             && cx.tcx.asyncness(def_id).is_async()
-            && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span)
+            && !is_node_func_call(cx.tcx.parent_hir_node(hir_id), path.span)
         {
             self.async_fns_as_value.insert(local_def_id);
         }
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index ae2ac38cffe..f2eb774b5cb 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -208,7 +208,7 @@ struct MutationVisitor<'tcx> {
 /// (i.e. the `x` in `x.as_mut()`), and that is the reason for why we care about its parent
 /// expression: that will be where the actual method call is.
 fn is_option_as_mut_use(tcx: TyCtxt<'_>, expr_id: HirId) -> bool {
-    if let Node::Expr(mutating_expr) = tcx.hir().get_parent(expr_id)
+    if let Node::Expr(mutating_expr) = tcx.parent_hir_node(expr_id)
         && let ExprKind::MethodCall(path, ..) = mutating_expr.kind
     {
         path.ident.name.as_str() == "as_mut"
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index 2e0a0f6cb3e..f7a455977fa 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -86,7 +86,6 @@ fn into_iter_bound<'tcx>(
     param_index: u32,
     node_args: GenericArgsRef<'tcx>,
 ) -> Option<Span> {
-    let param_env = cx.tcx.param_env(fn_did);
     let mut into_iter_span = None;
 
     for (pred, span) in cx.tcx.explicit_predicates_of(fn_did).predicates {
@@ -111,7 +110,7 @@ fn into_iter_bound<'tcx>(
                     }));
 
                     let predicate = EarlyBinder::bind(tr).instantiate(cx.tcx, args);
-                    let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), param_env, predicate);
+                    let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
                     if !cx
                         .tcx
                         .infer_ctxt()
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index fae1b90ace2..349e0e3e077 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -1007,9 +1007,9 @@ fn get_parent_local<'hir>(cx: &LateContext<'hir>, expr: &'hir hir::Expr<'hir>) -
 fn get_parent_local_hir_id<'hir>(cx: &LateContext<'hir>, hir_id: hir::HirId) -> Option<&'hir hir::Local<'hir>> {
     let map = cx.tcx.hir();
 
-    match map.find_parent(hir_id) {
-        Some(hir::Node::Local(local)) => Some(local),
-        Some(hir::Node::Pat(pattern)) => get_parent_local_hir_id(cx, pattern.hir_id),
+    match cx.tcx.parent_hir_node(hir_id) {
+        hir::Node::Local(local) => Some(local),
+        hir::Node::Pat(pattern) => get_parent_local_hir_id(cx, pattern.hir_id),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index 6e449dc9806..38c832931fc 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -217,8 +217,7 @@ fn path_to_matched_type(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<Ve
     match peel_hir_expr_refs(expr).0.kind {
         ExprKind::Path(ref qpath) => match cx.qpath_res(qpath, expr.hir_id) {
             Res::Local(hir_id) => {
-                let parent_id = cx.tcx.hir().parent_id(hir_id);
-                if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.hir_node(parent_id) {
+                if let Node::Local(Local { init: Some(init), .. }) = cx.tcx.parent_hir_node(hir_id) {
                     path_to_matched_type(cx, init)
                 } else {
                     None
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index 2c33c93412a..b3489142558 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
         if let Some(vec_args) = higher::VecArgs::hir(cx, expr.peel_borrows()) {
             // search for `let foo = vec![_]` expressions where all uses of `foo`
             // adjust to slices or call a method that exist on slices (e.g. len)
-            if let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
+            if let Node::Local(local) = cx.tcx.parent_hir_node(expr.hir_id)
                 // for now ignore locals with type annotations.
                 // this is to avoid compile errors when doing the suggestion here: let _: Vec<_> = vec![..];
                 && local.ty.is_none()
@@ -103,7 +103,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
             }
             // if the local pattern has a specified type, do not lint.
             else if let Some(_) = higher::VecArgs::hir(cx, expr)
-                && let Node::Local(local) = cx.tcx.hir().get_parent(expr.hir_id)
+                && let Node::Local(local) = cx.tcx.parent_hir_node(expr.hir_id)
                 && local.ty.is_some()
             {
                 let span = expr.span.ctxt().outer_expn_data().call_site;
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 6a33e11be46..67a18caca0e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -182,11 +182,9 @@ pub fn expr_or_init<'a, 'b, 'tcx: 'b>(cx: &LateContext<'tcx>, mut expr: &'a Expr
 /// Note: If you have an expression that references a binding `x`, use `path_to_local` to get the
 /// canonical binding `HirId`.
 pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option<&'tcx Expr<'tcx>> {
-    let hir = cx.tcx.hir();
     if let Node::Pat(pat) = cx.tcx.hir_node(hir_id)
         && matches!(pat.kind, PatKind::Binding(BindingAnnotation::NONE, ..))
-        && let parent = hir.parent_id(hir_id)
-        && let Node::Local(local) = cx.tcx.hir_node(parent)
+        && let Node::Local(local) = cx.tcx.parent_hir_node(hir_id)
     {
         return local.init;
     }
@@ -333,7 +331,7 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
 /// Checks if the `def_id` belongs to a function that is part of a trait impl.
 pub fn is_def_id_trait_method(cx: &LateContext<'_>, def_id: LocalDefId) -> bool {
     if let Some(hir_id) = cx.tcx.opt_local_def_id_to_hir_id(def_id)
-        && let Node::Item(item) = cx.tcx.hir().get_parent(hir_id)
+        && let Node::Item(item) = cx.tcx.parent_hir_node(hir_id)
         && let ItemKind::Impl(imp) = item.kind
     {
         imp.of_trait.is_some()
@@ -1311,7 +1309,7 @@ pub fn contains_return<'tcx>(expr: impl Visitable<'tcx>) -> bool {
 
 /// Gets the parent node, if any.
 pub fn get_parent_node(tcx: TyCtxt<'_>, id: HirId) -> Option<Node<'_>> {
-    tcx.hir().find_parent(id)
+    Some(tcx.parent_hir_node(id))
 }
 
 /// Gets the parent expression, if any –- this is useful to constrain a lint.
@@ -2227,7 +2225,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
 /// }
 /// ```
 pub fn is_trait_impl_item(cx: &LateContext<'_>, hir_id: HirId) -> bool {
-    if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) {
+    if let Node::Item(item) = cx.tcx.parent_hir_node(hir_id) {
         matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }))
     } else {
         false
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index adca2ca1c3e..7913926928f 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -237,7 +237,7 @@ fn path_segment_certainty(
         },
 
         // `get_parent` because `hir_id` refers to a `Pat`, and we're interested in the node containing the `Pat`.
-        Res::Local(hir_id) => match cx.tcx.hir().get_parent(hir_id) {
+        Res::Local(hir_id) => match cx.tcx.parent_hir_node(hir_id) {
             // An argument's type is always certain.
             Node::Param(..) => Certainty::Certain(None),
             // A local's type is certain if its type annotation is certain or it has an initializer whose
diff --git a/src/tools/clippy/tests/integration.rs b/src/tools/clippy/tests/integration.rs
index 267f095f9c2..7f4500826ff 100644
--- a/src/tools/clippy/tests/integration.rs
+++ b/src/tools/clippy/tests/integration.rs
@@ -77,7 +77,7 @@ fn integration_test() {
         // the repo basically just contains a span_delayed_bug that forces rustc/clippy to panic:
         /*
            #![feature(rustc_attrs)]
-           #[rustc_error(span_delayed_bug_from_inside_query)]
+           #[rustc_error(delayed_bug_from_inside_query)]
            fn main() {}
         */
 
diff --git a/src/tools/linkchecker/Cargo.toml b/src/tools/linkchecker/Cargo.toml
index 1d8f2f91882..318a69ab835 100644
--- a/src/tools/linkchecker/Cargo.toml
+++ b/src/tools/linkchecker/Cargo.toml
@@ -10,3 +10,4 @@ path = "main.rs"
 [dependencies]
 regex = "1"
 once_cell = "1"
+html5ever = "0.26.0"
diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs
index 7f73cac63cb..f49c6e79f13 100644
--- a/src/tools/linkchecker/main.rs
+++ b/src/tools/linkchecker/main.rs
@@ -14,6 +14,12 @@
 //! A few exceptions are allowed as there's known bugs in rustdoc, but this
 //! should catch the majority of "broken link" cases.
 
+use html5ever::tendril::ByteTendril;
+use html5ever::tokenizer::{
+    BufferQueue, TagToken, Token, TokenSink, TokenSinkResult, Tokenizer, TokenizerOpts,
+};
+use once_cell::sync::Lazy;
+use regex::Regex;
 use std::cell::RefCell;
 use std::collections::{HashMap, HashSet};
 use std::env;
@@ -23,9 +29,6 @@ use std::path::{Component, Path, PathBuf};
 use std::rc::Rc;
 use std::time::Instant;
 
-use once_cell::sync::Lazy;
-use regex::Regex;
-
 // Add linkcheck exceptions here
 // If at all possible you should use intra-doc links to avoid linkcheck issues. These
 // are cases where that does not work
@@ -182,171 +185,171 @@ impl Checker {
             }
         };
 
-        // Search for anything that's the regex 'href[ ]*=[ ]*".*?"'
-        with_attrs_in_source(&source, " href", |url, i, base| {
-            // Ignore external URLs
-            if url.starts_with("http:")
-                || url.starts_with("https:")
-                || url.starts_with("javascript:")
-                || url.starts_with("ftp:")
-                || url.starts_with("irc:")
-                || url.starts_with("data:")
-                || url.starts_with("mailto:")
-            {
-                report.links_ignored_external += 1;
-                return;
-            }
-            report.links_checked += 1;
-            let (url, fragment) = match url.split_once('#') {
-                None => (url, None),
-                Some((url, fragment)) => (url, Some(fragment)),
-            };
-            // NB: the `splitn` always succeeds, even if the delimiter is not present.
-            let url = url.splitn(2, '?').next().unwrap();
-
-            // Once we've plucked out the URL, parse it using our base url and
-            // then try to extract a file path.
-            let mut path = file.to_path_buf();
-            if !base.is_empty() || !url.is_empty() {
-                path.pop();
-                for part in Path::new(base).join(url).components() {
-                    match part {
-                        Component::Prefix(_) | Component::RootDir => {
-                            // Avoid absolute paths as they make the docs not
-                            // relocatable by making assumptions on where the docs
-                            // are hosted relative to the site root.
-                            report.errors += 1;
-                            println!(
-                                "{}:{}: absolute path - {}",
-                                pretty_path,
-                                i + 1,
-                                Path::new(base).join(url).display()
-                            );
-                            return;
-                        }
-                        Component::CurDir => {}
-                        Component::ParentDir => {
-                            path.pop();
-                        }
-                        Component::Normal(s) => {
-                            path.push(s);
-                        }
-                    }
-                }
-            }
+        let (base, urls) = get_urls(&source);
+        for (i, url) in urls {
+            self.check_url(file, &pretty_path, report, &base, i, &url);
+        }
 
-            let (target_pretty_path, target_entry) = self.load_file(&path, report);
-            let (target_source, target_ids) = match target_entry {
-                FileEntry::Missing => {
-                    if is_exception(file, &target_pretty_path) {
-                        report.links_ignored_exception += 1;
-                    } else {
+        self.check_intra_doc_links(file, &pretty_path, &source, report);
+
+        // we don't need the source anymore,
+        // so drop to reduce memory-usage
+        match self.cache.get_mut(&pretty_path).unwrap() {
+            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
+            _ => unreachable!("must be html file"),
+        }
+    }
+
+    fn check_url(
+        &mut self,
+        file: &Path,
+        pretty_path: &str,
+        report: &mut Report,
+        base: &Option<String>,
+        i: u64,
+        url: &str,
+    ) {
+        // Ignore external URLs
+        if url.starts_with("http:")
+            || url.starts_with("https:")
+            || url.starts_with("javascript:")
+            || url.starts_with("ftp:")
+            || url.starts_with("irc:")
+            || url.starts_with("data:")
+            || url.starts_with("mailto:")
+        {
+            report.links_ignored_external += 1;
+            return;
+        }
+        report.links_checked += 1;
+        let (url, fragment) = match url.split_once('#') {
+            None => (url, None),
+            Some((url, fragment)) => (url, Some(fragment)),
+        };
+        // NB: the `splitn` always succeeds, even if the delimiter is not present.
+        let url = url.splitn(2, '?').next().unwrap();
+
+        // Once we've plucked out the URL, parse it using our base url and
+        // then try to extract a file path.
+        let mut path = file.to_path_buf();
+        if base.is_some() || !url.is_empty() {
+            let base = base.as_deref().unwrap_or("");
+            path.pop();
+            for part in Path::new(base).join(url).components() {
+                match part {
+                    Component::Prefix(_) | Component::RootDir => {
+                        // Avoid absolute paths as they make the docs not
+                        // relocatable by making assumptions on where the docs
+                        // are hosted relative to the site root.
                         report.errors += 1;
                         println!(
-                            "{}:{}: broken link - `{}`",
+                            "{}:{}: absolute path - {}",
                             pretty_path,
-                            i + 1,
-                            target_pretty_path
+                            i,
+                            Path::new(base).join(url).display()
                         );
+                        return;
+                    }
+                    Component::CurDir => {}
+                    Component::ParentDir => {
+                        path.pop();
+                    }
+                    Component::Normal(s) => {
+                        path.push(s);
                     }
-                    return;
                 }
-                FileEntry::Dir => {
-                    // Links to directories show as directory listings when viewing
-                    // the docs offline so it's best to avoid them.
+            }
+        }
+
+        let (target_pretty_path, target_entry) = self.load_file(&path, report);
+        let (target_source, target_ids) = match target_entry {
+            FileEntry::Missing => {
+                if is_exception(file, &target_pretty_path) {
+                    report.links_ignored_exception += 1;
+                } else {
                     report.errors += 1;
-                    println!(
-                        "{}:{}: directory link to `{}` \
-                         (directory links should use index.html instead)",
-                        pretty_path,
-                        i + 1,
-                        target_pretty_path
-                    );
-                    return;
+                    println!("{}:{}: broken link - `{}`", pretty_path, i, target_pretty_path);
                 }
-                FileEntry::OtherFile => return,
-                FileEntry::Redirect { target } => {
-                    let t = target.clone();
-                    let (target, redir_entry) = self.load_file(&t, report);
-                    match redir_entry {
-                        FileEntry::Missing => {
-                            report.errors += 1;
-                            println!(
-                                "{}:{}: broken redirect from `{}` to `{}`",
-                                pretty_path,
-                                i + 1,
-                                target_pretty_path,
-                                target
-                            );
-                            return;
-                        }
-                        FileEntry::Redirect { target } => {
-                            // Redirect to a redirect, this link checker
-                            // currently doesn't support this, since it would
-                            // require cycle checking, etc.
-                            report.errors += 1;
-                            println!(
-                                "{}:{}: redirect from `{}` to `{}` \
+                return;
+            }
+            FileEntry::Dir => {
+                // Links to directories show as directory listings when viewing
+                // the docs offline so it's best to avoid them.
+                report.errors += 1;
+                println!(
+                    "{}:{}: directory link to `{}` \
+                         (directory links should use index.html instead)",
+                    pretty_path, i, target_pretty_path
+                );
+                return;
+            }
+            FileEntry::OtherFile => return,
+            FileEntry::Redirect { target } => {
+                let t = target.clone();
+                let (target, redir_entry) = self.load_file(&t, report);
+                match redir_entry {
+                    FileEntry::Missing => {
+                        report.errors += 1;
+                        println!(
+                            "{}:{}: broken redirect from `{}` to `{}`",
+                            pretty_path, i, target_pretty_path, target
+                        );
+                        return;
+                    }
+                    FileEntry::Redirect { target } => {
+                        // Redirect to a redirect, this link checker
+                        // currently doesn't support this, since it would
+                        // require cycle checking, etc.
+                        report.errors += 1;
+                        println!(
+                            "{}:{}: redirect from `{}` to `{}` \
                                  which is also a redirect (not supported)",
-                                pretty_path,
-                                i + 1,
-                                target_pretty_path,
-                                target.display()
-                            );
-                            return;
-                        }
-                        FileEntry::Dir => {
-                            report.errors += 1;
-                            println!(
-                                "{}:{}: redirect from `{}` to `{}` \
+                            pretty_path,
+                            i,
+                            target_pretty_path,
+                            target.display()
+                        );
+                        return;
+                    }
+                    FileEntry::Dir => {
+                        report.errors += 1;
+                        println!(
+                            "{}:{}: redirect from `{}` to `{}` \
                                  which is a directory \
                                  (directory links should use index.html instead)",
-                                pretty_path,
-                                i + 1,
-                                target_pretty_path,
-                                target
-                            );
-                            return;
-                        }
-                        FileEntry::OtherFile => return,
-                        FileEntry::HtmlFile { source, ids } => (source, ids),
+                            pretty_path, i, target_pretty_path, target
+                        );
+                        return;
                     }
+                    FileEntry::OtherFile => return,
+                    FileEntry::HtmlFile { source, ids } => (source, ids),
                 }
-                FileEntry::HtmlFile { source, ids } => (source, ids),
-            };
-
-            // Alright, if we've found an HTML file for the target link. If
-            // this is a fragment link, also check that the `id` exists.
-            if let Some(ref fragment) = fragment {
-                // Fragments like `#1-6` are most likely line numbers to be
-                // interpreted by javascript, so we're ignoring these
-                if fragment.splitn(2, '-').all(|f| f.chars().all(|c| c.is_numeric())) {
-                    return;
-                }
+            }
+            FileEntry::HtmlFile { source, ids } => (source, ids),
+        };
 
-                parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
+        // Alright, if we've found an HTML file for the target link. If
+        // this is a fragment link, also check that the `id` exists.
+        if let Some(ref fragment) = fragment {
+            // Fragments like `#1-6` are most likely line numbers to be
+            // interpreted by javascript, so we're ignoring these
+            if fragment.splitn(2, '-').all(|f| f.chars().all(|c| c.is_numeric())) {
+                return;
+            }
 
-                if target_ids.borrow().contains(*fragment) {
-                    return;
-                }
+            parse_ids(&mut target_ids.borrow_mut(), &pretty_path, target_source, report);
 
-                if is_exception(file, &format!("#{}", fragment)) {
-                    report.links_ignored_exception += 1;
-                } else {
-                    report.errors += 1;
-                    print!("{}:{}: broken link fragment ", pretty_path, i + 1);
-                    println!("`#{}` pointing to `{}`", fragment, target_pretty_path);
-                };
+            if target_ids.borrow().contains(*fragment) {
+                return;
             }
-        });
 
-        self.check_intra_doc_links(file, &pretty_path, &source, report);
-
-        // we don't need the source anymore,
-        // so drop to reduce memory-usage
-        match self.cache.get_mut(&pretty_path).unwrap() {
-            FileEntry::HtmlFile { source, .. } => *source = Rc::new(String::new()),
-            _ => unreachable!("must be html file"),
+            if is_exception(file, &format!("#{}", fragment)) {
+                report.links_ignored_exception += 1;
+            } else {
+                report.errors += 1;
+                print!("{}:{}: broken link fragment ", pretty_path, i);
+                println!("`#{}` pointing to `{}`", fragment, target_pretty_path);
+            };
         }
     }
 
@@ -496,59 +499,93 @@ fn maybe_redirect(source: &str) -> Option<String> {
     find_redirect(REDIRECT_RUSTDOC).or_else(|| find_redirect(REDIRECT_MDBOOK))
 }
 
-fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, mut f: F) {
-    let mut base = "";
-    for (i, mut line) in source.lines().enumerate() {
-        while let Some(j) = line.find(attr) {
-            let rest = &line[j + attr.len()..];
-            // The base tag should always be the first link in the document so
-            // we can get away with using one pass.
-            let is_base = line[..j].ends_with("<base");
-            line = rest;
-            let pos_equals = match rest.find('=') {
-                Some(i) => i,
-                None => continue,
-            };
-            if rest[..pos_equals].trim_start_matches(' ') != "" {
-                continue;
-            }
+fn parse_html<Sink: TokenSink>(source: &str, sink: Sink) -> Sink {
+    let tendril: ByteTendril = source.as_bytes().into();
+    let mut input = BufferQueue::new();
+    input.push_back(tendril.try_reinterpret().unwrap());
 
-            let rest = &rest[pos_equals + 1..];
+    let mut tok = Tokenizer::new(sink, TokenizerOpts::default());
+    let _ = tok.feed(&mut input);
+    assert!(input.is_empty());
+    tok.end();
+    tok.sink
+}
 
-            let pos_quote = match rest.find(&['"', '\''][..]) {
-                Some(i) => i,
-                None => continue,
-            };
-            let quote_delim = rest.as_bytes()[pos_quote] as char;
+#[derive(Default)]
+struct AttrCollector {
+    attr_name: &'static [u8],
+    base: Option<String>,
+    found_attrs: Vec<(u64, String)>,
+    /// Tracks whether or not it is inside a <script> tag.
+    ///
+    /// A lot of our sources have JSON script tags which have HTML embedded
+    /// within, but that cannot be parsed or processed correctly (since it is
+    /// JSON, not HTML). I think the sink is supposed to return
+    /// `TokenSinkResult::Script(…)` (and then maybe switch parser?), but I
+    /// don't fully understand the best way to use that, and this seems good
+    /// enough for now.
+    in_script: bool,
+}
 
-            if rest[..pos_quote].trim_start_matches(' ') != "" {
-                continue;
-            }
-            let rest = &rest[pos_quote + 1..];
-            let url = match rest.find(quote_delim) {
-                Some(i) => &rest[..i],
-                None => continue,
-            };
-            if is_base {
-                base = url;
-                continue;
+impl TokenSink for AttrCollector {
+    type Handle = ();
+
+    fn process_token(&mut self, token: Token, line_number: u64) -> TokenSinkResult<()> {
+        match token {
+            TagToken(tag) => {
+                let tag_name = tag.name.as_bytes();
+                if tag_name == b"base" {
+                    if let Some(href) =
+                        tag.attrs.iter().find(|attr| attr.name.local.as_bytes() == b"href")
+                    {
+                        self.base = Some(href.value.to_string());
+                    }
+                    return TokenSinkResult::Continue;
+                } else if tag_name == b"script" {
+                    self.in_script = !self.in_script;
+                }
+                if self.in_script {
+                    return TokenSinkResult::Continue;
+                }
+                for attr in tag.attrs.iter() {
+                    let name = attr.name.local.as_bytes();
+                    if name == self.attr_name {
+                        let url = attr.value.to_string();
+                        self.found_attrs.push((line_number, url));
+                    }
+                }
             }
-            f(url, i, base)
+            // Note: ParseError is pretty noisy. It seems html5ever does not
+            // particularly like some kinds of HTML comments.
+            _ => {}
         }
+        TokenSinkResult::Continue
     }
 }
 
+/// Retrieves href="..." attributes from HTML elements.
+fn get_urls(source: &str) -> (Option<String>, Vec<(u64, String)>) {
+    let collector = AttrCollector { attr_name: b"href", ..AttrCollector::default() };
+    let sink = parse_html(source, collector);
+    (sink.base, sink.found_attrs)
+}
+
+/// Retrieves id="..." attributes from HTML elements.
 fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) {
-    if ids.is_empty() {
-        with_attrs_in_source(source, " id", |fragment, i, _| {
-            let frag = fragment.trim_start_matches('#').to_owned();
-            let encoded = small_url_encode(&frag);
-            if !ids.insert(frag) {
-                report.errors += 1;
-                println!("{}:{}: id is not unique: `{}`", file, i, fragment);
-            }
-            // Just in case, we also add the encoded id.
-            ids.insert(encoded);
-        });
+    if !ids.is_empty() {
+        // ids have already been parsed
+        return;
+    }
+
+    let collector = AttrCollector { attr_name: b"id", ..AttrCollector::default() };
+    let sink = parse_html(source, collector);
+    for (line_number, id) in sink.found_attrs {
+        let encoded = small_url_encode(&id);
+        if let Some(id) = ids.replace(id) {
+            report.errors += 1;
+            println!("{}:{}: id is not unique: `{}`", file, line_number, id);
+        }
+        // Just in case, we also add the encoded id.
+        ids.insert(encoded);
     }
 }
diff --git a/src/tools/linkchecker/tests/broken_intra_doc_link/foo.html b/src/tools/linkchecker/tests/broken_intra_doc_link/foo.html
new file mode 100644
index 00000000000..50d7d12c6a6
--- /dev/null
+++ b/src/tools/linkchecker/tests/broken_intra_doc_link/foo.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+[<code>std::ffi::CString</code>]
+</body>
+</html>
diff --git a/src/tools/linkchecker/tests/checks.rs b/src/tools/linkchecker/tests/checks.rs
index 1a0b1b00e0d..b2ec6fd95c6 100644
--- a/src/tools/linkchecker/tests/checks.rs
+++ b/src/tools/linkchecker/tests/checks.rs
@@ -111,3 +111,11 @@ fn redirect_loop() {
          which is also a redirect (not supported)",
     );
 }
+
+#[test]
+fn broken_intra_doc_link() {
+    broken_test(
+        "broken_intra_doc_link",
+        "foo.html:3: broken intra-doc link - [<code>std::ffi::CString</code>]",
+    );
+}
diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs
new file mode 100644
index 00000000000..7097aa0c43a
--- /dev/null
+++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.rs
@@ -0,0 +1,31 @@
+#![feature(core_intrinsics)]
+#![feature(custom_mir)]
+
+use std::intrinsics::mir::*;
+use std::num::NonZeroI32;
+
+// We define our own option type so that we can control the varian indices.
+#[allow(unused)]
+enum Option<T> {
+    None,
+    Some(T),
+}
+use Option::*;
+
+#[custom_mir(dialect = "runtime", phase = "optimized")]
+fn set_discriminant(ptr: &mut Option<NonZeroI32>) {
+    mir! {
+        {
+            // We set the discriminant to `Some`, which is a NOP since this is the niched variant.
+            // However, the enum is actually encoding `None` currently! That's not good...
+            SetDiscriminant(*ptr, 1);
+            //~^ ERROR: trying to set discriminant of a Option<std::num::NonZero<i32>> to the niched variant, but the value does not match
+            Return()
+        }
+    }
+}
+
+pub fn main() {
+    let mut v = None;
+    set_discriminant(&mut v);
+}
diff --git a/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr
new file mode 100644
index 00000000000..a48a0a993da
--- /dev/null
+++ b/src/tools/miri/tests/fail/enum-set-discriminant-niche-variant-wrong.stderr
@@ -0,0 +1,20 @@
+error: Undefined Behavior: trying to set discriminant of a Option<std::num::NonZero<i32>> to the niched variant, but the value does not match
+  --> $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC
+   |
+LL |             SetDiscriminant(*ptr, 1);
+   |             ^^^^^^^^^^^^^^^^^^^^^^^^ trying to set discriminant of a Option<std::num::NonZero<i32>> to the niched variant, but the value does not match
+   |
+   = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior
+   = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information
+   = note: BACKTRACE:
+   = note: inside `set_discriminant` at $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC
+note: inside `main`
+  --> $DIR/enum-set-discriminant-niche-variant-wrong.rs:LL:CC
+   |
+LL |     set_discriminant(&mut v);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^
+
+note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace
+
+error: aborting due to 1 previous error
+
diff --git a/src/tools/rust-analyzer/.github/workflows/ci.yaml b/src/tools/rust-analyzer/.github/workflows/ci.yaml
index 07fa85a61cb..964be478fa3 100644
--- a/src/tools/rust-analyzer/.github/workflows/ci.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/ci.yaml
@@ -28,7 +28,7 @@ jobs:
       proc_macros: ${{ steps.filter.outputs.proc_macros }}
     steps:
       - uses: actions/checkout@v3
-      - uses: dorny/paths-filter@4067d885736b84de7c414f582ac45897079b0a78
+      - uses: dorny/paths-filter@1441771bbfdd59dcd748680ee64ebd8faab1a242
         id: filter
         with:
           filters: |
@@ -104,8 +104,8 @@ jobs:
         run: target/${{ matrix.target }}/debug/rust-analyzer analysis-stats --with-deps $(rustc --print sysroot)/lib/rustlib/src/rust/library/std
 
       - name: clippy
-        if: matrix.os == 'ubuntu-latest'
-        run: cargo clippy --all-targets
+        if: matrix.os == 'windows-latest'
+        run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
 
   # Weird targets to catch non-portable code
   rust-cross:
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index e9492ce0202..dc2bf3a7694 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -72,8 +72,8 @@ dependencies = [
  "cfg",
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "profile",
- "rust-analyzer-salsa",
  "rustc-hash",
+ "salsa",
  "semver",
  "span",
  "stdx",
@@ -167,7 +167,7 @@ checksum = "5676cea088c32290fe65c82895be9d06dd21e0fa49bb97ca840529e9417ab71a"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "synstructure",
 ]
 
@@ -314,17 +314,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "derivative"
-version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 1.0.109",
-]
-
-[[package]]
 name = "derive_arbitrary"
 version = "1.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -332,7 +321,7 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -369,6 +358,15 @@ dependencies = [
 ]
 
 [[package]]
+name = "env_logger"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4cd405aab171cb85d6735e5c8d9db038c17d3ca007a4d2c25f337935c3d90580"
+dependencies = [
+ "log",
+]
+
+[[package]]
 name = "equivalent"
 version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -453,6 +451,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 
 [[package]]
+name = "getrandom"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "wasi",
+]
+
+[[package]]
 name = "gimli"
 version = "0.27.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -930,6 +939,12 @@ dependencies = [
 ]
 
 [[package]]
+name = "linked-hash-map"
+version = "0.5.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
+
+[[package]]
 name = "load-cargo"
 version = "0.0.0"
 dependencies = [
@@ -1273,6 +1288,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
 
 [[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
 name = "proc-macro-api"
 version = "0.0.0"
 dependencies = [
@@ -1283,6 +1304,7 @@ dependencies = [
  "object 0.32.0",
  "paths",
  "profile",
+ "rustc-hash",
  "serde",
  "serde_json",
  "snap",
@@ -1437,47 +1459,47 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.33.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e5313d7f243b63ef9e58d94355b11aa8499f1328055f1f58adf0a5ea7d2faca"
+checksum = "322b751895cc4a0a2ee0c6ab36ec80bc8abf5f8d76254c482f96f03c27c92ebe"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros 0.33.0",
+ "ra-ap-rustc_index_macros 0.35.0",
  "smallvec",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index"
-version = "0.35.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "322b751895cc4a0a2ee0c6ab36ec80bc8abf5f8d76254c482f96f03c27c92ebe"
+checksum = "f8a41dee58608b1fc93779ea365edaa70ac9927e3335ae914b675be0fa063cd7"
 dependencies = [
  "arrayvec",
- "ra-ap-rustc_index_macros 0.35.0",
+ "ra-ap-rustc_index_macros 0.36.0",
  "smallvec",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.33.0"
+version = "0.35.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a83108ebf3e73dde205b9c25706209bcd7736480820f90ded28eabaf8b469f25"
+checksum = "054e25eac52f0506c1309ca4317c11ad4925d7b99eb897f71aa7c3cbafb46c2b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "synstructure",
 ]
 
 [[package]]
 name = "ra-ap-rustc_index_macros"
-version = "0.35.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "054e25eac52f0506c1309ca4317c11ad4925d7b99eb897f71aa7c3cbafb46c2b"
+checksum = "fbfe98def54c4337a2f7d8233850bd5d5349972b185fe8a0db2b979164b30ed8"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "synstructure",
 ]
 
@@ -1503,12 +1525,11 @@ dependencies = [
 
 [[package]]
 name = "ra-ap-rustc_pattern_analysis"
-version = "0.33.0"
+version = "0.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c4085e0c771fd4b883930b599ef42966b855762bbe4052c17673b3253421a6d"
+checksum = "b5529bffec7530b4a3425640bfdfd9b95d87c4c620f740266c0de6572561aab4"
 dependencies = [
- "derivative",
- "ra-ap-rustc_index 0.33.0",
+ "ra-ap-rustc_index 0.36.0",
  "rustc-hash",
  "rustc_apfloat",
  "smallvec",
@@ -1516,6 +1537,36 @@ dependencies = [
 ]
 
 [[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom",
+]
+
+[[package]]
 name = "rayon"
 version = "1.8.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1623,35 +1674,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rust-analyzer-salsa"
-version = "0.17.0-pre.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "719825638c59fd26a55412a24561c7c5bcf54364c88b9a7a04ba08a6eafaba8d"
-dependencies = [
- "indexmap",
- "lock_api",
- "oorandom",
- "parking_lot",
- "rust-analyzer-salsa-macros",
- "rustc-hash",
- "smallvec",
- "tracing",
- "triomphe",
-]
-
-[[package]]
-name = "rust-analyzer-salsa-macros"
-version = "0.17.0-pre.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d96498e9684848c6676c399032ebc37c52da95ecbefa83d71ccc53b9f8a4a8e"
-dependencies = [
- "heck",
- "proc-macro2",
- "quote",
- "syn 2.0.39",
-]
-
-[[package]]
 name = "rustc-demangle"
 version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1680,6 +1702,36 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
 
 [[package]]
+name = "salsa"
+version = "0.0.0"
+dependencies = [
+ "dissimilar",
+ "expect-test",
+ "indexmap",
+ "linked-hash-map",
+ "lock_api",
+ "oorandom",
+ "parking_lot",
+ "rand",
+ "rustc-hash",
+ "salsa-macros",
+ "smallvec",
+ "test-log",
+ "tracing",
+ "triomphe",
+]
+
+[[package]]
+name = "salsa-macros"
+version = "0.0.0"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "same-file"
 version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1735,7 +1787,7 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -1758,7 +1810,7 @@ checksum = "bcec881020c684085e55a25f7fd888954d56609ef363479dc5a1305eb0d40cab"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -1803,7 +1855,7 @@ name = "span"
 version = "0.0.0"
 dependencies = [
  "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "rust-analyzer-salsa",
+ "salsa",
  "stdx",
  "syntax",
  "vfs",
@@ -1837,17 +1889,6 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.109"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
-dependencies = [
- "proc-macro2",
- "quote",
- "unicode-ident",
-]
-
-[[package]]
-name = "syn"
 version = "2.0.39"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "23e78b90f2fcf45d3e842032ce32e3f2d1545ba6636271dcbf24fa306d87be7a"
@@ -1865,7 +1906,7 @@ checksum = "285ba80e733fac80aa4270fbcdf83772a79b80aa35c97075320abfee4a915b06"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
  "unicode-xid",
 ]
 
@@ -1912,6 +1953,27 @@ dependencies = [
 ]
 
 [[package]]
+name = "test-log"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6159ab4116165c99fc88cce31f99fa2c9dbe08d3691cb38da02fc3b45f357d2b"
+dependencies = [
+ "env_logger",
+ "test-log-macros",
+]
+
+[[package]]
+name = "test-log-macros"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ba277e77219e9eea169e8508942db1bf5d8a41ff2db9b20aab5a5aadc9fa25d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
 name = "test-utils"
 version = "0.0.0"
 dependencies = [
@@ -1954,7 +2016,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
@@ -2055,7 +2117,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.39",
+ "syn",
 ]
 
 [[package]]
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 3fb5d9aa7a8..2b81f7b11b2 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -70,6 +70,7 @@ proc-macro-srv = { path = "./crates/proc-macro-srv", version = "0.0.0" }
 proc-macro-srv-cli = { path = "./crates/proc-macro-srv-cli", version = "0.0.0" }
 profile = { path = "./crates/profile", version = "0.0.0" }
 project-model = { path = "./crates/project-model", version = "0.0.0" }
+salsa = { path = "./crates/salsa", version = "0.0.0" }
 span = { path = "./crates/span", version = "0.0.0" }
 stdx = { path = "./crates/stdx", version = "0.0.0" }
 syntax = { path = "./crates/syntax", version = "0.0.0" }
@@ -83,7 +84,7 @@ ra-ap-rustc_lexer = { version = "0.35.0", default-features = false }
 ra-ap-rustc_parse_format = { version = "0.35.0", default-features = false }
 ra-ap-rustc_index = { version = "0.35.0", default-features = false }
 ra-ap-rustc_abi = { version = "0.35.0", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.33.0", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.36.0", default-features = false }
 
 # local crates that aren't published to crates.io. These should not have versions.
 sourcegen = { path = "./crates/sourcegen" }
@@ -106,22 +107,21 @@ dissimilar = "1.0.7"
 either = "1.9.0"
 expect-test = "1.4.0"
 hashbrown = { version = "0.14", features = [
-    "inline-more",
+  "inline-more",
 ], default-features = false }
 indexmap = "2.1.0"
 itertools = "0.12.0"
 libc = "0.2.150"
 nohash-hasher = "0.2.0"
 rayon = "1.8.0"
-rust-analyzer-salsa = "0.17.0-pre.6"
 rustc-hash = "1.1.0"
 semver = "1.0.14"
 serde = { version = "1.0.192", features = ["derive"] }
 serde_json = "1.0.108"
 smallvec = { version = "1.10.0", features = [
-    "const_new",
-    "union",
-    "const_generics",
+  "const_new",
+  "union",
+  "const_generics",
 ] }
 smol_str = "0.2.1"
 text-size = "1.1.1"
@@ -164,23 +164,20 @@ len_without_is_empty = "allow"
 enum_variant_names = "allow"
 # Builder pattern disagrees
 new_ret_no_self = "allow"
+# Has a bunch of false positives
+useless_asref = "allow"
 
 ## Following lints should be tackled at some point
-borrowed_box = "allow"
-derived_hash_with_manual_eq = "allow"
-forget_non_drop = "allow"
-needless_doctest_main = "allow"
-non_canonical_clone_impl = "allow"
-non_canonical_partial_ord_impl = "allow"
-self_named_constructors = "allow"
 too_many_arguments = "allow"
 type_complexity = "allow"
 wrong_self_convention = "allow"
 
 ## warn at following lints
+# CI raises these to deny
 dbg_macro = "warn"
 todo = "warn"
-unimplemented = "allow"
+print_stdout = "warn"
+print_stderr = "warn"
+
 rc_buffer = "warn"
-# FIXME enable this, we use this pattern a lot so its annoying work ...
-# str_to_string = "warn"
+str_to_string = "warn"
diff --git a/src/tools/rust-analyzer/clippy.toml b/src/tools/rust-analyzer/clippy.toml
new file mode 100644
index 00000000000..8032c775ab0
--- /dev/null
+++ b/src/tools/rust-analyzer/clippy.toml
@@ -0,0 +1,5 @@
+disallowed-types = [
+    { path = "std::collections::HashMap", reason = "use FxHashMap" },
+    { path = "std::collections::HashSet", reason = "use FxHashSet" },
+    { path = "std::collections::hash_map::RandomState", reason = "use BuildHasherDefault<FxHasher>"}
+]
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index 485ba78846a..801ba2d1f6c 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
 
 [dependencies]
 la-arena.workspace = true
-rust-analyzer-salsa.workspace = true
+salsa.workspace = true
 rustc-hash.workspace = true
 triomphe.workspace = true
 semver.workspace = true
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index 51e6fdb9510..9560826e373 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -782,7 +782,7 @@ impl FromStr for Edition {
             "2018" => Edition::Edition2018,
             "2021" => Edition::Edition2021,
             "2024" => Edition::Edition2024,
-            _ => return Err(ParseEditionError { invalid_input: s.to_string() }),
+            _ => return Err(ParseEditionError { invalid_input: s.to_owned() }),
         };
         Ok(res)
     }
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index 22603842a1b..c59aff2a8bb 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -100,9 +100,14 @@ impl FlycheckHandle {
         FlycheckHandle { id, sender, _thread: thread }
     }
 
-    /// Schedule a re-start of the cargo check worker.
-    pub fn restart(&self) {
-        self.sender.send(StateChange::Restart).unwrap();
+    /// Schedule a re-start of the cargo check worker to do a workspace wide check.
+    pub fn restart_workspace(&self) {
+        self.sender.send(StateChange::Restart(None)).unwrap();
+    }
+
+    /// Schedule a re-start of the cargo check worker to do a package wide check.
+    pub fn restart_for_package(&self, package: String) {
+        self.sender.send(StateChange::Restart(Some(package))).unwrap();
     }
 
     /// Stop this cargo check worker.
@@ -153,7 +158,7 @@ pub enum Progress {
 }
 
 enum StateChange {
-    Restart,
+    Restart(Option<String>),
     Cancel,
 }
 
@@ -213,7 +218,7 @@ impl FlycheckActor {
                     tracing::debug!(flycheck_id = self.id, "flycheck cancelled");
                     self.cancel_check_process();
                 }
-                Event::RequestStateChange(StateChange::Restart) => {
+                Event::RequestStateChange(StateChange::Restart(package)) => {
                     // Cancel the previously spawned process
                     self.cancel_check_process();
                     while let Ok(restart) = inbox.recv_timeout(Duration::from_millis(50)) {
@@ -223,7 +228,7 @@ impl FlycheckActor {
                         }
                     }
 
-                    let command = self.check_command();
+                    let command = self.check_command(package.as_deref());
                     let formatted_command = format!("{:?}", command);
 
                     tracing::debug!(?command, "will restart flycheck");
@@ -297,7 +302,7 @@ impl FlycheckActor {
         }
     }
 
-    fn check_command(&self) -> Command {
+    fn check_command(&self, package: Option<&str>) -> Command {
         let (mut cmd, args) = match &self.config {
             FlycheckConfig::CargoCommand {
                 command,
@@ -314,7 +319,11 @@ impl FlycheckActor {
                 let mut cmd = Command::new(toolchain::cargo());
                 cmd.arg(command);
                 cmd.current_dir(&self.root);
-                cmd.arg("--workspace");
+
+                match package {
+                    Some(pkg) => cmd.arg("-p").arg(pkg),
+                    None => cmd.arg("--workspace"),
+                };
 
                 cmd.arg(if *ansi_color_output {
                     "--message-format=json-diagnostic-rendered-ansi"
@@ -493,9 +502,7 @@ impl CargoActor {
                     // Skip certain kinds of messages to only spend time on what's useful
                     JsonMessage::Cargo(message) => match message {
                         cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => {
-                            self.sender
-                                .send(CargoMessage::CompilerArtifact(Box::new(artifact)))
-                                .unwrap();
+                            self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap();
                         }
                         cargo_metadata::Message::CompilerMessage(msg) => {
                             self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap();
@@ -539,8 +546,9 @@ impl CargoActor {
     }
 }
 
+#[allow(clippy::large_enum_variant)]
 enum CargoMessage {
-    CompilerArtifact(Box<cargo_metadata::Artifact>),
+    CompilerArtifact(cargo_metadata::Artifact),
     Diagnostic(Diagnostic),
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
index bee6f0083b1..c91a5497262 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs
@@ -24,11 +24,11 @@ use triomphe::Arc;
 
 use crate::{
     db::DefDatabase,
-    item_tree::{AttrOwner, Fields, ItemTreeId, ItemTreeModItemNode},
+    item_tree::{AttrOwner, Fields, ItemTreeNode},
     lang_item::LangItem,
     nameres::{ModuleOrigin, ModuleSource},
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemLoc, AttrDefId, GenericParamId, ItemLoc, LocalFieldId, Lookup, MacroId,
+    AdtId, AttrDefId, GenericParamId, HasModule, ItemTreeLoc, LocalFieldId, Lookup, MacroId,
     VariantId,
 };
 
@@ -317,7 +317,7 @@ fn parse_comma_sep<S>(subtree: &tt::Subtree<S>) -> Vec<SmolStr> {
 }
 
 impl AttrsWithOwner {
-    pub fn attrs_with_owner(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
+    pub fn new(db: &dyn DefDatabase, owner: AttrDefId) -> Self {
         Self { attrs: db.attrs(owner), owner }
     }
 
@@ -356,12 +356,7 @@ impl AttrsWithOwner {
             AttrDefId::FieldId(it) => {
                 return db.fields_attrs(it.parent)[it.local_id].clone();
             }
-            // FIXME: DRY this up
-            AttrDefId::EnumVariantId(it) => {
-                let id = it.lookup(db).id;
-                let tree = id.item_tree(db);
-                tree.raw_attrs(id.value.into()).clone()
-            }
+            AttrDefId::EnumVariantId(it) => attrs_from_item_tree_loc(db, it),
             AttrDefId::AdtId(it) => match it {
                 AdtId::StructId(it) => attrs_from_item_tree_loc(db, it),
                 AdtId::EnumId(it) => attrs_from_item_tree_loc(db, it),
@@ -370,15 +365,15 @@ impl AttrsWithOwner {
             AttrDefId::TraitId(it) => attrs_from_item_tree_loc(db, it),
             AttrDefId::TraitAliasId(it) => attrs_from_item_tree_loc(db, it),
             AttrDefId::MacroId(it) => match it {
-                MacroId::Macro2Id(it) => attrs_from_item_tree(db, it.lookup(db).id),
-                MacroId::MacroRulesId(it) => attrs_from_item_tree(db, it.lookup(db).id),
-                MacroId::ProcMacroId(it) => attrs_from_item_tree(db, it.lookup(db).id),
+                MacroId::Macro2Id(it) => attrs_from_item_tree_loc(db, it),
+                MacroId::MacroRulesId(it) => attrs_from_item_tree_loc(db, it),
+                MacroId::ProcMacroId(it) => attrs_from_item_tree_loc(db, it),
             },
             AttrDefId::ImplId(it) => attrs_from_item_tree_loc(db, it),
-            AttrDefId::ConstId(it) => attrs_from_item_tree_assoc(db, it),
-            AttrDefId::StaticId(it) => attrs_from_item_tree_assoc(db, it),
-            AttrDefId::FunctionId(it) => attrs_from_item_tree_assoc(db, it),
-            AttrDefId::TypeAliasId(it) => attrs_from_item_tree_assoc(db, it),
+            AttrDefId::ConstId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::StaticId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::FunctionId(it) => attrs_from_item_tree_loc(db, it),
+            AttrDefId::TypeAliasId(it) => attrs_from_item_tree_loc(db, it),
             AttrDefId::GenericParamId(it) => match it {
                 GenericParamId::ConstParamId(it) => {
                     let src = it.parent().child_source(db);
@@ -603,29 +598,14 @@ fn any_has_attrs<'db>(
     id.lookup(db).source(db).map(ast::AnyHasAttrs::new)
 }
 
-fn attrs_from_item_tree<N: ItemTreeModItemNode>(
-    db: &dyn DefDatabase,
-    id: ItemTreeId<N>,
-) -> RawAttrs {
-    let tree = id.item_tree(db);
-    let mod_item = N::id_to_mod_item(id.value);
-    tree.raw_attrs(mod_item.into()).clone()
-}
-
-fn attrs_from_item_tree_loc<'db, N: ItemTreeModItemNode>(
+fn attrs_from_item_tree_loc<'db, N: ItemTreeNode>(
     db: &(dyn DefDatabase + 'db),
-    lookup: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = ItemLoc<N>>,
+    lookup: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = impl ItemTreeLoc<Id = N>>,
 ) -> RawAttrs {
-    let id = lookup.lookup(db).id;
-    attrs_from_item_tree(db, id)
-}
-
-fn attrs_from_item_tree_assoc<'db, N: ItemTreeModItemNode>(
-    db: &(dyn DefDatabase + 'db),
-    lookup: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<N>>,
-) -> RawAttrs {
-    let id = lookup.lookup(db).id;
-    attrs_from_item_tree(db, id)
+    let id = lookup.lookup(db).item_tree_id();
+    let tree = id.item_tree(db);
+    let attr_owner = N::attr_owner(id.value);
+    tree.raw_attrs(attr_owner).clone()
 }
 
 pub(crate) fn fields_attrs_source_map(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index 48a596f7f53..55b9a1dfdcb 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -283,9 +283,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
         experimental!(optimize),
     ),
 
-    gated!(
-        ffi_returns_twice, Normal, template!(Word), WarnFollowing, experimental!(ffi_returns_twice)
-    ),
     gated!(ffi_pure, Normal, template!(Word), WarnFollowing, experimental!(ffi_pure)),
     gated!(ffi_const, Normal, template!(Word), WarnFollowing, experimental!(ffi_const)),
     gated!(
@@ -653,7 +650,7 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
     rustc_attr!(TEST, rustc_regions, Normal, template!(Word), WarnFollowing),
     rustc_attr!(
         TEST, rustc_error, Normal,
-        template!(Word, List: "span_delayed_bug_from_inside_query"), WarnFollowingWordOnly
+        template!(Word, List: "delayed_bug_from_inside_query"), WarnFollowingWordOnly
     ),
     rustc_attr!(TEST, rustc_dump_user_args, Normal, template!(Word), WarnFollowing),
     rustc_attr!(TEST, rustc_evaluate_where_clauses, Normal, template!(Word), WarnFollowing),
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
index 492ea6d5c59..29ac666277d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
@@ -1980,10 +1980,7 @@ fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)>
     let ast_lit = lit.literal()?;
     let mut hir_lit: Literal = ast_lit.kind().into();
     if lit.minus_token().is_some() {
-        let Some(h) = hir_lit.negate() else {
-            return None;
-        };
-        hir_lit = h;
+        hir_lit = hir_lit.negate()?;
     }
     Some((hir_lit, ast_lit))
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
index b821b91b895..4afb4086517 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
@@ -29,11 +29,11 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo
                 "const {} = ",
                 match &it.name {
                     Some(name) => name.display(db.upcast()).to_string(),
-                    None => "_".to_string(),
+                    None => "_".to_owned(),
                 }
             )
         }),
-        DefWithBodyId::InTypeConstId(_) => "In type const = ".to_string(),
+        DefWithBodyId::InTypeConstId(_) => "In type const = ".to_owned(),
         DefWithBodyId::VariantId(it) => {
             let loc = it.lookup(db);
             let enum_loc = loc.parent.lookup(db);
@@ -123,7 +123,7 @@ impl Printer<'_> {
         wln!(self);
         f(self);
         self.indent_level -= 1;
-        self.buf = self.buf.trim_end_matches('\n').to_string();
+        self.buf = self.buf.trim_end_matches('\n').to_owned();
     }
 
     fn whitespace(&mut self) {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
index b3bb3355f12..ba7d06272af 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs
@@ -6,15 +6,21 @@
 
 use either::Either;
 use hir_expand::{attrs::collect_attrs, HirFileId};
+use syntax::ast;
 
 use crate::{
     db::DefDatabase,
-    dyn_map::{keys, DynMap},
+    dyn_map::{
+        keys::{self, Key},
+        DynMap,
+    },
     item_scope::ItemScope,
+    item_tree::ItemTreeNode,
     nameres::DefMap,
     src::{HasChildSource, HasSource},
-    AdtId, AssocItemId, DefWithBodyId, EnumId, ExternCrateId, FieldId, ImplId, Lookup, MacroId,
-    ModuleDefId, ModuleId, TraitId, UseId, VariantId,
+    AdtId, AssocItemId, DefWithBodyId, EnumId, FieldId, GenericDefId, ImplId, ItemTreeLoc,
+    LifetimeParamId, Lookup, MacroId, ModuleDefId, ModuleId, TraitId, TypeOrConstParamId,
+    VariantId,
 };
 
 pub trait ChildBySource {
@@ -55,29 +61,6 @@ impl ChildBySource for ImplId {
     }
 }
 
-fn add_assoc_item(db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId, item: AssocItemId) {
-    match item {
-        AssocItemId::FunctionId(func) => {
-            let loc = func.lookup(db);
-            if loc.id.file_id() == file_id {
-                res[keys::FUNCTION].insert(loc.source(db).value, func)
-            }
-        }
-        AssocItemId::ConstId(konst) => {
-            let loc = konst.lookup(db);
-            if loc.id.file_id() == file_id {
-                res[keys::CONST].insert(loc.source(db).value, konst)
-            }
-        }
-        AssocItemId::TypeAliasId(ty) => {
-            let loc = ty.lookup(db);
-            if loc.id.file_id() == file_id {
-                res[keys::TYPE_ALIAS].insert(loc.source(db).value, ty)
-            }
-        }
-    }
-}
-
 impl ChildBySource for ModuleId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let def_map = self.def_map(db);
@@ -89,15 +72,12 @@ impl ChildBySource for ModuleId {
 impl ChildBySource for ItemScope {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         self.declarations().for_each(|item| add_module_def(db, res, file_id, item));
-        self.impls().for_each(|imp| add_impl(db, res, file_id, imp));
-        self.extern_crate_decls().for_each(|ext| add_extern_crate(db, res, file_id, ext));
-        self.use_decls().for_each(|ext| add_use(db, res, file_id, ext));
-        self.unnamed_consts(db).for_each(|konst| {
-            let loc = konst.lookup(db);
-            if loc.id.file_id() == file_id {
-                res[keys::CONST].insert(loc.source(db).value, konst);
-            }
-        });
+        self.impls().for_each(|imp| insert_item_loc(db, res, file_id, imp, keys::IMPL));
+        self.extern_crate_decls()
+            .for_each(|ext| insert_item_loc(db, res, file_id, ext, keys::EXTERN_CRATE));
+        self.use_decls().for_each(|ext| insert_item_loc(db, res, file_id, ext, keys::USE));
+        self.unnamed_consts(db)
+            .for_each(|konst| insert_item_loc(db, res, file_id, konst, keys::CONST));
         self.attr_macro_invocs().filter(|(id, _)| id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
                 res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id);
@@ -132,59 +112,38 @@ impl ChildBySource for ItemScope {
             file_id: HirFileId,
             item: ModuleDefId,
         ) {
-            macro_rules! insert {
-                ($map:ident[$key:path].$insert:ident($id:ident)) => {{
-                    let loc = $id.lookup(db);
-                    if loc.id.file_id() == file_id {
-                        $map[$key].$insert(loc.source(db).value, $id)
-                    }
-                }};
-            }
             match item {
-                ModuleDefId::FunctionId(id) => insert!(map[keys::FUNCTION].insert(id)),
-                ModuleDefId::ConstId(id) => insert!(map[keys::CONST].insert(id)),
-                ModuleDefId::StaticId(id) => insert!(map[keys::STATIC].insert(id)),
-                ModuleDefId::TypeAliasId(id) => insert!(map[keys::TYPE_ALIAS].insert(id)),
-                ModuleDefId::TraitId(id) => insert!(map[keys::TRAIT].insert(id)),
-                ModuleDefId::TraitAliasId(id) => insert!(map[keys::TRAIT_ALIAS].insert(id)),
+                ModuleDefId::FunctionId(id) => {
+                    insert_item_loc(db, map, file_id, id, keys::FUNCTION)
+                }
+                ModuleDefId::ConstId(id) => insert_item_loc(db, map, file_id, id, keys::CONST),
+                ModuleDefId::TypeAliasId(id) => {
+                    insert_item_loc(db, map, file_id, id, keys::TYPE_ALIAS)
+                }
+                ModuleDefId::StaticId(id) => insert_item_loc(db, map, file_id, id, keys::STATIC),
+                ModuleDefId::TraitId(id) => insert_item_loc(db, map, file_id, id, keys::TRAIT),
+                ModuleDefId::TraitAliasId(id) => {
+                    insert_item_loc(db, map, file_id, id, keys::TRAIT_ALIAS)
+                }
                 ModuleDefId::AdtId(adt) => match adt {
-                    AdtId::StructId(id) => insert!(map[keys::STRUCT].insert(id)),
-                    AdtId::UnionId(id) => insert!(map[keys::UNION].insert(id)),
-                    AdtId::EnumId(id) => insert!(map[keys::ENUM].insert(id)),
+                    AdtId::StructId(id) => insert_item_loc(db, map, file_id, id, keys::STRUCT),
+                    AdtId::UnionId(id) => insert_item_loc(db, map, file_id, id, keys::UNION),
+                    AdtId::EnumId(id) => insert_item_loc(db, map, file_id, id, keys::ENUM),
                 },
                 ModuleDefId::MacroId(id) => match id {
-                    MacroId::Macro2Id(id) => insert!(map[keys::MACRO2].insert(id)),
-                    MacroId::MacroRulesId(id) => insert!(map[keys::MACRO_RULES].insert(id)),
-                    MacroId::ProcMacroId(id) => insert!(map[keys::PROC_MACRO].insert(id)),
+                    MacroId::Macro2Id(id) => insert_item_loc(db, map, file_id, id, keys::MACRO2),
+                    MacroId::MacroRulesId(id) => {
+                        insert_item_loc(db, map, file_id, id, keys::MACRO_RULES)
+                    }
+                    MacroId::ProcMacroId(id) => {
+                        insert_item_loc(db, map, file_id, id, keys::PROC_MACRO)
+                    }
                 },
                 ModuleDefId::ModuleId(_)
                 | ModuleDefId::EnumVariantId(_)
                 | ModuleDefId::BuiltinType(_) => (),
             }
         }
-        fn add_impl(db: &dyn DefDatabase, map: &mut DynMap, file_id: HirFileId, imp: ImplId) {
-            let loc = imp.lookup(db);
-            if loc.id.file_id() == file_id {
-                map[keys::IMPL].insert(loc.source(db).value, imp)
-            }
-        }
-        fn add_extern_crate(
-            db: &dyn DefDatabase,
-            map: &mut DynMap,
-            file_id: HirFileId,
-            ext: ExternCrateId,
-        ) {
-            let loc = ext.lookup(db);
-            if loc.id.file_id() == file_id {
-                map[keys::EXTERN_CRATE].insert(loc.source(db).value, ext)
-            }
-        }
-        fn add_use(db: &dyn DefDatabase, map: &mut DynMap, file_id: HirFileId, ext: UseId) {
-            let loc = ext.lookup(db);
-            if loc.id.file_id() == file_id {
-                map[keys::USE].insert(loc.source(db).value, ext)
-            }
-        }
     }
 }
 
@@ -237,3 +196,63 @@ impl ChildBySource for DefWithBodyId {
         }
     }
 }
+
+impl ChildBySource for GenericDefId {
+    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
+        let (gfile_id, generic_params_list) = self.file_id_and_params_of(db);
+        if gfile_id != file_id {
+            return;
+        }
+
+        let generic_params = db.generic_params(*self);
+        let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
+        let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
+
+        // For traits the first type index is `Self`, skip it.
+        if let GenericDefId::TraitId(_) = *self {
+            toc_idx_iter.next().unwrap(); // advance_by(1);
+        }
+
+        if let Some(generic_params_list) = generic_params_list {
+            for (local_id, ast_param) in
+                toc_idx_iter.zip(generic_params_list.type_or_const_params())
+            {
+                let id = TypeOrConstParamId { parent: *self, local_id };
+                match ast_param {
+                    ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id),
+                    ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id),
+                }
+            }
+            for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
+                let id = LifetimeParamId { parent: *self, local_id };
+                res[keys::LIFETIME_PARAM].insert(ast_param, id);
+            }
+        }
+    }
+}
+
+fn insert_item_loc<ID, N, Data>(
+    db: &dyn DefDatabase,
+    res: &mut DynMap,
+    file_id: HirFileId,
+    id: ID,
+    key: Key<N::Source, ID>,
+) where
+    ID: for<'db> Lookup<Database<'db> = dyn DefDatabase + 'db, Data = Data> + 'static,
+    Data: ItemTreeLoc<Id = N>,
+    N: ItemTreeNode,
+    N::Source: 'static,
+{
+    let loc = id.lookup(db);
+    if loc.item_tree_id().file_id() == file_id {
+        res[key].insert(loc.source(db).value, id)
+    }
+}
+
+fn add_assoc_item(db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId, item: AssocItemId) {
+    match item {
+        AssocItemId::FunctionId(func) => insert_item_loc(db, res, file_id, func, keys::FUNCTION),
+        AssocItemId::ConstId(konst) => insert_item_loc(db, res, file_id, konst, keys::CONST),
+        AssocItemId::TypeAliasId(ty) => insert_item_loc(db, res, file_id, ty, keys::TYPE_ALIAS),
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
index 5986b7df3d9..540f643ae7d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data/adt.rs
@@ -10,7 +10,7 @@ use hir_expand::{
     HirFileId, InFile,
 };
 use intern::Interned;
-use la_arena::{Arena, ArenaMap};
+use la_arena::Arena;
 use rustc_abi::{Align, Integer, IntegerType, ReprFlags, ReprOptions};
 use syntax::ast::{self, HasName, HasVisibility};
 use triomphe::Arc;
@@ -22,13 +22,11 @@ use crate::{
     lang_item::LangItem,
     lower::LowerCtx,
     nameres::diagnostics::{DefDiagnostic, DefDiagnostics},
-    src::HasChildSource,
-    src::HasSource,
     trace::Trace,
     tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree},
     type_ref::TypeRef,
     visibility::RawVisibility,
-    EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId, VariantId,
+    EnumId, EnumVariantId, LocalFieldId, LocalModuleId, Lookup, StructId, UnionId,
 };
 
 /// Note that we use `StructData` for unions as well!
@@ -387,46 +385,6 @@ impl VariantData {
     }
 }
 
-impl HasChildSource<LocalFieldId> for VariantId {
-    type Value = Either<ast::TupleField, ast::RecordField>;
-
-    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
-        let item_tree;
-        let (src, fields, container) = match *self {
-            VariantId::EnumVariantId(it) => {
-                let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    &item_tree[lookup.id.value].fields,
-                    lookup.parent.lookup(db).container,
-                )
-            }
-            VariantId::StructId(it) => {
-                let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    &item_tree[lookup.id.value].fields,
-                    lookup.container,
-                )
-            }
-            VariantId::UnionId(it) => {
-                let lookup = it.lookup(db);
-                item_tree = lookup.id.item_tree(db);
-                (
-                    lookup.source(db).map(|it| it.kind()),
-                    &item_tree[lookup.id.value].fields,
-                    lookup.container,
-                )
-            }
-        };
-        let mut trace = Trace::new_for_map();
-        lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields);
-        src.with_value(trace.into_map())
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
 pub enum StructKind {
     Tuple,
@@ -434,7 +392,7 @@ pub enum StructKind {
     Unit,
 }
 
-fn lower_struct(
+pub(crate) fn lower_struct(
     db: &dyn DefDatabase,
     trace: &mut Trace<FieldData, Either<ast::TupleField, ast::RecordField>>,
     ast: &InFile<ast::StructKind>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
index 1a44c319de5..2e137f67b4c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs
@@ -171,6 +171,7 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti
     .map(|(item, _)| item)
 }
 
+#[tracing::instrument(skip_all)]
 fn find_path_for_module(
     ctx: FindPathCtx<'_>,
     def_map: &DefMap,
@@ -312,6 +313,7 @@ fn find_self_super(def_map: &DefMap, item: ModuleId, from: ModuleId) -> Option<M
     }
 }
 
+#[tracing::instrument(skip_all)]
 fn calculate_best_path(
     ctx: FindPathCtx<'_>,
     def_map: &DefMap,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
index 349d327aaae..1d2c7c3a55f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -3,31 +3,27 @@
 //! generic parameters. See also the `Generics` type and the `generics_of` query
 //! in rustc.
 
-use base_db::FileId;
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
-    ExpandResult, HirFileId, InFile,
+    ExpandResult,
 };
 use intern::Interned;
-use la_arena::{Arena, ArenaMap, Idx};
+use la_arena::{Arena, Idx};
 use once_cell::unsync::Lazy;
 use stdx::impl_from;
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
 use triomphe::Arc;
 
 use crate::{
-    child_by_source::ChildBySource,
     db::DefDatabase,
-    dyn_map::{keys, DynMap},
     expander::Expander,
-    item_tree::ItemTree,
+    item_tree::{GenericsItemTreeNode, ItemTree},
     lower::LowerCtx,
     nameres::{DefMap, MacroSubNs},
-    src::{HasChildSource, HasSource},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
-    AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
-    LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
+    AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LocalTypeOrConstParamId, Lookup,
+    TypeOrConstParamId, TypeParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -264,7 +260,7 @@ impl GenericParamsCollector {
                 self.add_where_predicate_from_bound(
                     lower_ctx,
                     bound,
-                    lifetimes.as_ref(),
+                    lifetimes.as_deref(),
                     target.clone(),
                 );
             }
@@ -275,14 +271,14 @@ impl GenericParamsCollector {
         &mut self,
         lower_ctx: &LowerCtx<'_>,
         bound: ast::TypeBound,
-        hrtb_lifetimes: Option<&Box<[Name]>>,
+        hrtb_lifetimes: Option<&[Name]>,
         target: Either<TypeRef, LifetimeRef>,
     ) {
         let bound = TypeBound::from_ast(lower_ctx, bound);
         let predicate = match (target, bound) {
             (Either::Left(type_ref), bound) => match hrtb_lifetimes {
                 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
-                    lifetimes: hrtb_lifetimes.clone(),
+                    lifetimes: hrtb_lifetimes.to_vec().into_boxed_slice(),
                     target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
                     bound: Interned::new(bound),
                 },
@@ -418,13 +414,18 @@ impl GenericParams {
                 })
             }
         };
-        macro_rules! id_to_generics {
-            ($id:ident) => {{
-                let id = $id.lookup(db).id;
-                let tree = id.item_tree(db);
-                let item = &tree[id.value];
-                enabled_params(&item.generic_params, &tree)
-            }};
+        fn id_to_generics<Id: GenericsItemTreeNode>(
+            db: &dyn DefDatabase,
+            id: impl for<'db> Lookup<
+                Database<'db> = dyn DefDatabase + 'db,
+                Data = impl ItemTreeLoc<Id = Id>,
+            >,
+            enabled_params: impl Fn(&Interned<GenericParams>, &ItemTree) -> Interned<GenericParams>,
+        ) -> Interned<GenericParams> {
+            let id = id.lookup(db).item_tree_id();
+            let tree = id.item_tree(db);
+            let item = &tree[id.value];
+            enabled_params(item.generic_params(), &tree)
         }
 
         match def {
@@ -457,13 +458,13 @@ impl GenericParams {
                     Interned::new(generic_params.finish())
                 }
             }
-            GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics!(id),
-            GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics!(id),
-            GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics!(id),
-            GenericDefId::TraitId(id) => id_to_generics!(id),
-            GenericDefId::TraitAliasId(id) => id_to_generics!(id),
-            GenericDefId::TypeAliasId(id) => id_to_generics!(id),
-            GenericDefId::ImplId(id) => id_to_generics!(id),
+            GenericDefId::AdtId(AdtId::StructId(id)) => id_to_generics(db, id, enabled_params),
+            GenericDefId::AdtId(AdtId::EnumId(id)) => id_to_generics(db, id, enabled_params),
+            GenericDefId::AdtId(AdtId::UnionId(id)) => id_to_generics(db, id, enabled_params),
+            GenericDefId::TraitId(id) => id_to_generics(db, id, enabled_params),
+            GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
+            GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
+            GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
             GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
                 Interned::new(GenericParams {
                     type_or_consts: Default::default(),
@@ -507,141 +508,3 @@ impl GenericParams {
         })
     }
 }
-
-fn file_id_and_params_of(
-    def: GenericDefId,
-    db: &dyn DefDatabase,
-) -> (HirFileId, Option<ast::GenericParamList>) {
-    match def {
-        GenericDefId::FunctionId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::StructId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::UnionId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::AdtId(AdtId::EnumId(it)) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::TraitId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::TraitAliasId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::TypeAliasId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        GenericDefId::ImplId(it) => {
-            let src = it.lookup(db).source(db);
-            (src.file_id, src.value.generic_param_list())
-        }
-        // We won't be using this ID anyway
-        GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None),
-    }
-}
-
-impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
-    type Value = Either<ast::TypeOrConstParam, ast::TraitOrAlias>;
-    fn child_source(
-        &self,
-        db: &dyn DefDatabase,
-    ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        // For traits and trait aliases the first type index is `Self`, we need to add it before
-        // the other params.
-        match *self {
-            GenericDefId::TraitId(id) => {
-                let trait_ref = id.lookup(db).source(db).value;
-                let idx = idx_iter.next().unwrap();
-                params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref)));
-            }
-            GenericDefId::TraitAliasId(id) => {
-                let alias = id.lookup(db).source(db).value;
-                let idx = idx_iter.next().unwrap();
-                params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias)));
-            }
-            _ => {}
-        }
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) {
-                params.insert(idx, Either::Left(ast_param));
-            }
-        }
-
-        InFile::new(file_id, params)
-    }
-}
-
-impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
-    type Value = ast::LifetimeParam;
-    fn child_source(
-        &self,
-        db: &dyn DefDatabase,
-    ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.lifetime_params()) {
-                params.insert(idx, ast_param);
-            }
-        }
-
-        InFile::new(file_id, params)
-    }
-}
-
-impl ChildBySource for GenericDefId {
-    fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
-        let (gfile_id, generic_params_list) = file_id_and_params_of(*self, db);
-        if gfile_id != file_id {
-            return;
-        }
-
-        let generic_params = db.generic_params(*self);
-        let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
-        let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
-
-        // For traits the first type index is `Self`, skip it.
-        if let GenericDefId::TraitId(_) = *self {
-            toc_idx_iter.next().unwrap(); // advance_by(1);
-        }
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (local_id, ast_param) in
-                toc_idx_iter.zip(generic_params_list.type_or_const_params())
-            {
-                let id = TypeOrConstParamId { parent: *self, local_id };
-                match ast_param {
-                    ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id),
-                    ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id),
-                }
-            }
-            for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
-                let id = LifetimeParamId { parent: *self, local_id };
-                res[keys::LIFETIME_PARAM].insert(ast_param, id);
-            }
-        }
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
index c698510ca99..98982c7db84 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs
@@ -859,7 +859,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).fuzzy(),
+            Query::new("fmt".to_owned()).fuzzy(),
             expect![[r#"
                 dep::fmt (t)
                 dep::fmt::Display::FMT_CONST (a)
@@ -888,9 +888,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string())
-                .fuzzy()
-                .assoc_search_mode(AssocSearchMode::AssocItemsOnly),
+            Query::new("fmt".to_owned()).fuzzy().assoc_search_mode(AssocSearchMode::AssocItemsOnly),
             expect![[r#"
                 dep::fmt::Display::FMT_CONST (a)
                 dep::fmt::Display::format_function (a)
@@ -901,7 +899,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).fuzzy().assoc_search_mode(AssocSearchMode::Exclude),
+            Query::new("fmt".to_owned()).fuzzy().assoc_search_mode(AssocSearchMode::Exclude),
             expect![[r#"
                 dep::fmt (t)
             "#]],
@@ -937,7 +935,7 @@ pub mod fmt {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).fuzzy(),
+            Query::new("fmt".to_owned()).fuzzy(),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
@@ -951,7 +949,7 @@ pub mod fmt {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()),
+            Query::new("fmt".to_owned()),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
@@ -991,7 +989,7 @@ pub mod fmt {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()),
+            Query::new("fmt".to_owned()),
             expect![[r#"
                 dep::Fmt (m)
                 dep::Fmt (t)
@@ -1015,7 +1013,7 @@ pub mod fmt {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()),
+            Query::new("FMT".to_owned()),
             expect![[r#"
                 dep::FMT (t)
                 dep::FMT (v)
@@ -1027,7 +1025,7 @@ pub mod fmt {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()).case_sensitive(),
+            Query::new("FMT".to_owned()).case_sensitive(),
             expect![[r#"
                 dep::FMT (t)
                 dep::FMT (v)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
index 0b0c838bedb..0e6826a75a6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs
@@ -222,17 +222,15 @@ impl ItemScope {
         self.declarations.iter().copied()
     }
 
-    pub fn extern_crate_decls(
-        &self,
-    ) -> impl Iterator<Item = ExternCrateId> + ExactSizeIterator + '_ {
+    pub fn extern_crate_decls(&self) -> impl ExactSizeIterator<Item = ExternCrateId> + '_ {
         self.extern_crate_decls.iter().copied()
     }
 
-    pub fn use_decls(&self) -> impl Iterator<Item = UseId> + ExactSizeIterator + '_ {
+    pub fn use_decls(&self) -> impl ExactSizeIterator<Item = UseId> + '_ {
         self.use_decls.iter().copied()
     }
 
-    pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
+    pub fn impls(&self) -> impl ExactSizeIterator<Item = ImplId> + '_ {
         self.impls.iter().copied()
     }
 
@@ -674,7 +672,7 @@ impl ItemScope {
             format_to!(
                 buf,
                 "{}:",
-                name.map_or("_".to_string(), |name| name.display(db).to_string())
+                name.map_or("_".to_owned(), |name| name.display(db).to_string())
             );
 
             if let Some((.., i)) = def.types {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 336e0de7fd6..be16a5e31a2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -337,20 +337,18 @@ from_attrs!(
     LifetimeParamData(Idx<LifetimeParamData>),
 );
 
-/// Trait implemented by all item nodes in the item tree.
-pub trait ItemTreeModItemNode: Clone {
-    type Source: AstIdNode + Into<ast::Item>;
+/// Trait implemented by all nodes in the item tree.
+pub trait ItemTreeNode: Clone {
+    type Source: AstIdNode;
 
     fn ast_id(&self) -> FileAstId<Self::Source>;
 
     /// Looks up an instance of `Self` in an item tree.
     fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self;
-
-    /// Downcasts a `ModItem` to a `FileItemTreeId` specific to this type.
-    fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>>;
-
-    /// Upcasts a `FileItemTreeId` to a generic `ModItem`.
-    fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem;
+    fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner;
+}
+pub trait GenericsItemTreeNode: ItemTreeNode {
+    fn generic_params(&self) -> &Interned<GenericParams>;
 }
 
 pub struct FileItemTreeId<N>(Idx<N>);
@@ -372,7 +370,7 @@ impl<N> FileItemTreeId<N> {
 
 impl<N> Clone for FileItemTreeId<N> {
     fn clone(&self) -> Self {
-        Self(self.0)
+        *self
     }
 }
 impl<N> Copy for FileItemTreeId<N> {}
@@ -478,7 +476,7 @@ impl<N> Hash for ItemTreeId<N> {
 }
 
 macro_rules! mod_items {
-    ( $( $typ:ident in $fld:ident -> $ast:ty ),+ $(,)? ) => {
+    ( $( $typ:ident $(<$generic_params:ident>)? in $fld:ident -> $ast:ty ),+ $(,)? ) => {
         #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
         pub enum ModItem {
             $(
@@ -495,7 +493,7 @@ macro_rules! mod_items {
         )+
 
         $(
-            impl ItemTreeModItemNode for $typ {
+            impl ItemTreeNode for $typ {
                 type Source = $ast;
 
                 fn ast_id(&self) -> FileAstId<Self::Source> {
@@ -506,15 +504,8 @@ macro_rules! mod_items {
                     &tree.data().$fld[index]
                 }
 
-                fn id_from_mod_item(mod_item: ModItem) -> Option<FileItemTreeId<Self>> {
-                    match mod_item {
-                        ModItem::$typ(id) => Some(id),
-                        _ => None,
-                    }
-                }
-
-                fn id_to_mod_item(id: FileItemTreeId<Self>) -> ModItem {
-                    ModItem::$typ(id)
+                fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
+                    AttrOwner::ModItem(ModItem::$typ(id))
                 }
             }
 
@@ -525,6 +516,14 @@ macro_rules! mod_items {
                     &self.data().$fld[index]
                 }
             }
+
+            $(
+                impl GenericsItemTreeNode for $typ {
+                    fn generic_params(&self) -> &Interned<GenericParams> {
+                        &self.$generic_params
+                    }
+                }
+            )?
         )+
     };
 }
@@ -533,16 +532,16 @@ mod_items! {
     Use in uses -> ast::Use,
     ExternCrate in extern_crates -> ast::ExternCrate,
     ExternBlock in extern_blocks -> ast::ExternBlock,
-    Function in functions -> ast::Fn,
-    Struct in structs -> ast::Struct,
-    Union in unions -> ast::Union,
-    Enum in enums -> ast::Enum,
+    Function<explicit_generic_params> in functions -> ast::Fn,
+    Struct<generic_params> in structs -> ast::Struct,
+    Union<generic_params> in unions -> ast::Union,
+    Enum<generic_params> in enums -> ast::Enum,
     Const in consts -> ast::Const,
     Static in statics -> ast::Static,
-    Trait in traits -> ast::Trait,
-    TraitAlias in trait_aliases -> ast::TraitAlias,
-    Impl in impls -> ast::Impl,
-    TypeAlias in type_aliases -> ast::TypeAlias,
+    Trait<generic_params> in traits -> ast::Trait,
+    TraitAlias<generic_params> in trait_aliases -> ast::TraitAlias,
+    Impl<generic_params> in impls -> ast::Impl,
+    TypeAlias<generic_params> in type_aliases -> ast::TypeAlias,
     Mod in mods -> ast::Module,
     MacroCall in macro_calls -> ast::MacroCall,
     MacroRules in macro_rules -> ast::MacroRules,
@@ -578,17 +577,26 @@ impl Index<RawVisibilityId> for ItemTree {
     }
 }
 
-impl<N: ItemTreeModItemNode> Index<FileItemTreeId<N>> for ItemTree {
+impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
     type Output = N;
     fn index(&self, id: FileItemTreeId<N>) -> &N {
         N::lookup(self, id.index())
     }
 }
 
-impl Index<FileItemTreeId<Variant>> for ItemTree {
-    type Output = Variant;
-    fn index(&self, id: FileItemTreeId<Variant>) -> &Variant {
-        &self[id.index()]
+impl ItemTreeNode for Variant {
+    type Source = ast::Variant;
+
+    fn ast_id(&self) -> FileAstId<Self::Source> {
+        self.ast_id
+    }
+
+    fn lookup(tree: &ItemTree, index: Idx<Self>) -> &Self {
+        &tree.data().variants[index]
+    }
+
+    fn attr_owner(id: FileItemTreeId<Self>) -> AttrOwner {
+        AttrOwner::Variant(id)
     }
 }
 
@@ -1027,7 +1035,7 @@ impl AssocItem {
     }
 }
 
-#[derive(Debug, Eq, PartialEq)]
+#[derive(Debug, Clone, PartialEq, Eq)]
 pub struct Variant {
     pub name: Name,
     pub fields: Fields,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index b500f56b6c1..e0aa3ae6123 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -13,7 +13,7 @@ use crate::{
 
 use super::*;
 
-fn id<N: ItemTreeModItemNode>(index: Idx<N>) -> FileItemTreeId<N> {
+fn id<N: ItemTreeNode>(index: Idx<N>) -> FileItemTreeId<N> {
     FileItemTreeId(index)
 }
 
@@ -267,7 +267,7 @@ impl<'a> Ctx<'a> {
             if let Some(data) = self.lower_variant(&variant) {
                 let idx = self.data().variants.alloc(data);
                 self.add_attrs(
-                    FileItemTreeId(idx).into(),
+                    id(idx).into(),
                     RawAttrs::new(self.db.upcast(), &variant, self.span_map()),
                 );
             }
@@ -658,7 +658,7 @@ impl<'a> Ctx<'a> {
 
     fn lower_visibility(&mut self, item: &dyn ast::HasVisibility) -> RawVisibilityId {
         let vis =
-            RawVisibility::from_ast_with_span_map(self.db, item.visibility(), self.span_map());
+            RawVisibility::from_opt_ast_with_span_map(self.db, item.visibility(), self.span_map());
         self.data().vis.alloc(vis)
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index 520034d213c..0086b7180b2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -24,7 +24,7 @@ pub(super) fn print_item_tree(db: &dyn DefDatabase, tree: &ItemTree) -> String {
         p.print_mod_item(*item);
     }
 
-    let mut s = p.buf.trim_end_matches('\n').to_string();
+    let mut s = p.buf.trim_end_matches('\n').to_owned();
     s.push('\n');
     s
 }
@@ -58,7 +58,7 @@ impl Printer<'_> {
         wln!(self);
         f(self);
         self.indent_level -= 1;
-        self.buf = self.buf.trim_end_matches('\n').to_string();
+        self.buf = self.buf.trim_end_matches('\n').to_owned();
     }
 
     /// Ensures that a blank line is output before the next text.
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
index 71bc5213336..5670ebfa17f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -70,7 +70,11 @@ use std::{
     panic::{RefUnwindSafe, UnwindSafe},
 };
 
-use base_db::{impl_intern_key, salsa, CrateId, Edition};
+use base_db::{
+    impl_intern_key,
+    salsa::{self, impl_intern_value_trivial},
+    CrateId, Edition,
+};
 use hir_expand::{
     ast_id_map::{AstIdNode, FileAstId},
     builtin_attr_macro::BuiltinAttrExpander,
@@ -87,7 +91,7 @@ use hir_expand::{
 use item_tree::ExternBlock;
 use la_arena::Idx;
 use nameres::DefMap;
-use span::Span;
+use span::{FileId, Span};
 use stdx::impl_from;
 use syntax::{ast, AstNode};
 
@@ -98,142 +102,34 @@ use crate::{
     data::adt::VariantData,
     db::DefDatabase,
     item_tree::{
-        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeModItemNode, Macro2,
-        MacroRules, Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
+        Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
+        Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
     },
 };
 
-/// A `ModuleId` that is always a crate's root module.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct CrateRootModuleId {
-    krate: CrateId,
-}
-
-impl CrateRootModuleId {
-    pub fn def_map(&self, db: &dyn DefDatabase) -> Arc<DefMap> {
-        db.crate_def_map(self.krate)
-    }
-
-    pub fn krate(self) -> CrateId {
-        self.krate
-    }
-}
-
-impl PartialEq<ModuleId> for CrateRootModuleId {
-    fn eq(&self, other: &ModuleId) -> bool {
-        other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
-    }
-}
-impl PartialEq<CrateRootModuleId> for ModuleId {
-    fn eq(&self, other: &CrateRootModuleId) -> bool {
-        other == self
-    }
-}
-
-impl From<CrateRootModuleId> for ModuleId {
-    fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
-        ModuleId { krate, block: None, local_id: DefMap::ROOT }
-    }
-}
-
-impl From<CrateRootModuleId> for ModuleDefId {
-    fn from(value: CrateRootModuleId) -> Self {
-        ModuleDefId::ModuleId(value.into())
-    }
-}
-
-impl From<CrateId> for CrateRootModuleId {
-    fn from(krate: CrateId) -> Self {
-        CrateRootModuleId { krate }
-    }
-}
-
-impl TryFrom<ModuleId> for CrateRootModuleId {
-    type Error = ();
-
-    fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result<Self, Self::Error> {
-        if block.is_none() && local_id == DefMap::ROOT {
-            Ok(CrateRootModuleId { krate })
-        } else {
-            Err(())
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
-pub struct ModuleId {
-    krate: CrateId,
-    /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
-    /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
-    /// `DefMap` of `krate`.
-    block: Option<BlockId>,
-    /// The module's ID in its originating `DefMap`.
-    pub local_id: LocalModuleId,
-}
-
-impl ModuleId {
-    pub fn def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
-        match self.block {
-            Some(block) => db.block_def_map(block),
-            None => db.crate_def_map(self.krate),
-        }
-    }
-
-    pub fn krate(self) -> CrateId {
-        self.krate
-    }
-
-    pub fn name(self, db: &dyn DefDatabase) -> Option<Name> {
-        let def_map = self.def_map(db);
-        let parent = def_map[self.local_id].parent?;
-        def_map[parent].children.iter().find_map(|(name, module_id)| {
-            if *module_id == self.local_id {
-                Some(name.clone())
-            } else {
-                None
-            }
-        })
-    }
-
-    pub fn containing_module(self, db: &dyn DefDatabase) -> Option<ModuleId> {
-        self.def_map(db).containing_module(self.local_id)
-    }
-
-    pub fn containing_block(self) -> Option<BlockId> {
-        self.block
-    }
-
-    pub fn is_block_module(self) -> bool {
-        self.block.is_some() && self.local_id == DefMap::ROOT
-    }
-}
-
-/// An ID of a module, **local** to a `DefMap`.
-pub type LocalModuleId = Idx<nameres::ModuleData>;
-
 #[derive(Debug)]
-pub struct ItemLoc<N: ItemTreeModItemNode> {
+pub struct ItemLoc<N: ItemTreeNode> {
     pub container: ModuleId,
     pub id: ItemTreeId<N>,
 }
 
-impl<N: ItemTreeModItemNode> Clone for ItemLoc<N> {
+impl<N: ItemTreeNode> Clone for ItemLoc<N> {
     fn clone(&self) -> Self {
-        Self { container: self.container, id: self.id }
+        *self
     }
 }
 
-impl<N: ItemTreeModItemNode> Copy for ItemLoc<N> {}
+impl<N: ItemTreeNode> Copy for ItemLoc<N> {}
 
-impl<N: ItemTreeModItemNode> PartialEq for ItemLoc<N> {
+impl<N: ItemTreeNode> PartialEq for ItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeModItemNode> Eq for ItemLoc<N> {}
+impl<N: ItemTreeNode> Eq for ItemLoc<N> {}
 
-impl<N: ItemTreeModItemNode> Hash for ItemLoc<N> {
+impl<N: ItemTreeNode> Hash for ItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
@@ -241,142 +137,153 @@ impl<N: ItemTreeModItemNode> Hash for ItemLoc<N> {
 }
 
 #[derive(Debug)]
-pub struct AssocItemLoc<N: ItemTreeModItemNode> {
+pub struct AssocItemLoc<N: ItemTreeNode> {
     pub container: ItemContainerId,
     pub id: ItemTreeId<N>,
 }
 
-impl<N: ItemTreeModItemNode> Clone for AssocItemLoc<N> {
+impl<N: ItemTreeNode> Clone for AssocItemLoc<N> {
     fn clone(&self) -> Self {
-        Self { container: self.container, id: self.id }
+        *self
     }
 }
 
-impl<N: ItemTreeModItemNode> Copy for AssocItemLoc<N> {}
+impl<N: ItemTreeNode> Copy for AssocItemLoc<N> {}
 
-impl<N: ItemTreeModItemNode> PartialEq for AssocItemLoc<N> {
+impl<N: ItemTreeNode> PartialEq for AssocItemLoc<N> {
     fn eq(&self, other: &Self) -> bool {
         self.container == other.container && self.id == other.id
     }
 }
 
-impl<N: ItemTreeModItemNode> Eq for AssocItemLoc<N> {}
+impl<N: ItemTreeNode> Eq for AssocItemLoc<N> {}
 
-impl<N: ItemTreeModItemNode> Hash for AssocItemLoc<N> {
+impl<N: ItemTreeNode> Hash for AssocItemLoc<N> {
     fn hash<H: Hasher>(&self, state: &mut H) {
         self.container.hash(state);
         self.id.hash(state);
     }
 }
 
+pub trait ItemTreeLoc {
+    type Container;
+    type Id;
+    fn item_tree_id(&self) -> ItemTreeId<Self::Id>;
+    fn container(&self) -> Self::Container;
+}
+
 macro_rules! impl_intern {
     ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
         impl_intern_key!($id);
+        impl_intern_value_trivial!($loc);
         impl_intern_lookup!(DefDatabase, $id, $loc, $intern, $lookup);
     };
 }
 
+macro_rules! impl_loc {
+    ($loc:ident, $id:ident: $id_ty:ident, $container:ident: $container_type:ident) => {
+        impl ItemTreeLoc for $loc {
+            type Container = $container_type;
+            type Id = $id_ty;
+            fn item_tree_id(&self) -> ItemTreeId<Self::Id> {
+                self.$id
+            }
+            fn container(&self) -> Self::Container {
+                self.$container
+            }
+        }
+    };
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct FunctionId(salsa::InternId);
 type FunctionLoc = AssocItemLoc<Function>;
 impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
+impl_loc!(FunctionLoc, id: Function, container: ItemContainerId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct StructId(salsa::InternId);
 type StructLoc = ItemLoc<Struct>;
 impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
+impl_loc!(StructLoc, id: Struct, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct UnionId(salsa::InternId);
 pub type UnionLoc = ItemLoc<Union>;
 impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
+impl_loc!(UnionLoc, id: Union, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
 pub struct EnumId(salsa::InternId);
 pub type EnumLoc = ItemLoc<Enum>;
 impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct EnumVariantId(salsa::InternId);
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct EnumVariantLoc {
-    pub id: ItemTreeId<Variant>,
-    pub parent: EnumId,
-    pub index: u32,
-}
-impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant);
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct FieldId {
-    pub parent: VariantId,
-    pub local_id: LocalFieldId,
-}
-
-pub type LocalFieldId = Idx<data::adt::FieldData>;
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TupleId(pub u32);
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TupleFieldId {
-    pub tuple: TupleId,
-    pub index: u32,
-}
+impl_loc!(EnumLoc, id: Enum, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct ConstId(salsa::InternId);
 type ConstLoc = AssocItemLoc<Const>;
 impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
+impl_loc!(ConstLoc, id: Const, container: ItemContainerId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct StaticId(salsa::InternId);
 pub type StaticLoc = AssocItemLoc<Static>;
 impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
+impl_loc!(StaticLoc, id: Static, container: ItemContainerId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct TraitId(salsa::InternId);
 pub type TraitLoc = ItemLoc<Trait>;
 impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
+impl_loc!(TraitLoc, id: Trait, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct TraitAliasId(salsa::InternId);
 pub type TraitAliasLoc = ItemLoc<TraitAlias>;
 impl_intern!(TraitAliasId, TraitAliasLoc, intern_trait_alias, lookup_intern_trait_alias);
+impl_loc!(TraitAliasLoc, id: TraitAlias, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct TypeAliasId(salsa::InternId);
 type TypeAliasLoc = AssocItemLoc<TypeAlias>;
 impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
+impl_loc!(TypeAliasLoc, id: TypeAlias, container: ItemContainerId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ImplId(salsa::InternId);
 type ImplLoc = ItemLoc<Impl>;
 impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
+impl_loc!(ImplLoc, id: Impl, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct UseId(salsa::InternId);
 type UseLoc = ItemLoc<Use>;
 impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
+impl_loc!(UseLoc, id: Use, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ExternCrateId(salsa::InternId);
 type ExternCrateLoc = ItemLoc<ExternCrate>;
 impl_intern!(ExternCrateId, ExternCrateLoc, intern_extern_crate, lookup_intern_extern_crate);
+impl_loc!(ExternCrateLoc, id: ExternCrate, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ExternBlockId(salsa::InternId);
 type ExternBlockLoc = ItemLoc<ExternBlock>;
 impl_intern!(ExternBlockId, ExternBlockLoc, intern_extern_block, lookup_intern_extern_block);
+impl_loc!(ExternBlockLoc, id: ExternBlock, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub enum MacroExpander {
-    Declarative,
-    BuiltIn(BuiltinFnLikeExpander),
-    BuiltInAttr(BuiltinAttrExpander),
-    BuiltInDerive(BuiltinDeriveExpander),
-    BuiltInEager(EagerExpander),
+pub struct EnumVariantId(salsa::InternId);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct EnumVariantLoc {
+    pub id: ItemTreeId<Variant>,
+    pub parent: EnumId,
+    pub index: u32,
 }
+impl_intern!(EnumVariantId, EnumVariantLoc, intern_enum_variant, lookup_intern_enum_variant);
+impl_loc!(EnumVariantLoc, id: Variant, parent: EnumId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct Macro2Id(salsa::InternId);
@@ -389,6 +296,7 @@ pub struct Macro2Loc {
     pub edition: Edition,
 }
 impl_intern!(Macro2Id, Macro2Loc, intern_macro2, lookup_intern_macro2);
+impl_loc!(Macro2Loc, id: Macro2, container: ModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct MacroRulesId(salsa::InternId);
@@ -401,6 +309,7 @@ pub struct MacroRulesLoc {
     pub edition: Edition,
 }
 impl_intern!(MacroRulesId, MacroRulesLoc, intern_macro_rules, lookup_intern_macro_rules);
+impl_loc!(MacroRulesLoc, id: MacroRules, container: ModuleId);
 
 bitflags::bitflags! {
     #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -410,6 +319,14 @@ bitflags::bitflags! {
     }
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub enum MacroExpander {
+    Declarative,
+    BuiltIn(BuiltinFnLikeExpander),
+    BuiltInAttr(BuiltinAttrExpander),
+    BuiltInDerive(BuiltinDeriveExpander),
+    BuiltInEager(EagerExpander),
+}
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ProcMacroId(salsa::InternId);
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -421,6 +338,7 @@ pub struct ProcMacroLoc {
     pub edition: Edition,
 }
 impl_intern!(ProcMacroId, ProcMacroLoc, intern_proc_macro, lookup_intern_proc_macro);
+impl_loc!(ProcMacroLoc, id: Function, container: CrateRootModuleId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct BlockId(salsa::InternId);
@@ -432,11 +350,152 @@ pub struct BlockLoc {
 }
 impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 
+/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and
+/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent.
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
+pub struct ConstBlockId(salsa::InternId);
+impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const);
+
+#[derive(Debug, Hash, PartialEq, Eq, Clone)]
+pub struct ConstBlockLoc {
+    /// The parent of the anonymous const block.
+    pub parent: DefWithBodyId,
+    /// The root expression of this const block in the parent body.
+    pub root: hir::ExprId,
+}
+
+/// A `ModuleId` that is always a crate's root module.
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct CrateRootModuleId {
+    krate: CrateId,
+}
+
+impl CrateRootModuleId {
+    pub fn def_map(&self, db: &dyn DefDatabase) -> Arc<DefMap> {
+        db.crate_def_map(self.krate)
+    }
+
+    pub fn krate(self) -> CrateId {
+        self.krate
+    }
+}
+
+impl PartialEq<ModuleId> for CrateRootModuleId {
+    fn eq(&self, other: &ModuleId) -> bool {
+        other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate
+    }
+}
+
+impl From<CrateId> for CrateRootModuleId {
+    fn from(krate: CrateId) -> Self {
+        CrateRootModuleId { krate }
+    }
+}
+
+impl TryFrom<ModuleId> for CrateRootModuleId {
+    type Error = ();
+
+    fn try_from(ModuleId { krate, block, local_id }: ModuleId) -> Result<Self, Self::Error> {
+        if block.is_none() && local_id == DefMap::ROOT {
+            Ok(CrateRootModuleId { krate })
+        } else {
+            Err(())
+        }
+    }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct ModuleId {
+    krate: CrateId,
+    /// If this `ModuleId` was derived from a `DefMap` for a block expression, this stores the
+    /// `BlockId` of that block expression. If `None`, this module is part of the crate-level
+    /// `DefMap` of `krate`.
+    block: Option<BlockId>,
+    /// The module's ID in its originating `DefMap`.
+    pub local_id: LocalModuleId,
+}
+
+impl ModuleId {
+    pub fn def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
+        match self.block {
+            Some(block) => db.block_def_map(block),
+            None => db.crate_def_map(self.krate),
+        }
+    }
+
+    pub fn krate(self) -> CrateId {
+        self.krate
+    }
+
+    pub fn name(self, db: &dyn DefDatabase) -> Option<Name> {
+        let def_map = self.def_map(db);
+        let parent = def_map[self.local_id].parent?;
+        def_map[parent].children.iter().find_map(|(name, module_id)| {
+            if *module_id == self.local_id {
+                Some(name.clone())
+            } else {
+                None
+            }
+        })
+    }
+
+    pub fn containing_module(self, db: &dyn DefDatabase) -> Option<ModuleId> {
+        self.def_map(db).containing_module(self.local_id)
+    }
+
+    pub fn containing_block(self) -> Option<BlockId> {
+        self.block
+    }
+
+    pub fn is_block_module(self) -> bool {
+        self.block.is_some() && self.local_id == DefMap::ROOT
+    }
+}
+
+impl PartialEq<CrateRootModuleId> for ModuleId {
+    fn eq(&self, other: &CrateRootModuleId) -> bool {
+        other == self
+    }
+}
+
+impl From<CrateRootModuleId> for ModuleId {
+    fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self {
+        ModuleId { krate, block: None, local_id: DefMap::ROOT }
+    }
+}
+
+impl From<CrateRootModuleId> for ModuleDefId {
+    fn from(value: CrateRootModuleId) -> Self {
+        ModuleDefId::ModuleId(value.into())
+    }
+}
+
+/// An ID of a module, **local** to a `DefMap`.
+pub type LocalModuleId = Idx<nameres::ModuleData>;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct FieldId {
+    pub parent: VariantId,
+    pub local_id: LocalFieldId,
+}
+
+pub type LocalFieldId = Idx<data::adt::FieldData>;
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct TupleId(pub u32);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct TupleFieldId {
+    pub tuple: TupleId,
+    pub index: u32,
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct TypeOrConstParamId {
     pub parent: GenericDefId,
     pub local_id: LocalTypeOrConstParamId,
 }
+impl_intern_value_trivial!(TypeOrConstParamId);
 
 /// A TypeOrConstParamId with an invariant that it actually belongs to a type
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -498,6 +557,7 @@ pub struct LifetimeParamId {
     pub local_id: LocalLifetimeParamId,
 }
 pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
+impl_intern_value_trivial!(LifetimeParamId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ItemContainerId {
@@ -572,20 +632,6 @@ impl_from!(
     for ModuleDefId
 );
 
-/// Id of the anonymous const block expression and patterns. This is very similar to `ClosureId` and
-/// shouldn't be a `DefWithBodyId` since its type inference is dependent on its parent.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub struct ConstBlockId(salsa::InternId);
-impl_intern!(ConstBlockId, ConstBlockLoc, intern_anonymous_const, lookup_intern_anonymous_const);
-
-#[derive(Debug, Hash, PartialEq, Eq, Clone)]
-pub struct ConstBlockLoc {
-    /// The parent of the anonymous const block.
-    pub parent: DefWithBodyId,
-    /// The root expression of this const block in the parent body.
-    pub root: hir::ExprId,
-}
-
 /// Something that holds types, required for the current const arg lowering implementation as they
 /// need to be able to query where they are defined.
 #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
@@ -721,6 +767,9 @@ impl Clone for Box<dyn OpaqueInternableThing> {
 pub struct InTypeConstId(salsa::InternId);
 impl_intern!(InTypeConstId, InTypeConstLoc, intern_in_type_const, lookup_intern_in_type_const);
 
+// We would like to set `derive(PartialEq)`
+// but the compiler complains about that `.expected_ty` does not implement the `Copy` trait.
+#[allow(clippy::derived_hash_with_manual_eq)]
 #[derive(Debug, Hash, Eq, Clone)]
 pub struct InTypeConstLoc {
     pub id: AstId<ast::ConstArg>,
@@ -850,6 +899,39 @@ impl_from!(
     for GenericDefId
 );
 
+impl GenericDefId {
+    fn file_id_and_params_of(
+        self,
+        db: &dyn DefDatabase,
+    ) -> (HirFileId, Option<ast::GenericParamList>) {
+        fn file_id_and_params_of_item_loc<Loc>(
+            db: &dyn DefDatabase,
+            def: impl for<'db> Lookup<Database<'db> = dyn DefDatabase + 'db, Data = Loc>,
+        ) -> (HirFileId, Option<ast::GenericParamList>)
+        where
+            Loc: src::HasSource,
+            Loc::Value: ast::HasGenericParams,
+        {
+            let src = def.lookup(db).source(db);
+            (src.file_id, ast::HasGenericParams::generic_param_list(&src.value))
+        }
+
+        match self {
+            GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None),
+            GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
+            GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
+            // We won't be using this ID anyway
+            GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None),
+        }
+    }
+}
+
 impl From<AssocItemId> for GenericDefId {
     fn from(item: AssocItemId) -> Self {
         match item {
@@ -983,43 +1065,91 @@ impl VariantId {
 }
 
 pub trait HasModule {
+    /// Returns the enclosing module this thing is defined within.
     fn module(&self, db: &dyn DefDatabase) -> ModuleId;
+    /// Returns the crate this thing is defined within.
+    #[inline]
+    #[doc(alias = "crate")]
+    fn krate(&self, db: &dyn DefDatabase) -> CrateId {
+        self.module(db).krate
+    }
+}
+
+// In theory this impl should work out for us, but rustc thinks it collides with all the other
+// manual impls that do not have a ModuleId container...
+// impl<N, ItemId, Data> HasModule for ItemId
+// where
+//     N: ItemTreeNode,
+//     ItemId: for<'db> Lookup<Database<'db> = dyn DefDatabase + 'db, Data = Data> + Copy,
+//     Data: ItemTreeLoc<Id = N, Container = ModuleId>,
+// {
+//     #[inline]
+//     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+//         self.lookup(db).container()
+//     }
+// }
+
+impl<N, ItemId> HasModule for ItemId
+where
+    N: ItemTreeNode,
+    ItemId: for<'db> Lookup<Database<'db> = dyn DefDatabase + 'db, Data = ItemLoc<N>> + Copy,
+{
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.lookup(db).container
+    }
 }
 
-impl HasModule for ItemContainerId {
+// Technically this does not overlap with the above, but rustc currently forbids this, hence why we
+// need to write the 3 impls manually instead
+// impl<N, ItemId> HasModule for ItemId
+// where
+//     N: ItemTreeModItemNode,
+//     ItemId: for<'db> Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<N>> + Copy,
+// {
+//     #[inline]
+//     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+//         self.lookup(db).container.module(db)
+//     }
+// }
+
+// region: manual-assoc-has-module-impls
+#[inline]
+fn module_for_assoc_item_loc<'db>(
+    db: &(dyn 'db + DefDatabase),
+    id: impl Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<impl ItemTreeNode>>,
+) -> ModuleId {
+    id.lookup(db).container.module(db)
+}
+
+impl HasModule for FunctionId {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        match *self {
-            ItemContainerId::ModuleId(it) => it,
-            ItemContainerId::ImplId(it) => it.lookup(db).container,
-            ItemContainerId::TraitId(it) => it.lookup(db).container,
-            ItemContainerId::ExternBlockId(it) => it.lookup(db).container,
-        }
+        module_for_assoc_item_loc(db, *self)
     }
 }
 
-impl<N: ItemTreeModItemNode> HasModule for AssocItemLoc<N> {
+impl HasModule for ConstId {
     #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        self.container.module(db)
+        module_for_assoc_item_loc(db, *self)
     }
 }
 
-impl HasModule for AdtId {
+impl HasModule for StaticId {
+    #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        match self {
-            AdtId::StructId(it) => it.lookup(db).container,
-            AdtId::UnionId(it) => it.lookup(db).container,
-            AdtId::EnumId(it) => it.lookup(db).container,
-        }
+        module_for_assoc_item_loc(db, *self)
     }
 }
 
-impl HasModule for EnumId {
+impl HasModule for TypeAliasId {
     #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        self.lookup(db).container
+        module_for_assoc_item_loc(db, *self)
     }
 }
+// endregion: manual-assoc-has-module-impls
 
 impl HasModule for EnumVariantId {
     #[inline]
@@ -1028,46 +1158,81 @@ impl HasModule for EnumVariantId {
     }
 }
 
-impl HasModule for ExternCrateId {
+impl HasModule for MacroRulesId {
     #[inline]
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         self.lookup(db).container
     }
 }
 
+impl HasModule for Macro2Id {
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.lookup(db).container
+    }
+}
+
+impl HasModule for ProcMacroId {
+    #[inline]
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        self.lookup(db).container.into()
+    }
+}
+
+impl HasModule for ItemContainerId {
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        match *self {
+            ItemContainerId::ModuleId(it) => it,
+            ItemContainerId::ImplId(it) => it.module(db),
+            ItemContainerId::TraitId(it) => it.module(db),
+            ItemContainerId::ExternBlockId(it) => it.module(db),
+        }
+    }
+}
+
+impl HasModule for AdtId {
+    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
+        match *self {
+            AdtId::StructId(it) => it.module(db),
+            AdtId::UnionId(it) => it.module(db),
+            AdtId::EnumId(it) => it.module(db),
+        }
+    }
+}
+
 impl HasModule for VariantId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        match self {
-            VariantId::EnumVariantId(it) => it.lookup(db).parent.module(db),
-            VariantId::StructId(it) => it.lookup(db).container,
-            VariantId::UnionId(it) => it.lookup(db).container,
+        match *self {
+            VariantId::EnumVariantId(it) => it.module(db),
+            VariantId::StructId(it) => it.module(db),
+            VariantId::UnionId(it) => it.module(db),
         }
     }
 }
 
 impl HasModule for MacroId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        match self {
-            MacroId::MacroRulesId(it) => it.lookup(db).container,
-            MacroId::Macro2Id(it) => it.lookup(db).container,
-            MacroId::ProcMacroId(it) => it.lookup(db).container.into(),
+        match *self {
+            MacroId::MacroRulesId(it) => it.module(db),
+            MacroId::Macro2Id(it) => it.module(db),
+            MacroId::ProcMacroId(it) => it.module(db),
         }
     }
 }
 
 impl HasModule for TypeOwnerId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        match self {
-            TypeOwnerId::FunctionId(it) => it.lookup(db).module(db),
-            TypeOwnerId::StaticId(it) => it.lookup(db).module(db),
-            TypeOwnerId::ConstId(it) => it.lookup(db).module(db),
-            TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db),
+        match *self {
+            TypeOwnerId::FunctionId(it) => it.module(db),
+            TypeOwnerId::StaticId(it) => it.module(db),
+            TypeOwnerId::ConstId(it) => it.module(db),
             TypeOwnerId::AdtId(it) => it.module(db),
-            TypeOwnerId::TraitId(it) => it.lookup(db).container,
-            TypeOwnerId::TraitAliasId(it) => it.lookup(db).container,
-            TypeOwnerId::TypeAliasId(it) => it.lookup(db).module(db),
-            TypeOwnerId::ImplId(it) => it.lookup(db).container,
-            TypeOwnerId::EnumVariantId(it) => it.lookup(db).parent.module(db),
+            TypeOwnerId::TraitId(it) => it.module(db),
+            TypeOwnerId::TraitAliasId(it) => it.module(db),
+            TypeOwnerId::TypeAliasId(it) => it.module(db),
+            TypeOwnerId::ImplId(it) => it.module(db),
+            TypeOwnerId::EnumVariantId(it) => it.module(db),
+            TypeOwnerId::InTypeConstId(it) => it.lookup(db).owner.module(db),
         }
     }
 }
@@ -1075,10 +1240,10 @@ impl HasModule for TypeOwnerId {
 impl HasModule for DefWithBodyId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         match self {
-            DefWithBodyId::FunctionId(it) => it.lookup(db).module(db),
-            DefWithBodyId::StaticId(it) => it.lookup(db).module(db),
-            DefWithBodyId::ConstId(it) => it.lookup(db).module(db),
-            DefWithBodyId::VariantId(it) => it.lookup(db).parent.module(db),
+            DefWithBodyId::FunctionId(it) => it.module(db),
+            DefWithBodyId::StaticId(it) => it.module(db),
+            DefWithBodyId::ConstId(it) => it.module(db),
+            DefWithBodyId::VariantId(it) => it.module(db),
             DefWithBodyId::InTypeConstId(it) => it.lookup(db).owner.module(db),
         }
     }
@@ -1087,29 +1252,43 @@ impl HasModule for DefWithBodyId {
 impl HasModule for GenericDefId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
         match self {
-            GenericDefId::FunctionId(it) => it.lookup(db).module(db),
+            GenericDefId::FunctionId(it) => it.module(db),
             GenericDefId::AdtId(it) => it.module(db),
-            GenericDefId::TraitId(it) => it.lookup(db).container,
-            GenericDefId::TraitAliasId(it) => it.lookup(db).container,
-            GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
-            GenericDefId::ImplId(it) => it.lookup(db).container,
-            GenericDefId::EnumVariantId(it) => it.lookup(db).parent.lookup(db).container,
-            GenericDefId::ConstId(it) => it.lookup(db).module(db),
+            GenericDefId::TraitId(it) => it.module(db),
+            GenericDefId::TraitAliasId(it) => it.module(db),
+            GenericDefId::TypeAliasId(it) => it.module(db),
+            GenericDefId::ImplId(it) => it.module(db),
+            GenericDefId::EnumVariantId(it) => it.module(db),
+            GenericDefId::ConstId(it) => it.module(db),
         }
     }
 }
 
-impl HasModule for TypeAliasId {
-    #[inline]
-    fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        self.lookup(db).module(db)
-    }
-}
-
-impl HasModule for TraitId {
-    #[inline]
+impl HasModule for AttrDefId {
     fn module(&self, db: &dyn DefDatabase) -> ModuleId {
-        self.lookup(db).container
+        match self {
+            AttrDefId::ModuleId(it) => *it,
+            AttrDefId::FieldId(it) => it.parent.module(db),
+            AttrDefId::AdtId(it) => it.module(db),
+            AttrDefId::FunctionId(it) => it.module(db),
+            AttrDefId::EnumVariantId(it) => it.module(db),
+            AttrDefId::StaticId(it) => it.module(db),
+            AttrDefId::ConstId(it) => it.module(db),
+            AttrDefId::TraitId(it) => it.module(db),
+            AttrDefId::TraitAliasId(it) => it.module(db),
+            AttrDefId::TypeAliasId(it) => it.module(db),
+            AttrDefId::ImplId(it) => it.module(db),
+            AttrDefId::ExternBlockId(it) => it.module(db),
+            AttrDefId::GenericParamId(it) => match it {
+                GenericParamId::TypeParamId(it) => it.parent(),
+                GenericParamId::ConstParamId(it) => it.parent(),
+                GenericParamId::LifetimeParamId(it) => it.parent,
+            }
+            .module(db),
+            AttrDefId::MacroId(it) => it.module(db),
+            AttrDefId::ExternCrateId(it) => it.module(db),
+            AttrDefId::UseId(it) => it.module(db),
+        }
     }
 }
 
@@ -1120,51 +1299,20 @@ impl ModuleDefId {
     pub fn module(&self, db: &dyn DefDatabase) -> Option<ModuleId> {
         Some(match self {
             ModuleDefId::ModuleId(id) => *id,
-            ModuleDefId::FunctionId(id) => id.lookup(db).module(db),
+            ModuleDefId::FunctionId(id) => id.module(db),
             ModuleDefId::AdtId(id) => id.module(db),
-            ModuleDefId::EnumVariantId(id) => id.lookup(db).parent.module(db),
-            ModuleDefId::ConstId(id) => id.lookup(db).container.module(db),
-            ModuleDefId::StaticId(id) => id.lookup(db).module(db),
-            ModuleDefId::TraitId(id) => id.lookup(db).container,
-            ModuleDefId::TraitAliasId(id) => id.lookup(db).container,
-            ModuleDefId::TypeAliasId(id) => id.lookup(db).module(db),
+            ModuleDefId::EnumVariantId(id) => id.module(db),
+            ModuleDefId::ConstId(id) => id.module(db),
+            ModuleDefId::StaticId(id) => id.module(db),
+            ModuleDefId::TraitId(id) => id.module(db),
+            ModuleDefId::TraitAliasId(id) => id.module(db),
+            ModuleDefId::TypeAliasId(id) => id.module(db),
             ModuleDefId::MacroId(id) => id.module(db),
             ModuleDefId::BuiltinType(_) => return None,
         })
     }
 }
 
-impl AttrDefId {
-    pub fn krate(&self, db: &dyn DefDatabase) -> CrateId {
-        match self {
-            AttrDefId::ModuleId(it) => it.krate,
-            AttrDefId::FieldId(it) => it.parent.module(db).krate,
-            AttrDefId::AdtId(it) => it.module(db).krate,
-            AttrDefId::FunctionId(it) => it.lookup(db).module(db).krate,
-            AttrDefId::EnumVariantId(it) => it.lookup(db).parent.module(db).krate,
-            AttrDefId::StaticId(it) => it.lookup(db).module(db).krate,
-            AttrDefId::ConstId(it) => it.lookup(db).module(db).krate,
-            AttrDefId::TraitId(it) => it.lookup(db).container.krate,
-            AttrDefId::TraitAliasId(it) => it.lookup(db).container.krate,
-            AttrDefId::TypeAliasId(it) => it.lookup(db).module(db).krate,
-            AttrDefId::ImplId(it) => it.lookup(db).container.krate,
-            AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
-            AttrDefId::GenericParamId(it) => {
-                match it {
-                    GenericParamId::TypeParamId(it) => it.parent(),
-                    GenericParamId::ConstParamId(it) => it.parent(),
-                    GenericParamId::LifetimeParamId(it) => it.parent,
-                }
-                .module(db)
-                .krate
-            }
-            AttrDefId::MacroId(it) => it.module(db).krate,
-            AttrDefId::ExternCrateId(it) => it.lookup(db).container.krate,
-            AttrDefId::UseId(it) => it.lookup(db).container.krate,
-        }
-    }
-}
-
 /// A helper trait for converting to MacroCallId
 pub trait AsMacroCall {
     fn as_call_id(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
index 553c0b79533..86b4466153a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_derive_macro.rs
@@ -157,7 +157,7 @@ where
     generic: Vec<T::InGenericArg>,
 }
 
-impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, {
+impl <T: $crate::clone::Clone, > $crate::clone::Clone for Foo<T, > where <T as Trait>::InWc: Marker, T: Trait, T::InFieldShorthand: $crate::clone::Clone, T::InGenericArg: $crate::clone::Clone, {
     fn clone(&self ) -> Self {
         match self {
             Foo {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
index d0ae1f59f7c..edc8247f166 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs
@@ -35,9 +35,9 @@ macro_rules! f {
     };
 }
 
-struct#0:1@58..64#2# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#2#
-    map#0:1@86..89#2#:#0:1@89..90#2# #0:1@89..90#2#::#0:1@91..92#2#std#0:1@93..96#2#::#0:1@96..97#2#collections#0:1@98..109#2#::#0:1@109..110#2#HashSet#0:1@111..118#2#<#0:1@118..119#2#(#0:1@119..120#2#)#0:1@120..121#2#>#0:1@121..122#2#,#0:1@122..123#2#
-}#0:1@132..133#2#
+struct#0:1@58..64#1# MyTraitMap2#0:2@31..42#0# {#0:1@72..73#1#
+    map#0:1@86..89#1#:#0:1@89..90#1# #0:1@89..90#1#::#0:1@91..92#1#std#0:1@93..96#1#::#0:1@96..97#1#collections#0:1@98..109#1#::#0:1@109..110#1#HashSet#0:1@111..118#1#<#0:1@118..119#1#(#0:1@119..120#1#)#0:1@120..121#1#>#0:1@121..122#1#,#0:1@122..123#1#
+}#0:1@132..133#1#
 "#]],
     );
 }
@@ -171,7 +171,7 @@ fn main(foo: ()) {
     }
 
     fn main(foo: ()) {
-        /* error: unresolved macro unresolved */"helloworld!"#0:3@207..323#6#;
+        /* error: unresolved macro unresolved */"helloworld!"#0:3@207..323#2#;
     }
 }
 
@@ -197,7 +197,7 @@ macro_rules! mk_struct {
 #[macro_use]
 mod foo;
 
-struct#1:1@59..65#2# Foo#0:2@32..35#0#(#1:1@70..71#2#u32#0:2@41..44#0#)#1:1@74..75#2#;#1:1@75..76#2#
+struct#1:1@59..65#1# Foo#0:2@32..35#0#(#1:1@70..71#1#u32#0:2@41..44#0#)#1:1@74..75#1#;#1:1@75..76#1#
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
index e315414e9bd..fc5a6e80a42 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs
@@ -224,7 +224,7 @@ fn reindent(indent: IndentLevel, pp: String) -> String {
         return pp;
     }
     let mut lines = pp.split_inclusive('\n');
-    let mut res = lines.next().unwrap().to_string();
+    let mut res = lines.next().unwrap().to_owned();
     for line in lines {
         if line.trim().is_empty() {
             res.push_str(line)
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
index fb6fd867a16..21cc28f1b3d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs
@@ -33,8 +33,8 @@ use crate::{
     db::DefDatabase,
     item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
     item_tree::{
-        self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
-        ItemTreeModItemNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
+        self, ExternCrate, Fields, FileItemTreeId, ImportKind, ItemTree, ItemTreeId, ItemTreeNode,
+        Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId,
     },
     macro_call_as_call_id, macro_call_as_call_id_with_eager,
     nameres::{
@@ -2125,7 +2125,7 @@ impl ModCollector<'_, '_> {
 
         let is_export = export_attr.exists();
         let local_inner = if is_export {
-            export_attr.tt_values().flat_map(|it| &it.token_trees).any(|it| match it {
+            export_attr.tt_values().flat_map(|it| it.token_trees.iter()).any(|it| match it {
                 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => {
                     ident.text.contains("local_inner_macros")
                 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 7a9c4ea0169..db47d743c5a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -27,9 +27,9 @@ use crate::{
     visibility::{RawVisibility, Visibility},
     AdtId, ConstId, ConstParamId, CrateRootModuleId, DefWithBodyId, EnumId, EnumVariantId,
     ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId, HasModule, ImplId,
-    ItemContainerId, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId, MacroRulesId,
-    ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId, TypeAliasId,
-    TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
+    ItemContainerId, ItemTreeLoc, LifetimeParamId, LocalModuleId, Lookup, Macro2Id, MacroId,
+    MacroRulesId, ModuleDefId, ModuleId, ProcMacroId, StaticId, StructId, TraitAliasId, TraitId,
+    TypeAliasId, TypeOrConstParamId, TypeOwnerId, TypeParamId, UseId, VariantId,
 };
 
 #[derive(Debug, Clone)]
@@ -248,6 +248,7 @@ impl Resolver {
             RawVisibility::Public => Some(Visibility::Public),
         }
     }
+
     pub fn resolve_path_in_value_ns(
         &self,
         db: &dyn DefDatabase,
@@ -1014,13 +1015,13 @@ impl HasResolver for CrateRootModuleId {
 
 impl HasResolver for TraitId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
+        lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for TraitAliasId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
+        lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
@@ -1036,25 +1037,25 @@ impl<T: Into<AdtId> + Copy> HasResolver for T {
 
 impl HasResolver for FunctionId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
+        lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
 impl HasResolver for ConstId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for StaticId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for TypeAliasId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
+        lookup_resolver(db, self).push_generic_params_scope(db, self.into())
     }
 }
 
@@ -1071,19 +1072,19 @@ impl HasResolver for ImplId {
 impl HasResolver for ExternBlockId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
         // Same as parent's
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for ExternCrateId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for UseId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
@@ -1170,18 +1171,28 @@ impl HasResolver for MacroId {
 
 impl HasResolver for Macro2Id {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for ProcMacroId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
 
 impl HasResolver for MacroRulesId {
     fn resolver(self, db: &dyn DefDatabase) -> Resolver {
-        self.lookup(db).container.resolver(db)
+        lookup_resolver(db, self)
     }
 }
+
+fn lookup_resolver<'db>(
+    db: &(dyn DefDatabase + 'db),
+    lookup: impl Lookup<
+        Database<'db> = dyn DefDatabase + 'db,
+        Data = impl ItemTreeLoc<Container = impl HasResolver>,
+    >,
+) -> Resolver {
+    lookup.lookup(db).container().resolver(db)
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/src.rs b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
index 9bd8c8d2215..4283f003f89 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/src.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/src.rs
@@ -1,12 +1,14 @@
 //! Utilities for mapping between hir IDs and the surface syntax.
 
+use either::Either;
 use hir_expand::InFile;
 use la_arena::ArenaMap;
 use syntax::ast;
 
 use crate::{
-    db::DefDatabase, item_tree::ItemTreeModItemNode, AssocItemLoc, EnumVariantLoc, ItemLoc, Lookup,
-    Macro2Loc, MacroRulesLoc, ProcMacroLoc, UseId,
+    data::adt::lower_struct, db::DefDatabase, item_tree::ItemTreeNode, trace::Trace, GenericDefId,
+    ItemTreeLoc, LocalFieldId, LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, UseId,
+    VariantId,
 };
 
 pub trait HasSource {
@@ -14,81 +16,22 @@ pub trait HasSource {
     fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value>;
 }
 
-impl<N: ItemTreeModItemNode> HasSource for AssocItemLoc<N> {
-    type Value = N::Source;
-
-    fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
-    }
-}
-
-impl<N: ItemTreeModItemNode> HasSource for ItemLoc<N> {
-    type Value = N::Source;
-
-    fn source(&self, db: &dyn DefDatabase) -> InFile<N::Source> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
-    }
-}
-
-impl HasSource for EnumVariantLoc {
-    type Value = ast::Variant;
-
-    fn source(&self, db: &dyn DefDatabase) -> InFile<ast::Variant> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id).to_node(&root))
-    }
-}
-
-impl HasSource for Macro2Loc {
-    type Value = ast::MacroDef;
-
-    fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
-    }
-}
-
-impl HasSource for MacroRulesLoc {
-    type Value = ast::MacroRules;
+impl<T> HasSource for T
+where
+    T: ItemTreeLoc,
+    T::Id: ItemTreeNode,
+{
+    type Value = <T::Id as ItemTreeNode>::Source;
 
     fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
-    }
-}
-
-impl HasSource for ProcMacroLoc {
-    type Value = ast::Fn;
-
-    fn source(&self, db: &dyn DefDatabase) -> InFile<Self::Value> {
-        let tree = self.id.item_tree(db);
-        let ast_id_map = db.ast_id_map(self.id.file_id());
-        let root = db.parse_or_expand(self.id.file_id());
-        let node = &tree[self.id.value];
-
-        InFile::new(self.id.file_id(), ast_id_map.get(node.ast_id()).to_node(&root))
+        let id = self.item_tree_id();
+        let file_id = id.file_id();
+        let tree = id.item_tree(db);
+        let ast_id_map = db.ast_id_map(file_id);
+        let root = db.parse_or_expand(file_id);
+        let node = &tree[id.value];
+
+        InFile::new(file_id, ast_id_map.get(node.ast_id()).to_node(&root))
     }
 }
 
@@ -111,3 +54,105 @@ impl HasChildSource<la_arena::Idx<ast::UseTree>> for UseId {
         )
     }
 }
+
+impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
+    type Value = Either<ast::TypeOrConstParam, ast::TraitOrAlias>;
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
+        let generic_params = db.generic_params(*self);
+        let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
+
+        let (file_id, generic_params_list) = self.file_id_and_params_of(db);
+
+        let mut params = ArenaMap::default();
+
+        // For traits and trait aliases the first type index is `Self`, we need to add it before
+        // the other params.
+        match *self {
+            GenericDefId::TraitId(id) => {
+                let trait_ref = id.lookup(db).source(db).value;
+                let idx = idx_iter.next().unwrap();
+                params.insert(idx, Either::Right(ast::TraitOrAlias::Trait(trait_ref)));
+            }
+            GenericDefId::TraitAliasId(id) => {
+                let alias = id.lookup(db).source(db).value;
+                let idx = idx_iter.next().unwrap();
+                params.insert(idx, Either::Right(ast::TraitOrAlias::TraitAlias(alias)));
+            }
+            _ => {}
+        }
+
+        if let Some(generic_params_list) = generic_params_list {
+            for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) {
+                params.insert(idx, Either::Left(ast_param));
+            }
+        }
+
+        InFile::new(file_id, params)
+    }
+}
+
+impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
+    type Value = ast::LifetimeParam;
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalLifetimeParamId, Self::Value>> {
+        let generic_params = db.generic_params(*self);
+        let idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
+
+        let (file_id, generic_params_list) = self.file_id_and_params_of(db);
+
+        let mut params = ArenaMap::default();
+
+        if let Some(generic_params_list) = generic_params_list {
+            for (idx, ast_param) in idx_iter.zip(generic_params_list.lifetime_params()) {
+                params.insert(idx, ast_param);
+            }
+        }
+
+        InFile::new(file_id, params)
+    }
+}
+
+impl HasChildSource<LocalFieldId> for VariantId {
+    type Value = Either<ast::TupleField, ast::RecordField>;
+
+    fn child_source(&self, db: &dyn DefDatabase) -> InFile<ArenaMap<LocalFieldId, Self::Value>> {
+        let item_tree;
+        let (src, fields, container) = match *self {
+            VariantId::EnumVariantId(it) => {
+                let lookup = it.lookup(db);
+                item_tree = lookup.id.item_tree(db);
+                (
+                    lookup.source(db).map(|it| it.kind()),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.parent.lookup(db).container,
+                )
+            }
+            VariantId::StructId(it) => {
+                let lookup = it.lookup(db);
+                item_tree = lookup.id.item_tree(db);
+                (
+                    lookup.source(db).map(|it| it.kind()),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.container,
+                )
+            }
+            VariantId::UnionId(it) => {
+                let lookup = it.lookup(db);
+                item_tree = lookup.id.item_tree(db);
+                (
+                    lookup.source(db).map(|it| it.kind()),
+                    &item_tree[lookup.id.value].fields,
+                    lookup.container,
+                )
+            }
+        };
+        let mut trace = Trace::new_for_map();
+        lower_struct(db, &mut trace, &src, container.krate, &item_tree, fields);
+        src.with_value(trace.into_map())
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/trace.rs b/src/tools/rust-analyzer/crates/hir-def/src/trace.rs
index 04d5b266194..da50ee8dc7a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/trace.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/trace.rs
@@ -11,6 +11,8 @@
 //! projections.
 use la_arena::{Arena, ArenaMap, Idx, RawIdx};
 
+// FIXME: This isn't really used anymore, at least not in a way where it does anything useful.
+// Check if we should get rid of this or make proper use of it instead.
 pub(crate) struct Trace<T, V> {
     arena: Option<Arena<T>>,
     map: Option<ArenaMap<Idx<T>, V>>,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
index b9676179a5f..0f3fac1cecd 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs
@@ -37,10 +37,14 @@ impl RawVisibility {
         db: &dyn DefDatabase,
         node: InFile<Option<ast::Visibility>>,
     ) -> RawVisibility {
+        let node = match node.transpose() {
+            None => return RawVisibility::private(),
+            Some(node) => node,
+        };
         Self::from_ast_with_span_map(db, node.value, db.span_map(node.file_id).as_ref())
     }
 
-    pub(crate) fn from_ast_with_span_map(
+    pub(crate) fn from_opt_ast_with_span_map(
         db: &dyn DefDatabase,
         node: Option<ast::Visibility>,
         span_map: SpanMapRef<'_>,
@@ -49,29 +53,28 @@ impl RawVisibility {
             None => return RawVisibility::private(),
             Some(node) => node,
         };
-        match node.kind() {
+        Self::from_ast_with_span_map(db, node, span_map)
+    }
+
+    fn from_ast_with_span_map(
+        db: &dyn DefDatabase,
+        node: ast::Visibility,
+        span_map: SpanMapRef<'_>,
+    ) -> RawVisibility {
+        let path = match node.kind() {
             ast::VisibilityKind::In(path) => {
                 let path = ModPath::from_src(db.upcast(), path, span_map);
-                let path = match path {
+                match path {
                     None => return RawVisibility::private(),
                     Some(path) => path,
-                };
-                RawVisibility::Module(path, VisibilityExplicitness::Explicit)
-            }
-            ast::VisibilityKind::PubCrate => {
-                let path = ModPath::from_kind(PathKind::Crate);
-                RawVisibility::Module(path, VisibilityExplicitness::Explicit)
-            }
-            ast::VisibilityKind::PubSuper => {
-                let path = ModPath::from_kind(PathKind::Super(1));
-                RawVisibility::Module(path, VisibilityExplicitness::Explicit)
-            }
-            ast::VisibilityKind::PubSelf => {
-                let path = ModPath::from_kind(PathKind::Super(0));
-                RawVisibility::Module(path, VisibilityExplicitness::Explicit)
+                }
             }
-            ast::VisibilityKind::Pub => RawVisibility::Public,
-        }
+            ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate),
+            ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)),
+            ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)),
+            ast::VisibilityKind::Pub => return RawVisibility::Public,
+        };
+        RawVisibility::Module(path, VisibilityExplicitness::Explicit)
     }
 
     pub fn resolve(
@@ -94,6 +97,11 @@ pub enum Visibility {
 }
 
 impl Visibility {
+    pub(crate) fn is_visible_from_other_crate(self) -> bool {
+        matches!(self, Visibility::Public)
+    }
+
+    #[tracing::instrument(skip_all)]
     pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> bool {
         let to_module = match self {
             Visibility::Module(m, _) => m,
@@ -104,24 +112,33 @@ impl Visibility {
             return false;
         }
         let def_map = from_module.def_map(db);
-        self.is_visible_from_def_map(db, &def_map, from_module.local_id)
-    }
-
-    pub(crate) fn is_visible_from_other_crate(self) -> bool {
-        matches!(self, Visibility::Public)
+        Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id)
     }
 
     pub(crate) fn is_visible_from_def_map(
         self,
         db: &dyn DefDatabase,
         def_map: &DefMap,
-        mut from_module: LocalModuleId,
+        from_module: LocalModuleId,
     ) -> bool {
-        let mut to_module = match self {
+        let to_module = match self {
             Visibility::Module(m, _) => m,
             Visibility::Public => return true,
         };
+        // if they're not in the same crate, it can't be visible
+        if def_map.krate() != to_module.krate {
+            return false;
+        }
+        Self::is_visible_from_def_map_(db, def_map, to_module, from_module)
+    }
 
+    fn is_visible_from_def_map_(
+        db: &dyn DefDatabase,
+        def_map: &DefMap,
+        mut to_module: ModuleId,
+        mut from_module: LocalModuleId,
+    ) -> bool {
+        debug_assert_eq!(to_module.krate, def_map.krate());
         // `to_module` might be the root module of a block expression. Those have the same
         // visibility as the containing module (even though no items are directly nameable from
         // there, getting this right is important for method resolution).
@@ -129,20 +146,25 @@ impl Visibility {
 
         // Additional complication: `to_module` might be in `from_module`'s `DefMap`, which we're
         // currently computing, so we must not call the `def_map` query for it.
-        let mut arc;
+        let def_map_block = def_map.block_id();
         loop {
-            let to_module_def_map =
-                if to_module.krate == def_map.krate() && to_module.block == def_map.block_id() {
+            match (to_module.block, def_map_block) {
+                // to_module is not a block, so there is no parent def map to use
+                (None, _) => (),
+                (Some(a), Some(b)) if a == b => {
                     cov_mark::hit!(is_visible_from_same_block_def_map);
-                    def_map
-                } else {
-                    arc = to_module.def_map(db);
-                    &arc
-                };
-            match to_module_def_map.parent() {
-                Some(parent) => to_module = parent,
-                None => break,
+                    if let Some(parent) = def_map.parent() {
+                        to_module = parent;
+                    }
+                }
+                _ => {
+                    if let Some(parent) = to_module.def_map(db).parent() {
+                        to_module = parent;
+                        continue;
+                    }
+                }
             }
+            break;
         }
 
         // from_module needs to be a descendant of to_module
@@ -175,30 +197,25 @@ impl Visibility {
     /// visible in unrelated modules).
     pub(crate) fn max(self, other: Visibility, def_map: &DefMap) -> Option<Visibility> {
         match (self, other) {
-            (Visibility::Module(_, _) | Visibility::Public, Visibility::Public)
-            | (Visibility::Public, Visibility::Module(_, _)) => Some(Visibility::Public),
-            (Visibility::Module(mod_a, vis_a), Visibility::Module(mod_b, vis_b)) => {
+            (_, Visibility::Public) | (Visibility::Public, _) => Some(Visibility::Public),
+            (Visibility::Module(mod_a, expl_a), Visibility::Module(mod_b, expl_b)) => {
                 if mod_a.krate != mod_b.krate {
                     return None;
                 }
 
-                let mut a_ancestors = iter::successors(Some(mod_a.local_id), |&m| {
-                    let parent_id = def_map[m].parent?;
-                    Some(parent_id)
-                });
-                let mut b_ancestors = iter::successors(Some(mod_b.local_id), |&m| {
-                    let parent_id = def_map[m].parent?;
-                    Some(parent_id)
-                });
+                let mut a_ancestors =
+                    iter::successors(Some(mod_a.local_id), |&m| def_map[m].parent);
+                let mut b_ancestors =
+                    iter::successors(Some(mod_b.local_id), |&m| def_map[m].parent);
 
                 if a_ancestors.any(|m| m == mod_b.local_id) {
                     // B is above A
-                    return Some(Visibility::Module(mod_b, vis_b));
+                    return Some(Visibility::Module(mod_b, expl_b));
                 }
 
                 if b_ancestors.any(|m| m == mod_a.local_id) {
                     // A is above B
-                    return Some(Visibility::Module(mod_a, vis_a));
+                    return Some(Visibility::Module(mod_a, expl_a));
                 }
 
                 None
@@ -207,7 +224,8 @@ impl Visibility {
     }
 }
 
-/// Whether the item was imported through `pub(crate) use` or just `use`.
+/// Whether the item was imported through an explicit `pub(crate) use` or just a `use` without
+/// visibility.
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum VisibilityExplicitness {
     Explicit,
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
index 530f10a0684..ab582741f5b 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/ast_id_map.rs
@@ -155,7 +155,7 @@ impl PartialEq for AstIdMap {
 impl Eq for AstIdMap {}
 
 impl AstIdMap {
-    pub(crate) fn ast_id_map(
+    pub(crate) fn new(
         db: &dyn ExpandDatabase,
         file_id: span::HirFileId,
     ) -> triomphe::Arc<AstIdMap> {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
index c20c1639e1a..1c92dea38e6 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs
@@ -123,7 +123,7 @@ impl RawAttrs {
                 .filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
 
             let cfg_options = &crate_graph[krate].cfg_options;
-            let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
+            let cfg = Subtree { delimiter: subtree.delimiter, token_trees: Box::from(cfg) };
             let cfg = CfgExpr::parse(&cfg);
             if cfg_options.check(&cfg) == Some(false) {
                 smallvec![]
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
index dd2aa94ad01..903b0d48070 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs
@@ -137,5 +137,8 @@ pub fn pseudo_derive_attr_expansion(
         token_trees.extend(tt.iter().cloned());
         token_trees.push(mk_leaf(']'));
     }
-    ExpandResult::ok(tt::Subtree { delimiter: tt.delimiter, token_trees })
+    ExpandResult::ok(tt::Subtree {
+        delimiter: tt.delimiter,
+        token_trees: token_trees.into_boxed_slice(),
+    })
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
index 024fb8c1f61..27954875143 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_derive_macro.rs
@@ -194,6 +194,7 @@ struct BasicAdtInfo {
     /// second field is `Some(ty)` if it's a const param of type `ty`, `None` if it's a type param.
     /// third fields is where bounds, if any
     param_types: Vec<(tt::Subtree, Option<tt::Subtree>, Option<tt::Subtree>)>,
+    where_clause: Vec<tt::Subtree>,
     associated_types: Vec<tt::Subtree>,
 }
 
@@ -202,10 +203,11 @@ fn parse_adt(
     adt: &ast::Adt,
     call_site: Span,
 ) -> Result<BasicAdtInfo, ExpandError> {
-    let (name, generic_param_list, shape) = match adt {
+    let (name, generic_param_list, where_clause, shape) = match adt {
         ast::Adt::Struct(it) => (
             it.name(),
             it.generic_param_list(),
+            it.where_clause(),
             AdtShape::Struct(VariantShape::from(tm, it.field_list())?),
         ),
         ast::Adt::Enum(it) => {
@@ -217,6 +219,7 @@ fn parse_adt(
             (
                 it.name(),
                 it.generic_param_list(),
+                it.where_clause(),
                 AdtShape::Enum {
                     default_variant,
                     variants: it
@@ -233,7 +236,9 @@ fn parse_adt(
                 },
             )
         }
-        ast::Adt::Union(it) => (it.name(), it.generic_param_list(), AdtShape::Union),
+        ast::Adt::Union(it) => {
+            (it.name(), it.generic_param_list(), it.where_clause(), AdtShape::Union)
+        }
     };
 
     let mut param_type_set: FxHashSet<Name> = FxHashSet::default();
@@ -274,6 +279,14 @@ fn parse_adt(
         })
         .collect();
 
+    let where_clause = if let Some(w) = where_clause {
+        w.predicates()
+            .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
+            .collect()
+    } else {
+        vec![]
+    };
+
     // For a generic parameter `T`, when shorthand associated type `T::Assoc` appears in field
     // types (of any variant for enums), we generate trait bound for it. It sounds reasonable to
     // also generate trait bound for qualified associated type `<T as Trait>::Assoc`, but rustc
@@ -301,7 +314,7 @@ fn parse_adt(
         .map(|it| mbe::syntax_node_to_token_tree(it.syntax(), tm, call_site))
         .collect();
     let name_token = name_to_token(tm, name)?;
-    Ok(BasicAdtInfo { name: name_token, shape, param_types, associated_types })
+    Ok(BasicAdtInfo { name: name_token, shape, param_types, where_clause, associated_types })
 }
 
 fn name_to_token(
@@ -366,7 +379,8 @@ fn expand_simple_derive(
         }
     };
     let trait_body = make_trait_body(&info);
-    let mut where_block = vec![];
+    let mut where_block: Vec<_> =
+        info.where_clause.into_iter().map(|w| quote! {invoc_span => #w , }).collect();
     let (params, args): (Vec<_>, Vec<_>) = info
         .param_types
         .into_iter()
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
index 29d389f656f..6d3de0e55d2 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs
@@ -155,10 +155,10 @@ fn line_expand(
     // not incremental
     ExpandResult::ok(tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(span),
-        token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+        token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
             text: "0u32".into(),
             span,
-        }))],
+        }))]),
     })
 }
 
@@ -208,11 +208,11 @@ fn assert_expand(
         [cond, panic_args @ ..] => {
             let comma = tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(call_site_span),
-                token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
+                token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct {
                     char: ',',
                     spacing: tt::Spacing::Alone,
                     span: call_site_span,
-                }))],
+                }))]),
             };
             let cond = cond.clone();
             let panic_args = itertools::Itertools::intersperse(panic_args.iter().cloned(), comma);
@@ -359,7 +359,10 @@ fn panic_expand(
         close: call_site_span,
         kind: tt::DelimiterKind::Parenthesis,
     };
-    call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+    // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+    call.push(tt::TokenTree::Subtree(subtree));
+
     ExpandResult::ok(call)
 }
 
@@ -388,7 +391,10 @@ fn unreachable_expand(
         close: call_site_span,
         kind: tt::DelimiterKind::Parenthesis,
     };
-    call.token_trees.push(tt::TokenTree::Subtree(subtree));
+
+    // FIXME(slow): quote! have a way to expand to builder to make this a vec!
+    call.push(tt::TokenTree::Subtree(subtree));
+
     ExpandResult::ok(call)
 }
 
@@ -509,7 +515,7 @@ fn concat_bytes_expand(
             tt::TokenTree::Leaf(tt::Leaf::Literal(lit)) => {
                 let token = ast::make::tokens::literal(&lit.to_string());
                 match token.kind() {
-                    syntax::SyntaxKind::BYTE => bytes.push(token.text().to_string()),
+                    syntax::SyntaxKind::BYTE => bytes.push(token.text().to_owned()),
                     syntax::SyntaxKind::BYTE_STRING => {
                         let components = unquote_byte_string(lit).unwrap_or_default();
                         components.into_iter().for_each(|it| bytes.push(it.to_string()));
@@ -564,7 +570,7 @@ fn concat_bytes_expand_subtree(
                 let lit = ast::make::tokens::literal(&lit.to_string());
                 match lit.kind() {
                     syntax::SyntaxKind::BYTE | syntax::SyntaxKind::INT_NUMBER => {
-                        bytes.push(lit.text().to_string())
+                        bytes.push(lit.text().to_owned())
                     }
                     _ => {
                         return Err(mbe::ExpandError::UnexpectedToken.into());
@@ -675,10 +681,10 @@ fn include_bytes_expand(
     // FIXME: actually read the file here if the user asked for macro expansion
     let res = tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(span),
-        token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
+        token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
             text: r#"b"""#.into(),
             span,
-        }))],
+        }))]),
     };
     ExpandResult::ok(res)
 }
@@ -743,7 +749,7 @@ fn env_expand(
         // We cannot use an empty string here, because for
         // `include!(concat!(env!("OUT_DIR"), "/foo.rs"))` will become
         // `include!("foo.rs"), which might go to infinite loop
-        "UNRESOLVED_ENV_VAR".to_string()
+        "UNRESOLVED_ENV_VAR".to_owned()
     });
     let expanded = quote! {span => #s };
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
index f220284fae7..6a288cf9197 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs
@@ -61,7 +61,7 @@ pub trait ExpandDatabase: SourceDatabase {
     #[salsa::input]
     fn proc_macros(&self) -> Arc<ProcMacros>;
 
-    #[salsa::invoke(AstIdMap::ast_id_map)]
+    #[salsa::invoke(AstIdMap::new)]
     fn ast_id_map(&self, file_id: HirFileId) -> Arc<AstIdMap>;
 
     /// Main public API -- parses a hir file, not caring whether it's a real
@@ -524,7 +524,7 @@ fn macro_expand(
                 return ExpandResult {
                     value: CowArc::Owned(tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                        token_trees: Vec::new(),
+                        token_trees: Box::new([]),
                     }),
                     // FIXME: We should make sure to enforce an invariant that invalid macro
                     // calls do not reach this call path!
@@ -586,7 +586,7 @@ fn macro_expand(
             return value.map(|()| {
                 CowArc::Owned(tt::Subtree {
                     delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                    token_trees: vec![],
+                    token_trees: Box::new([]),
                 })
             });
         }
@@ -601,7 +601,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
         return ExpandResult {
             value: Arc::new(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                token_trees: Vec::new(),
+                token_trees: Box::new([]),
             }),
             // FIXME: We should make sure to enforce an invariant that invalid macro
             // calls do not reach this call path!
@@ -635,7 +635,7 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult<A
         return value.map(|()| {
             Arc::new(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                token_trees: vec![],
+                token_trees: Box::new([]),
             })
         });
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index 492501f5b6e..a3b2c700ffe 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -312,7 +312,7 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo)
 }
 
 fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
-    let tts = std::mem::take(&mut tt.token_trees);
+    let tts = std::mem::take(&mut tt.token_trees).into_vec();
     tt.token_trees = tts
         .into_iter()
         // delete all fake nodes
@@ -343,7 +343,7 @@ fn reverse_fixups_(tt: &mut Subtree, undo_info: &[Subtree]) {
                     // we have a fake node here, we need to replace it again with the original
                     let original = undo_info[u32::from(leaf.span().range.start()) as usize].clone();
                     if original.delimiter.kind == tt::DelimiterKind::Invisible {
-                        original.token_trees.into()
+                        SmallVec::from(original.token_trees.into_vec())
                     } else {
                         SmallVec::from_const([original.into()])
                     }
@@ -383,7 +383,7 @@ mod tests {
     fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
         a.delimiter.kind == b.delimiter.kind
             && a.token_trees.len() == b.token_trees.len()
-            && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
+            && a.token_trees.iter().zip(b.token_trees.iter()).all(|(a, b)| check_tt_eq(a, b))
     }
 
     fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
index 8ddaa3f3039..65b834d7a81 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs
@@ -7,9 +7,10 @@
 
 use std::iter;
 
+use base_db::salsa::{self, InternValue};
 use span::{MacroCallId, Span, SyntaxContextId};
 
-use crate::db::ExpandDatabase;
+use crate::db::{ExpandDatabase, InternSyntaxContextQuery};
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq)]
 pub struct SyntaxContextData {
@@ -22,6 +23,14 @@ pub struct SyntaxContextData {
     pub opaque_and_semitransparent: SyntaxContextId,
 }
 
+impl InternValue for SyntaxContextData {
+    type Key = (SyntaxContextId, Option<MacroCallId>, Transparency);
+
+    fn into_key(&self) -> Self::Key {
+        (self.parent, self.outer_expn, self.outer_transparency)
+    }
+}
+
 impl std::fmt::Debug for SyntaxContextData {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         f.debug_struct("SyntaxContextData")
@@ -149,38 +158,36 @@ fn apply_mark_internal(
     transparency: Transparency,
 ) -> SyntaxContextId {
     let syntax_context_data = db.lookup_intern_syntax_context(ctxt);
-    let mut opaque = handle_self_ref(ctxt, syntax_context_data.opaque);
-    let mut opaque_and_semitransparent =
-        handle_self_ref(ctxt, syntax_context_data.opaque_and_semitransparent);
+    let mut opaque = syntax_context_data.opaque;
+    let mut opaque_and_semitransparent = syntax_context_data.opaque_and_semitransparent;
 
     if transparency >= Transparency::Opaque {
         let parent = opaque;
-        // Unlike rustc, with salsa we can't prefetch the to be allocated ID to create cycles with
-        // salsa when interning, so we use a sentinel value that effectively means the current
-        // syntax context.
-        let new_opaque = SyntaxContextId::SELF_REF;
-        opaque = db.intern_syntax_context(SyntaxContextData {
-            outer_expn: call_id,
-            outer_transparency: transparency,
-            parent,
-            opaque: new_opaque,
-            opaque_and_semitransparent: new_opaque,
-        });
+        opaque = salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert(
+            (parent, call_id, transparency),
+            |new_opaque| SyntaxContextData {
+                outer_expn: call_id,
+                outer_transparency: transparency,
+                parent,
+                opaque: new_opaque,
+                opaque_and_semitransparent: new_opaque,
+            },
+        );
     }
 
     if transparency >= Transparency::SemiTransparent {
         let parent = opaque_and_semitransparent;
-        // Unlike rustc, with salsa we can't prefetch the to be allocated ID to create cycles with
-        // salsa when interning, so we use a sentinel value that effectively means the current
-        // syntax context.
-        let new_opaque_and_semitransparent = SyntaxContextId::SELF_REF;
-        opaque_and_semitransparent = db.intern_syntax_context(SyntaxContextData {
-            outer_expn: call_id,
-            outer_transparency: transparency,
-            parent,
-            opaque,
-            opaque_and_semitransparent: new_opaque_and_semitransparent,
-        });
+        opaque_and_semitransparent =
+            salsa::plumbing::get_query_table::<InternSyntaxContextQuery>(db).get_or_insert(
+                (parent, call_id, transparency),
+                |new_opaque_and_semitransparent| SyntaxContextData {
+                    outer_expn: call_id,
+                    outer_transparency: transparency,
+                    parent,
+                    opaque,
+                    opaque_and_semitransparent: new_opaque_and_semitransparent,
+                },
+            );
     }
 
     let parent = ctxt;
@@ -201,20 +208,12 @@ pub trait SyntaxContextExt {
     fn marks(self, db: &dyn ExpandDatabase) -> Vec<(Option<MacroCallId>, Transparency)>;
 }
 
-#[inline(always)]
-fn handle_self_ref(p: SyntaxContextId, n: SyntaxContextId) -> SyntaxContextId {
-    match n {
-        SyntaxContextId::SELF_REF => p,
-        _ => n,
-    }
-}
-
 impl SyntaxContextExt for SyntaxContextId {
     fn normalize_to_macro_rules(self, db: &dyn ExpandDatabase) -> Self {
-        handle_self_ref(self, db.lookup_intern_syntax_context(self).opaque_and_semitransparent)
+        db.lookup_intern_syntax_context(self).opaque_and_semitransparent
     }
     fn normalize_to_macros_2_0(self, db: &dyn ExpandDatabase) -> Self {
-        handle_self_ref(self, db.lookup_intern_syntax_context(self).opaque)
+        db.lookup_intern_syntax_context(self).opaque
     }
     fn parent_ctxt(self, db: &dyn ExpandDatabase) -> Self {
         db.lookup_intern_syntax_context(self).parent
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index bd250524903..fd028182faf 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -30,7 +30,7 @@ use triomphe::Arc;
 
 use std::{fmt, hash::Hash};
 
-use base_db::{CrateId, Edition, FileId};
+use base_db::{salsa::impl_intern_value_trivial, CrateId, Edition, FileId};
 use either::Either;
 use span::{FileRange, HirFileIdRepr, Span, SyntaxContextId};
 use syntax::{
@@ -66,6 +66,7 @@ pub mod tt {
     pub type Delimiter = ::tt::Delimiter<Span>;
     pub type DelimSpan = ::tt::DelimSpan<Span>;
     pub type Subtree = ::tt::Subtree<Span>;
+    pub type SubtreeBuilder = ::tt::SubtreeBuilder<Span>;
     pub type Leaf = ::tt::Leaf<Span>;
     pub type Literal = ::tt::Literal<Span>;
     pub type Punct = ::tt::Punct<Span>;
@@ -175,6 +176,7 @@ pub struct MacroCallLoc {
     pub kind: MacroCallKind,
     pub call_site: Span,
 }
+impl_intern_value_trivial!(MacroCallLoc);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct MacroDefId {
@@ -760,7 +762,7 @@ impl ExpansionInfo {
             (
                 Arc::new(tt::Subtree {
                     delimiter: tt::Delimiter::invisible_spanned(loc.call_site),
-                    token_trees: Vec::new(),
+                    token_trees: Box::new([]),
                 }),
                 SyntaxFixupUndoInfo::NONE,
             )
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
index 824f3c3e8f2..c1930c94f5c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs
@@ -31,7 +31,7 @@ macro_rules! __quote {
                     open: $span,
                     close: $span,
                 },
-                token_trees: $crate::quote::IntoTt::to_tokens(children),
+                token_trees: $crate::quote::IntoTt::to_tokens(children).into_boxed_slice(),
             }
         }
     };
@@ -146,7 +146,7 @@ impl IntoTt for Vec<crate::tt::TokenTree> {
     fn to_subtree(self, span: Span) -> crate::tt::Subtree {
         crate::tt::Subtree {
             delimiter: crate::tt::Delimiter::invisible_spanned(span),
-            token_trees: self,
+            token_trees: self.into_boxed_slice(),
         }
     }
 
@@ -296,8 +296,9 @@ mod tests {
         // }
         let struct_name = mk_ident("Foo");
         let fields = [mk_ident("name"), mk_ident("id")];
-        let fields =
-            fields.iter().flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees);
+        let fields = fields
+            .iter()
+            .flat_map(|it| quote!(DUMMY =>#it: self.#it.clone(), ).token_trees.into_vec());
 
         let list = crate::tt::Subtree {
             delimiter: crate::tt::Delimiter {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
index 991fd2f91df..8d819e41aa2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -88,6 +88,7 @@ impl<'a, 'db> Autoderef<'a, 'db> {
 impl Iterator for Autoderef<'_, '_> {
     type Item = (Ty, usize);
 
+    #[tracing::instrument(skip_all)]
     fn next(&mut self) -> Option<Self::Item> {
         if self.at_start {
             self.at_start = false;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
index 24a7eb3ff0a..c485c9b2e80 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs
@@ -125,6 +125,7 @@ impl<D> TyBuilder<D> {
         this
     }
 
+    #[tracing::instrument(skip_all)]
     pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable<'_>) -> Self {
         self.fill(|x| match x {
             ParamKind::Type => table.new_type_var().cast(Interner),
@@ -208,6 +209,7 @@ impl TyBuilder<()> {
         )
     }
 
+    #[tracing::instrument(skip_all)]
     pub fn subst_for_def(
         db: &dyn HirDatabase,
         def: impl Into<GenericDefId>,
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 7e460f9f867..bd243518fc6 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
@@ -17,7 +17,7 @@ use hir_def::{
 use hir_expand::name::name;
 
 use crate::{
-    db::HirDatabase,
+    db::{HirDatabase, InternedCoroutine},
     display::HirDisplay,
     from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
     make_single_type_binders,
@@ -428,7 +428,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
         &self,
         id: chalk_ir::CoroutineId<Interner>,
     ) -> Arc<chalk_solve::rust_ir::CoroutineDatum<Interner>> {
-        let (parent, expr) = self.db.lookup_intern_coroutine(id.into());
+        let InternedCoroutine(parent, expr) = self.db.lookup_intern_coroutine(id.into());
 
         // We fill substitution with unknown type, because we only need to know whether the generic
         // params are types or consts to build `Binders` and those being filled up are for
@@ -473,7 +473,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
         let inner_types =
             rust_ir::CoroutineWitnessExistential { types: wrap_empty_binders(vec![]) };
 
-        let (parent, _) = self.db.lookup_intern_coroutine(id.into());
+        let InternedCoroutine(parent, _) = self.db.lookup_intern_coroutine(id.into());
         // See the comment in `coroutine_datum()` for unknown types.
         let subst = TyBuilder::subst_for_coroutine(self.db, parent).fill_with_unknown().build();
         let it = subst
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
index ac82208708a..98384c47490 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs
@@ -133,7 +133,7 @@ fn bit_op() {
     check_number(r#"const GOAL: i8 = 1 << 7"#, (1i8 << 7) as i128);
     check_number(r#"const GOAL: i8 = -1 << 2"#, (-1i8 << 2) as i128);
     check_fail(r#"const GOAL: i8 = 1 << 8"#, |e| {
-        e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_string()))
+        e == ConstEvalError::MirEvalError(MirEvalError::Panic("Overflow in Shl".to_owned()))
     });
     check_number(r#"const GOAL: i32 = 100000000i32 << 11"#, (100000000i32 << 11) as i128);
 }
@@ -2756,7 +2756,7 @@ fn memory_limit() {
         "#,
         |e| {
             e == ConstEvalError::MirEvalError(MirEvalError::Panic(
-                "Memory allocation of 30000000000 bytes failed".to_string(),
+                "Memory allocation of 30000000000 bytes failed".to_owned(),
             ))
         },
     );
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
index 21679150b34..fbd366864a4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs
@@ -3,7 +3,11 @@
 
 use std::sync;
 
-use base_db::{impl_intern_key, salsa, CrateId, Upcast};
+use base_db::{
+    impl_intern_key,
+    salsa::{self, impl_intern_value_trivial},
+    CrateId, Upcast,
+};
 use hir_def::{
     db::DefDatabase, hir::ExprId, layout::TargetDataLayout, AdtId, BlockId, ConstParamId,
     DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId,
@@ -199,9 +203,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::interned]
     fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
     #[salsa::interned]
-    fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
+    fn intern_closure(&self, id: InternedClosure) -> InternedClosureId;
     #[salsa::interned]
-    fn intern_coroutine(&self, id: (DefWithBodyId, ExprId)) -> InternedCoroutineId;
+    fn intern_coroutine(&self, id: InternedCoroutine) -> InternedCoroutineId;
 
     #[salsa::invoke(chalk_db::associated_ty_data_query)]
     fn associated_ty_data(
@@ -338,9 +342,17 @@ pub struct InternedClosureId(salsa::InternId);
 impl_intern_key!(InternedClosureId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct InternedClosure(pub DefWithBodyId, pub ExprId);
+impl_intern_value_trivial!(InternedClosure);
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedCoroutineId(salsa::InternId);
 impl_intern_key!(InternedCoroutineId);
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId);
+impl_intern_value_trivial!(InternedCoroutine);
+
 /// This exists just for Chalk, because Chalk just has a single `FnDefId` where
 /// we have different IDs for struct and enum variant constructors.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
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 78f2005e676..38eb3371e3c 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
@@ -16,11 +16,9 @@ mod case_conv;
 use std::fmt;
 
 use hir_def::{
-    data::adt::VariantData,
-    hir::{Pat, PatId},
-    src::HasSource,
-    AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId,
-    StaticId, StructId,
+    data::adt::VariantData, db::DefDatabase, hir::Pat, src::HasSource, AdtId, AttrDefId, ConstId,
+    EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, ModuleId, StaticId, StructId,
+    TraitId, TypeAliasId,
 };
 use hir_expand::{
     name::{AsName, Name},
@@ -79,12 +77,14 @@ pub enum IdentType {
     Enum,
     Field,
     Function,
+    Module,
     Parameter,
     StaticVariable,
     Structure,
+    Trait,
+    TypeAlias,
     Variable,
     Variant,
-    Module,
 }
 
 impl fmt::Display for IdentType {
@@ -94,12 +94,14 @@ impl fmt::Display for IdentType {
             IdentType::Enum => "Enum",
             IdentType::Field => "Field",
             IdentType::Function => "Function",
+            IdentType::Module => "Module",
             IdentType::Parameter => "Parameter",
             IdentType::StaticVariable => "Static variable",
             IdentType::Structure => "Structure",
+            IdentType::Trait => "Trait",
+            IdentType::TypeAlias => "Type alias",
             IdentType::Variable => "Variable",
             IdentType::Variant => "Variant",
-            IdentType::Module => "Module",
         };
 
         repr.fmt(f)
@@ -136,10 +138,12 @@ impl<'a> DeclValidator<'a> {
     pub(super) fn validate_item(&mut self, item: ModuleDefId) {
         match item {
             ModuleDefId::ModuleId(module_id) => self.validate_module(module_id),
+            ModuleDefId::TraitId(trait_id) => self.validate_trait(trait_id),
             ModuleDefId::FunctionId(func) => self.validate_func(func),
             ModuleDefId::AdtId(adt) => self.validate_adt(adt),
             ModuleDefId::ConstId(const_id) => self.validate_const(const_id),
             ModuleDefId::StaticId(static_id) => self.validate_static(static_id),
+            ModuleDefId::TypeAliasId(type_alias_id) => self.validate_type_alias(type_alias_id),
             _ => (),
         }
     }
@@ -242,50 +246,46 @@ impl<'a> DeclValidator<'a> {
 
         // Check the module name.
         let Some(module_name) = module_id.name(self.db.upcast()) else { return };
-        let module_name_replacement =
+        let Some(module_name_replacement) =
             module_name.as_str().and_then(to_lower_snake_case).map(|new_name| Replacement {
                 current_name: module_name,
                 suggested_text: new_name,
                 expected_case: CaseType::LowerSnakeCase,
-            });
-
-        if let Some(module_name_replacement) = module_name_replacement {
-            let module_data = &module_id.def_map(self.db.upcast())[module_id.local_id];
-            let module_src = module_data.declaration_source(self.db.upcast());
-
-            if let Some(module_src) = module_src {
-                let ast_ptr = match module_src.value.name() {
-                    Some(name) => name,
-                    None => {
-                        never!(
-                            "Replacement ({:?}) was generated for a module without a name: {:?}",
-                            module_name_replacement,
-                            module_src
-                        );
-                        return;
-                    }
-                };
-
-                let diagnostic = IncorrectCase {
-                    file: module_src.file_id,
-                    ident_type: IdentType::Module,
-                    ident: AstPtr::new(&ast_ptr),
-                    expected_case: module_name_replacement.expected_case,
-                    ident_text: module_name_replacement
-                        .current_name
-                        .display(self.db.upcast())
-                        .to_string(),
-                    suggested_text: module_name_replacement.suggested_text,
-                };
-
-                self.sink.push(diagnostic);
-            }
+            })
+        else {
+            return;
+        };
+        let module_data = &module_id.def_map(self.db.upcast())[module_id.local_id];
+        let Some(module_src) = module_data.declaration_source(self.db.upcast()) else {
+            return;
+        };
+        self.create_incorrect_case_diagnostic_for_ast_node(
+            module_name_replacement,
+            module_src.file_id,
+            &module_src.value,
+            IdentType::Module,
+        );
+    }
+
+    fn validate_trait(&mut self, trait_id: TraitId) {
+        // Check whether non-snake case identifiers are allowed for this trait.
+        if self.allowed(trait_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
+            return;
         }
+
+        // Check the trait name.
+        let data = self.db.trait_data(trait_id);
+        self.create_incorrect_case_diagnostic_for_item_name(
+            trait_id,
+            &data.name,
+            CaseType::UpperCamelCase,
+            IdentType::Trait,
+        );
     }
 
     fn validate_func(&mut self, func: FunctionId) {
-        let data = self.db.function_data(func);
-        if matches!(func.lookup(self.db.upcast()).container, ItemContainerId::ExternBlockId(_)) {
+        let container = func.lookup(self.db.upcast()).container;
+        if matches!(container, ItemContainerId::ExternBlockId(_)) {
             cov_mark::hit!(extern_func_incorrect_case_ignored);
             return;
         }
@@ -296,270 +296,173 @@ impl<'a> DeclValidator<'a> {
         }
 
         // Check the function name.
-        let function_name = data.name.display(self.db.upcast()).to_string();
-        let fn_name_replacement = to_lower_snake_case(&function_name).map(|new_name| Replacement {
-            current_name: data.name.clone(),
-            suggested_text: new_name,
-            expected_case: CaseType::LowerSnakeCase,
-        });
-
-        let body = self.db.body(func.into());
+        // Skipped if function is an associated item of a trait implementation.
+        if !self.is_trait_impl_container(container) {
+            let data = self.db.function_data(func);
+            self.create_incorrect_case_diagnostic_for_item_name(
+                func,
+                &data.name,
+                CaseType::LowerSnakeCase,
+                IdentType::Function,
+            );
+        } else {
+            cov_mark::hit!(trait_impl_assoc_func_name_incorrect_case_ignored);
+        }
 
         // Check the patterns inside the function body.
-        // This includes function parameters.
-        let pats_replacements = body
+        self.validate_func_body(func);
+    }
+
+    /// Check incorrect names for patterns inside the function body.
+    /// This includes function parameters except for trait implementation associated functions.
+    fn validate_func_body(&mut self, func: FunctionId) {
+        let body = self.db.body(func.into());
+        let mut pats_replacements = body
             .pats
             .iter()
             .filter_map(|(pat_id, pat)| match pat {
-                Pat::Bind { id, .. } => Some((pat_id, &body.bindings[*id].name)),
-                _ => None,
-            })
-            .filter_map(|(id, bind_name)| {
-                Some((
-                    id,
-                    Replacement {
+                Pat::Bind { id, .. } => {
+                    let bind_name = &body.bindings[*id].name;
+                    let replacement = Replacement {
                         current_name: bind_name.clone(),
-                        suggested_text: to_lower_snake_case(
-                            &bind_name.display(self.db.upcast()).to_string(),
-                        )?,
+                        suggested_text: to_lower_snake_case(&bind_name.to_smol_str())?,
                         expected_case: CaseType::LowerSnakeCase,
-                    },
-                ))
+                    };
+                    Some((pat_id, replacement))
+                }
+                _ => None,
             })
-            .collect();
+            .peekable();
 
-        // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
-        if let Some(fn_name_replacement) = fn_name_replacement {
-            self.create_incorrect_case_diagnostic_for_func(func, fn_name_replacement);
-        }
-
-        self.create_incorrect_case_diagnostic_for_variables(func, pats_replacements);
-    }
-
-    /// Given the information about incorrect names in the function declaration, looks up into the source code
-    /// for exact locations and adds diagnostics into the sink.
-    fn create_incorrect_case_diagnostic_for_func(
-        &mut self,
-        func: FunctionId,
-        fn_name_replacement: Replacement,
-    ) {
-        let fn_loc = func.lookup(self.db.upcast());
-        let fn_src = fn_loc.source(self.db.upcast());
-
-        // Diagnostic for function name.
-        let ast_ptr = match fn_src.value.name() {
-            Some(name) => name,
-            None => {
-                never!(
-                    "Replacement ({:?}) was generated for a function without a name: {:?}",
-                    fn_name_replacement,
-                    fn_src
-                );
-                return;
-            }
-        };
-
-        let diagnostic = IncorrectCase {
-            file: fn_src.file_id,
-            ident_type: IdentType::Function,
-            ident: AstPtr::new(&ast_ptr),
-            expected_case: fn_name_replacement.expected_case,
-            ident_text: fn_name_replacement.current_name.display(self.db.upcast()).to_string(),
-            suggested_text: fn_name_replacement.suggested_text,
-        };
-
-        self.sink.push(diagnostic);
-    }
-
-    /// Given the information about incorrect variable names, looks up into the source code
-    /// for exact locations and adds diagnostics into the sink.
-    fn create_incorrect_case_diagnostic_for_variables(
-        &mut self,
-        func: FunctionId,
-        pats_replacements: Vec<(PatId, Replacement)>,
-    ) {
         // XXX: only look at source_map if we do have missing fields
-        if pats_replacements.is_empty() {
+        if pats_replacements.peek().is_none() {
             return;
         }
 
         let (_, source_map) = self.db.body_with_source_map(func.into());
-
         for (id, replacement) in pats_replacements {
-            if let Ok(source_ptr) = source_map.pat_syntax(id) {
-                if let Some(ptr) = source_ptr.value.cast::<ast::IdentPat>() {
-                    let root = source_ptr.file_syntax(self.db.upcast());
-                    let ident_pat = ptr.to_node(&root);
-                    let parent = match ident_pat.syntax().parent() {
-                        Some(parent) => parent,
-                        None => continue,
-                    };
-                    let name_ast = match ident_pat.name() {
-                        Some(name_ast) => name_ast,
-                        None => continue,
-                    };
-
-                    let is_param = ast::Param::can_cast(parent.kind());
-
-                    // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
-                    // because e.g. match arms are patterns as well.
-                    // In other words, we check that it's a named variable binding.
-                    let is_binding = ast::LetStmt::can_cast(parent.kind())
-                        || (ast::MatchArm::can_cast(parent.kind())
-                            && ident_pat.at_token().is_some());
-                    if !(is_param || is_binding) {
-                        // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
-                        continue;
-                    }
+            let Ok(source_ptr) = source_map.pat_syntax(id) else {
+                continue;
+            };
+            let Some(ptr) = source_ptr.value.cast::<ast::IdentPat>() else {
+                continue;
+            };
+            let root = source_ptr.file_syntax(self.db.upcast());
+            let ident_pat = ptr.to_node(&root);
+            let Some(parent) = ident_pat.syntax().parent() else {
+                continue;
+            };
 
-                    let ident_type =
-                        if is_param { IdentType::Parameter } else { IdentType::Variable };
+            let is_param = ast::Param::can_cast(parent.kind());
+            // We have to check that it's either `let var = ...` or `var @ Variant(_)` statement,
+            // because e.g. match arms are patterns as well.
+            // In other words, we check that it's a named variable binding.
+            let is_binding = ast::LetStmt::can_cast(parent.kind())
+                || (ast::MatchArm::can_cast(parent.kind()) && ident_pat.at_token().is_some());
+            if !(is_param || is_binding) {
+                // This pattern is not an actual variable declaration, e.g. `Some(val) => {..}` match arm.
+                continue;
+            }
 
-                    let diagnostic = IncorrectCase {
-                        file: source_ptr.file_id,
-                        ident_type,
-                        ident: AstPtr::new(&name_ast),
-                        expected_case: replacement.expected_case,
-                        ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
-                        suggested_text: replacement.suggested_text,
-                    };
+            let ident_type = if is_param { IdentType::Parameter } else { IdentType::Variable };
 
-                    self.sink.push(diagnostic);
-                }
-            }
+            self.create_incorrect_case_diagnostic_for_ast_node(
+                replacement,
+                source_ptr.file_id,
+                &ident_pat,
+                ident_type,
+            );
         }
     }
 
     fn validate_struct(&mut self, struct_id: StructId) {
-        let data = self.db.struct_data(struct_id);
-
+        // Check the structure name.
         let non_camel_case_allowed =
             self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false);
-        let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false);
-
-        // Check the structure name.
-        let struct_name = data.name.display(self.db.upcast()).to_string();
-        let struct_name_replacement = if !non_camel_case_allowed {
-            to_camel_case(&struct_name).map(|new_name| Replacement {
-                current_name: data.name.clone(),
-                suggested_text: new_name,
-                expected_case: CaseType::UpperCamelCase,
-            })
-        } else {
-            None
-        };
+        if !non_camel_case_allowed {
+            let data = self.db.struct_data(struct_id);
+            self.create_incorrect_case_diagnostic_for_item_name(
+                struct_id,
+                &data.name,
+                CaseType::UpperCamelCase,
+                IdentType::Structure,
+            );
+        }
 
         // Check the field names.
-        let mut struct_fields_replacements = Vec::new();
-
-        if !non_snake_case_allowed {
-            if let VariantData::Record(fields) = data.variant_data.as_ref() {
-                for (_, field) in fields.iter() {
-                    let field_name = field.name.display(self.db.upcast()).to_string();
-                    if let Some(new_name) = to_lower_snake_case(&field_name) {
-                        let replacement = Replacement {
-                            current_name: field.name.clone(),
-                            suggested_text: new_name,
-                            expected_case: CaseType::LowerSnakeCase,
-                        };
-                        struct_fields_replacements.push(replacement);
-                    }
-                }
-            }
+        self.validate_struct_fields(struct_id);
+    }
+
+    /// Check incorrect names for struct fields.
+    fn validate_struct_fields(&mut self, struct_id: StructId) {
+        if self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false) {
+            return;
         }
 
-        // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
-        self.create_incorrect_case_diagnostic_for_struct(
-            struct_id,
-            struct_name_replacement,
-            struct_fields_replacements,
-        );
-    }
+        let data = self.db.struct_data(struct_id);
+        let VariantData::Record(fields) = data.variant_data.as_ref() else {
+            return;
+        };
+        let mut struct_fields_replacements = fields
+            .iter()
+            .filter_map(|(_, field)| {
+                to_lower_snake_case(&field.name.to_smol_str()).map(|new_name| Replacement {
+                    current_name: field.name.clone(),
+                    suggested_text: new_name,
+                    expected_case: CaseType::LowerSnakeCase,
+                })
+            })
+            .peekable();
 
-    /// Given the information about incorrect names in the struct declaration, looks up into the source code
-    /// for exact locations and adds diagnostics into the sink.
-    fn create_incorrect_case_diagnostic_for_struct(
-        &mut self,
-        struct_id: StructId,
-        struct_name_replacement: Option<Replacement>,
-        struct_fields_replacements: Vec<Replacement>,
-    ) {
         // XXX: Only look at sources if we do have incorrect names.
-        if struct_name_replacement.is_none() && struct_fields_replacements.is_empty() {
+        if struct_fields_replacements.peek().is_none() {
             return;
         }
 
         let struct_loc = struct_id.lookup(self.db.upcast());
         let struct_src = struct_loc.source(self.db.upcast());
 
-        if let Some(replacement) = struct_name_replacement {
-            let ast_ptr = match struct_src.value.name() {
-                Some(name) => name,
-                None => {
-                    never!(
-                        "Replacement ({:?}) was generated for a structure without a name: {:?}",
-                        replacement,
-                        struct_src
-                    );
-                    return;
-                }
-            };
-
-            let diagnostic = IncorrectCase {
-                file: struct_src.file_id,
-                ident_type: IdentType::Structure,
-                ident: AstPtr::new(&ast_ptr),
-                expected_case: replacement.expected_case,
-                ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
-                suggested_text: replacement.suggested_text,
-            };
-
-            self.sink.push(diagnostic);
-        }
-
-        let struct_fields_list = match struct_src.value.field_list() {
-            Some(ast::FieldList::RecordFieldList(fields)) => fields,
-            _ => {
-                always!(
-                    struct_fields_replacements.is_empty(),
-                    "Replacements ({:?}) were generated for a structure fields which had no fields list: {:?}",
-                    struct_fields_replacements,
-                    struct_src
-                );
-                return;
-            }
+        let Some(ast::FieldList::RecordFieldList(struct_fields_list)) =
+            struct_src.value.field_list()
+        else {
+            always!(
+                struct_fields_replacements.peek().is_none(),
+                "Replacements ({:?}) were generated for a structure fields \
+                which had no fields list: {:?}",
+                struct_fields_replacements.collect::<Vec<_>>(),
+                struct_src
+            );
+            return;
         };
         let mut struct_fields_iter = struct_fields_list.fields();
-        for field_to_rename in struct_fields_replacements {
+        for field_replacement in struct_fields_replacements {
             // We assume that parameters in replacement are in the same order as in the
             // actual params list, but just some of them (ones that named correctly) are skipped.
-            let ast_ptr = loop {
-                match struct_fields_iter.next().and_then(|field| field.name()) {
-                    Some(field_name) => {
-                        if field_name.as_name() == field_to_rename.current_name {
-                            break field_name;
-                        }
-                    }
-                    None => {
-                        never!(
-                            "Replacement ({:?}) was generated for a structure field which was not found: {:?}",
-                            field_to_rename, struct_src
-                        );
-                        return;
+            let field = loop {
+                if let Some(field) = struct_fields_iter.next() {
+                    let Some(field_name) = field.name() else {
+                        continue;
+                    };
+                    if field_name.as_name() == field_replacement.current_name {
+                        break field;
                     }
+                } else {
+                    never!(
+                        "Replacement ({:?}) was generated for a structure field \
+                        which was not found: {:?}",
+                        field_replacement,
+                        struct_src
+                    );
+                    return;
                 }
             };
 
-            let diagnostic = IncorrectCase {
-                file: struct_src.file_id,
-                ident_type: IdentType::Field,
-                ident: AstPtr::new(&ast_ptr),
-                expected_case: field_to_rename.expected_case,
-                ident_text: field_to_rename.current_name.display(self.db.upcast()).to_string(),
-                suggested_text: field_to_rename.suggested_text,
-            };
-
-            self.sink.push(diagnostic);
+            self.create_incorrect_case_diagnostic_for_ast_node(
+                field_replacement,
+                struct_src.file_id,
+                &field,
+                IdentType::Field,
+            );
         }
     }
 
@@ -572,163 +475,103 @@ impl<'a> DeclValidator<'a> {
         }
 
         // Check the enum name.
-        let enum_name = data.name.display(self.db.upcast()).to_string();
-        let enum_name_replacement = to_camel_case(&enum_name).map(|new_name| Replacement {
-            current_name: data.name.clone(),
-            suggested_text: new_name,
-            expected_case: CaseType::UpperCamelCase,
-        });
+        self.create_incorrect_case_diagnostic_for_item_name(
+            enum_id,
+            &data.name,
+            CaseType::UpperCamelCase,
+            IdentType::Enum,
+        );
 
-        // Check the field names.
-        let enum_fields_replacements = data
+        // Check the variant names.
+        self.validate_enum_variants(enum_id)
+    }
+
+    /// Check incorrect names for enum variants.
+    fn validate_enum_variants(&mut self, enum_id: EnumId) {
+        let data = self.db.enum_data(enum_id);
+        let mut enum_variants_replacements = data
             .variants
             .iter()
             .filter_map(|(_, name)| {
-                Some(Replacement {
+                to_camel_case(&name.to_smol_str()).map(|new_name| Replacement {
                     current_name: name.clone(),
-                    suggested_text: to_camel_case(&name.to_smol_str())?,
+                    suggested_text: new_name,
                     expected_case: CaseType::UpperCamelCase,
                 })
             })
-            .collect();
-
-        // If there is at least one element to spawn a warning on, go to the source map and generate a warning.
-        self.create_incorrect_case_diagnostic_for_enum(
-            enum_id,
-            enum_name_replacement,
-            enum_fields_replacements,
-        )
-    }
+            .peekable();
 
-    /// Given the information about incorrect names in the struct declaration, looks up into the source code
-    /// for exact locations and adds diagnostics into the sink.
-    fn create_incorrect_case_diagnostic_for_enum(
-        &mut self,
-        enum_id: EnumId,
-        enum_name_replacement: Option<Replacement>,
-        enum_variants_replacements: Vec<Replacement>,
-    ) {
         // XXX: only look at sources if we do have incorrect names
-        if enum_name_replacement.is_none() && enum_variants_replacements.is_empty() {
+        if enum_variants_replacements.peek().is_none() {
             return;
         }
 
         let enum_loc = enum_id.lookup(self.db.upcast());
         let enum_src = enum_loc.source(self.db.upcast());
 
-        if let Some(replacement) = enum_name_replacement {
-            let ast_ptr = match enum_src.value.name() {
-                Some(name) => name,
-                None => {
-                    never!(
-                        "Replacement ({:?}) was generated for a enum without a name: {:?}",
-                        replacement,
-                        enum_src
-                    );
-                    return;
-                }
-            };
-
-            let diagnostic = IncorrectCase {
-                file: enum_src.file_id,
-                ident_type: IdentType::Enum,
-                ident: AstPtr::new(&ast_ptr),
-                expected_case: replacement.expected_case,
-                ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
-                suggested_text: replacement.suggested_text,
-            };
-
-            self.sink.push(diagnostic);
-        }
-
-        let enum_variants_list = match enum_src.value.variant_list() {
-            Some(variants) => variants,
-            _ => {
-                always!(
-                    enum_variants_replacements.is_empty(),
-                    "Replacements ({:?}) were generated for a enum variants which had no fields list: {:?}",
-                    enum_variants_replacements,
-                    enum_src
-                );
-                return;
-            }
+        let Some(enum_variants_list) = enum_src.value.variant_list() else {
+            always!(
+                enum_variants_replacements.peek().is_none(),
+                "Replacements ({:?}) were generated for enum variants \
+                which had no fields list: {:?}",
+                enum_variants_replacements,
+                enum_src
+            );
+            return;
         };
         let mut enum_variants_iter = enum_variants_list.variants();
-        for variant_to_rename in enum_variants_replacements {
+        for variant_replacement in enum_variants_replacements {
             // We assume that parameters in replacement are in the same order as in the
             // actual params list, but just some of them (ones that named correctly) are skipped.
-            let ast_ptr = loop {
-                match enum_variants_iter.next().and_then(|v| v.name()) {
-                    Some(variant_name) => {
-                        if variant_name.as_name() == variant_to_rename.current_name {
-                            break variant_name;
-                        }
-                    }
-                    None => {
-                        never!(
-                            "Replacement ({:?}) was generated for a enum variant which was not found: {:?}",
-                            variant_to_rename, enum_src
-                        );
-                        return;
+            let variant = loop {
+                if let Some(variant) = enum_variants_iter.next() {
+                    let Some(variant_name) = variant.name() else {
+                        continue;
+                    };
+                    if variant_name.as_name() == variant_replacement.current_name {
+                        break variant;
                     }
+                } else {
+                    never!(
+                        "Replacement ({:?}) was generated for an enum variant \
+                        which was not found: {:?}",
+                        variant_replacement,
+                        enum_src
+                    );
+                    return;
                 }
             };
 
-            let diagnostic = IncorrectCase {
-                file: enum_src.file_id,
-                ident_type: IdentType::Variant,
-                ident: AstPtr::new(&ast_ptr),
-                expected_case: variant_to_rename.expected_case,
-                ident_text: variant_to_rename.current_name.display(self.db.upcast()).to_string(),
-                suggested_text: variant_to_rename.suggested_text,
-            };
-
-            self.sink.push(diagnostic);
+            self.create_incorrect_case_diagnostic_for_ast_node(
+                variant_replacement,
+                enum_src.file_id,
+                &variant,
+                IdentType::Variant,
+            );
         }
     }
 
     fn validate_const(&mut self, const_id: ConstId) {
-        let data = self.db.const_data(const_id);
+        let container = const_id.lookup(self.db.upcast()).container;
+        if self.is_trait_impl_container(container) {
+            cov_mark::hit!(trait_impl_assoc_const_incorrect_case_ignored);
+            return;
+        }
 
         if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
             return;
         }
 
-        let name = match &data.name {
-            Some(name) => name,
-            None => return,
-        };
-
-        let const_name = name.to_smol_str();
-        let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) {
-            Replacement {
-                current_name: name.clone(),
-                suggested_text: new_name,
-                expected_case: CaseType::UpperSnakeCase,
-            }
-        } else {
-            // Nothing to do here.
+        let data = self.db.const_data(const_id);
+        let Some(name) = &data.name else {
             return;
         };
-
-        let const_loc = const_id.lookup(self.db.upcast());
-        let const_src = const_loc.source(self.db.upcast());
-
-        let ast_ptr = match const_src.value.name() {
-            Some(name) => name,
-            None => return,
-        };
-
-        let diagnostic = IncorrectCase {
-            file: const_src.file_id,
-            ident_type: IdentType::Constant,
-            ident: AstPtr::new(&ast_ptr),
-            expected_case: replacement.expected_case,
-            ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
-            suggested_text: replacement.suggested_text,
-        };
-
-        self.sink.push(diagnostic);
+        self.create_incorrect_case_diagnostic_for_item_name(
+            const_id,
+            name,
+            CaseType::UpperSnakeCase,
+            IdentType::Constant,
+        );
     }
 
     fn validate_static(&mut self, static_id: StaticId) {
@@ -742,32 +585,91 @@ impl<'a> DeclValidator<'a> {
             return;
         }
 
-        let name = &data.name;
+        self.create_incorrect_case_diagnostic_for_item_name(
+            static_id,
+            &data.name,
+            CaseType::UpperSnakeCase,
+            IdentType::StaticVariable,
+        );
+    }
 
-        let static_name = name.to_smol_str();
-        let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) {
-            Replacement {
-                current_name: name.clone(),
-                suggested_text: new_name,
-                expected_case: CaseType::UpperSnakeCase,
-            }
-        } else {
-            // Nothing to do here.
+    fn validate_type_alias(&mut self, type_alias_id: TypeAliasId) {
+        let container = type_alias_id.lookup(self.db.upcast()).container;
+        if self.is_trait_impl_container(container) {
+            cov_mark::hit!(trait_impl_assoc_type_incorrect_case_ignored);
+            return;
+        }
+
+        // Check whether non-snake case identifiers are allowed for this type alias.
+        if self.allowed(type_alias_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
+            return;
+        }
+
+        // Check the type alias name.
+        let data = self.db.type_alias_data(type_alias_id);
+        self.create_incorrect_case_diagnostic_for_item_name(
+            type_alias_id,
+            &data.name,
+            CaseType::UpperCamelCase,
+            IdentType::TypeAlias,
+        );
+    }
+
+    fn create_incorrect_case_diagnostic_for_item_name<N, S, L>(
+        &mut self,
+        item_id: L,
+        name: &Name,
+        expected_case: CaseType,
+        ident_type: IdentType,
+    ) where
+        N: AstNode + HasName + fmt::Debug,
+        S: HasSource<Value = N>,
+        L: Lookup<Data = S, Database<'a> = dyn DefDatabase + 'a>,
+    {
+        let to_expected_case_type = match expected_case {
+            CaseType::LowerSnakeCase => to_lower_snake_case,
+            CaseType::UpperSnakeCase => to_upper_snake_case,
+            CaseType::UpperCamelCase => to_camel_case,
+        };
+        let Some(replacement) = to_expected_case_type(&name.to_smol_str()).map(|new_name| {
+            Replacement { current_name: name.clone(), suggested_text: new_name, expected_case }
+        }) else {
             return;
         };
 
-        let static_loc = static_id.lookup(self.db.upcast());
-        let static_src = static_loc.source(self.db.upcast());
+        let item_loc = item_id.lookup(self.db.upcast());
+        let item_src = item_loc.source(self.db.upcast());
+        self.create_incorrect_case_diagnostic_for_ast_node(
+            replacement,
+            item_src.file_id,
+            &item_src.value,
+            ident_type,
+        );
+    }
 
-        let ast_ptr = match static_src.value.name() {
-            Some(name) => name,
-            None => return,
+    fn create_incorrect_case_diagnostic_for_ast_node<T>(
+        &mut self,
+        replacement: Replacement,
+        file_id: HirFileId,
+        node: &T,
+        ident_type: IdentType,
+    ) where
+        T: AstNode + HasName + fmt::Debug,
+    {
+        let Some(name_ast) = node.name() else {
+            never!(
+                "Replacement ({:?}) was generated for a {:?} without a name: {:?}",
+                replacement,
+                ident_type,
+                node
+            );
+            return;
         };
 
         let diagnostic = IncorrectCase {
-            file: static_src.file_id,
-            ident_type: IdentType::StaticVariable,
-            ident: AstPtr::new(&ast_ptr),
+            file: file_id,
+            ident_type,
+            ident: AstPtr::new(&name_ast),
             expected_case: replacement.expected_case,
             ident_text: replacement.current_name.display(self.db.upcast()).to_string(),
             suggested_text: replacement.suggested_text,
@@ -775,4 +677,13 @@ impl<'a> DeclValidator<'a> {
 
         self.sink.push(diagnostic);
     }
+
+    fn is_trait_impl_container(&self, container_id: ItemContainerId) -> bool {
+        if let ItemContainerId::ImplId(impl_id) = container_id {
+            if self.db.impl_trait(impl_id).is_some() {
+                return true;
+            }
+        }
+        false
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index eda8f2371c9..7f8fb7f4b52 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -27,7 +27,7 @@ use crate::{
 
 pub(crate) use hir_def::{
     body::Body,
-    hir::{Expr, ExprId, MatchArm, Pat, PatId},
+    hir::{Expr, ExprId, MatchArm, Pat, PatId, Statement},
     LocalFieldId, VariantId,
 };
 
@@ -44,6 +44,12 @@ pub enum BodyValidationDiagnostic {
         match_expr: ExprId,
         uncovered_patterns: String,
     },
+    RemoveTrailingReturn {
+        return_expr: ExprId,
+    },
+    RemoveUnnecessaryElse {
+        if_expr: ExprId,
+    },
 }
 
 impl BodyValidationDiagnostic {
@@ -72,6 +78,10 @@ impl ExprValidator {
         let body = db.body(self.owner);
         let mut filter_map_next_checker = None;
 
+        if matches!(self.owner, DefWithBodyId::FunctionId(_)) {
+            self.check_for_trailing_return(body.body_expr, &body);
+        }
+
         for (id, expr) in body.exprs.iter() {
             if let Some((variant, missed_fields, true)) =
                 record_literal_missing_fields(db, &self.infer, id, expr)
@@ -90,9 +100,16 @@ impl ExprValidator {
                 Expr::Call { .. } | Expr::MethodCall { .. } => {
                     self.validate_call(db, id, expr, &mut filter_map_next_checker);
                 }
+                Expr::Closure { body: body_expr, .. } => {
+                    self.check_for_trailing_return(*body_expr, &body);
+                }
+                Expr::If { .. } => {
+                    self.check_for_unnecessary_else(id, expr, &body);
+                }
                 _ => {}
             }
         }
+
         for (id, pat) in body.pats.iter() {
             if let Some((variant, missed_fields, true)) =
                 record_pattern_missing_fields(db, &self.infer, id, pat)
@@ -153,14 +170,7 @@ impl ExprValidator {
         }
 
         let pattern_arena = Arena::new();
-        let ty_arena = Arena::new();
-        let cx = MatchCheckCtx::new(
-            self.owner.module(db.upcast()),
-            self.owner,
-            db,
-            &pattern_arena,
-            &ty_arena,
-        );
+        let cx = MatchCheckCtx::new(self.owner.module(db.upcast()), self.owner, db, &pattern_arena);
 
         let mut m_arms = Vec::with_capacity(arms.len());
         let mut has_lowering_errors = false;
@@ -207,7 +217,7 @@ impl ExprValidator {
         }
 
         let report = match compute_match_usefulness(
-            rustc_pattern_analysis::MatchCtxt { tycx: &cx },
+            &cx,
             m_arms.as_slice(),
             scrut_ty.clone(),
             ValidityConstraint::ValidOnly,
@@ -244,6 +254,59 @@ impl ExprValidator {
         }
         pattern
     }
+
+    fn check_for_trailing_return(&mut self, body_expr: ExprId, body: &Body) {
+        match &body.exprs[body_expr] {
+            Expr::Block { statements, tail, .. } => {
+                let last_stmt = tail.or_else(|| match statements.last()? {
+                    Statement::Expr { expr, .. } => Some(*expr),
+                    _ => None,
+                });
+                if let Some(last_stmt) = last_stmt {
+                    self.check_for_trailing_return(last_stmt, body);
+                }
+            }
+            Expr::If { then_branch, else_branch, .. } => {
+                self.check_for_trailing_return(*then_branch, body);
+                if let Some(else_branch) = else_branch {
+                    self.check_for_trailing_return(*else_branch, body);
+                }
+            }
+            Expr::Match { arms, .. } => {
+                for arm in arms.iter() {
+                    let MatchArm { expr, .. } = arm;
+                    self.check_for_trailing_return(*expr, body);
+                }
+            }
+            Expr::Return { .. } => {
+                self.diagnostics.push(BodyValidationDiagnostic::RemoveTrailingReturn {
+                    return_expr: body_expr,
+                });
+            }
+            _ => (),
+        }
+    }
+
+    fn check_for_unnecessary_else(&mut self, id: ExprId, expr: &Expr, body: &Body) {
+        if let Expr::If { condition: _, then_branch, else_branch } = expr {
+            if else_branch.is_none() {
+                return;
+            }
+            if let Expr::Block { statements, tail, .. } = &body.exprs[*then_branch] {
+                let last_then_expr = tail.or_else(|| match statements.last()? {
+                    Statement::Expr { expr, .. } => Some(*expr),
+                    _ => None,
+                });
+                if let Some(last_then_expr) = last_then_expr {
+                    let last_then_expr_ty = &self.infer[last_then_expr];
+                    if last_then_expr_ty.is_never() {
+                        self.diagnostics
+                            .push(BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr: id })
+                    }
+                }
+            }
+        }
+    }
 }
 
 struct FilterMapNextChecker {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 0b595042cd5..712842372b6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -9,7 +9,7 @@ use rustc_pattern_analysis::{
     index::IdxContainer,
     Captures, TypeCx,
 };
-use smallvec::SmallVec;
+use smallvec::{smallvec, SmallVec};
 use stdx::never;
 use typed_arena::Arena;
 
@@ -41,8 +41,14 @@ pub(crate) struct MatchCheckCtx<'p> {
     body: DefWithBodyId,
     pub(crate) db: &'p dyn HirDatabase,
     pub(crate) pattern_arena: &'p Arena<DeconstructedPat<'p>>,
-    ty_arena: &'p Arena<Ty>,
     exhaustive_patterns: bool,
+    min_exhaustive_patterns: bool,
+}
+
+#[derive(Clone)]
+pub(crate) struct PatData<'p> {
+    /// Keep db around so that we can print variant names in `Debug`.
+    pub(crate) db: &'p dyn HirDatabase,
 }
 
 impl<'p> MatchCheckCtx<'p> {
@@ -51,11 +57,12 @@ impl<'p> MatchCheckCtx<'p> {
         body: DefWithBodyId,
         db: &'p dyn HirDatabase,
         pattern_arena: &'p Arena<DeconstructedPat<'p>>,
-        ty_arena: &'p Arena<Ty>,
     ) -> Self {
         let def_map = db.crate_def_map(module.krate());
         let exhaustive_patterns = def_map.is_unstable_feature_enabled("exhaustive_patterns");
-        Self { module, body, db, pattern_arena, exhaustive_patterns, ty_arena }
+        let min_exhaustive_patterns =
+            def_map.is_unstable_feature_enabled("min_exhaustive_patterns");
+        Self { module, body, db, pattern_arena, exhaustive_patterns, min_exhaustive_patterns }
     }
 
     fn is_uninhabited(&self, ty: &Ty) -> bool {
@@ -75,18 +82,15 @@ impl<'p> MatchCheckCtx<'p> {
         }
     }
 
-    fn variant_id_for_adt(&self, ctor: &Constructor<Self>, adt: hir_def::AdtId) -> VariantId {
+    fn variant_id_for_adt(ctor: &Constructor<Self>, adt: hir_def::AdtId) -> Option<VariantId> {
         match ctor {
-            &Variant(id) => id.into(),
-            Struct | UnionField => {
-                assert!(!matches!(adt, hir_def::AdtId::EnumId(_)));
-                match adt {
-                    hir_def::AdtId::EnumId(_) => unreachable!(),
-                    hir_def::AdtId::StructId(id) => id.into(),
-                    hir_def::AdtId::UnionId(id) => id.into(),
-                }
-            }
-            _ => panic!("bad constructor {self:?} for adt {adt:?}"),
+            &Variant(id) => Some(id.into()),
+            Struct | UnionField => match adt {
+                hir_def::AdtId::EnumId(_) => None,
+                hir_def::AdtId::StructId(id) => Some(id.into()),
+                hir_def::AdtId::UnionId(id) => Some(id.into()),
+            },
+            _ => panic!("bad constructor {ctor:?} for adt {adt:?}"),
         }
     }
 
@@ -200,7 +204,7 @@ impl<'p> MatchCheckCtx<'p> {
                                 Wildcard
                             }
                         };
-                        let variant = self.variant_id_for_adt(&ctor, adt.0);
+                        let variant = Self::variant_id_for_adt(&ctor, adt.0).unwrap();
                         let fields_len = variant.variant_data(self.db.upcast()).fields().len();
                         // For each field in the variant, we store the relevant index into `self.fields` if any.
                         let mut field_id_to_id: Vec<Option<usize>> = vec![None; fields_len];
@@ -241,7 +245,8 @@ impl<'p> MatchCheckCtx<'p> {
                 fields = self.pattern_arena.alloc_extend(subpats);
             }
         }
-        DeconstructedPat::new(ctor, fields, pat.ty.clone(), ())
+        let data = PatData { db: self.db };
+        DeconstructedPat::new(ctor, fields, pat.ty.clone(), data)
     }
 
     pub(crate) fn hoist_witness_pat(&self, pat: &WitnessPat<'p>) -> Pat {
@@ -266,7 +271,7 @@ impl<'p> MatchCheckCtx<'p> {
                     PatKind::Deref { subpattern: subpatterns.next().unwrap() }
                 }
                 TyKind::Adt(adt, substs) => {
-                    let variant = self.variant_id_for_adt(pat.ctor(), adt.0);
+                    let variant = Self::variant_id_for_adt(pat.ctor(), adt.0).unwrap();
                     let subpatterns = self
                         .list_variant_nonhidden_fields(pat.ty(), variant)
                         .zip(subpatterns)
@@ -307,11 +312,14 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
     type VariantIdx = EnumVariantId;
     type StrLit = Void;
     type ArmData = ();
-    type PatData = ();
+    type PatData = PatData<'p>;
 
     fn is_exhaustive_patterns_feature_on(&self) -> bool {
         self.exhaustive_patterns
     }
+    fn is_min_exhaustive_patterns_feature_on(&self) -> bool {
+        self.min_exhaustive_patterns
+    }
 
     fn ctor_arity(
         &self,
@@ -327,7 +335,7 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
                         // patterns. If we're here we can assume this is a box pattern.
                         1
                     } else {
-                        let variant = self.variant_id_for_adt(ctor, adt);
+                        let variant = Self::variant_id_for_adt(ctor, adt).unwrap();
                         self.list_variant_nonhidden_fields(ty, variant).count()
                     }
                 }
@@ -347,54 +355,51 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
         }
     }
 
-    fn ctor_sub_tys(
-        &self,
-        ctor: &rustc_pattern_analysis::constructor::Constructor<Self>,
-        ty: &Self::Ty,
-    ) -> &[Self::Ty] {
-        use std::iter::once;
-        fn alloc<'a>(cx: &'a MatchCheckCtx<'_>, iter: impl Iterator<Item = Ty>) -> &'a [Ty] {
-            cx.ty_arena.alloc_extend(iter)
-        }
-        match ctor {
+    fn ctor_sub_tys<'a>(
+        &'a self,
+        ctor: &'a rustc_pattern_analysis::constructor::Constructor<Self>,
+        ty: &'a Self::Ty,
+    ) -> impl ExactSizeIterator<Item = Self::Ty> + Captures<'a> {
+        let single = |ty| smallvec![ty];
+        let tys: SmallVec<[_; 2]> = match ctor {
             Struct | Variant(_) | UnionField => match ty.kind(Interner) {
                 TyKind::Tuple(_, substs) => {
                     let tys = substs.iter(Interner).map(|ty| ty.assert_ty_ref(Interner));
-                    alloc(self, tys.cloned())
+                    tys.cloned().collect()
                 }
-                TyKind::Ref(.., rty) => alloc(self, once(rty.clone())),
+                TyKind::Ref(.., rty) => single(rty.clone()),
                 &TyKind::Adt(AdtId(adt), ref substs) => {
                     if is_box(self.db, adt) {
                         // The only legal patterns of type `Box` (outside `std`) are `_` and box
                         // patterns. If we're here we can assume this is a box pattern.
                         let subst_ty = substs.at(Interner, 0).assert_ty_ref(Interner).clone();
-                        alloc(self, once(subst_ty))
+                        single(subst_ty)
                     } else {
-                        let variant = self.variant_id_for_adt(ctor, adt);
-                        let tys = self.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty);
-                        alloc(self, tys)
+                        let variant = Self::variant_id_for_adt(ctor, adt).unwrap();
+                        self.list_variant_nonhidden_fields(ty, variant).map(|(_, ty)| ty).collect()
                     }
                 }
                 ty_kind => {
                     never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
-                    alloc(self, once(ty.clone()))
+                    single(ty.clone())
                 }
             },
             Ref => match ty.kind(Interner) {
-                TyKind::Ref(.., rty) => alloc(self, once(rty.clone())),
+                TyKind::Ref(.., rty) => single(rty.clone()),
                 ty_kind => {
                     never!("Unexpected type for `{:?}` constructor: {:?}", ctor, ty_kind);
-                    alloc(self, once(ty.clone()))
+                    single(ty.clone())
                 }
             },
             Slice(_) => unreachable!("Found a `Slice` constructor in match checking"),
             Bool(..) | IntRange(..) | F32Range(..) | F64Range(..) | Str(..) | Opaque(..)
-            | NonExhaustive | Hidden | Missing | Wildcard => &[],
+            | NonExhaustive | Hidden | Missing | Wildcard => smallvec![],
             Or => {
                 never!("called `Fields::wildcards` on an `Or` ctor");
-                &[]
+                smallvec![]
             }
-        }
+        };
+        tys.into_iter()
     }
 
     fn ctors_for_ty(
@@ -456,11 +461,27 @@ impl<'p> TypeCx for MatchCheckCtx<'p> {
         })
     }
 
-    fn debug_pat(
-        _f: &mut fmt::Formatter<'_>,
-        _pat: &rustc_pattern_analysis::pat::DeconstructedPat<'_, Self>,
+    fn write_variant_name(
+        f: &mut fmt::Formatter<'_>,
+        pat: &rustc_pattern_analysis::pat::DeconstructedPat<'_, Self>,
     ) -> fmt::Result {
-        // FIXME: implement this, as using `unimplemented!()` causes panics in `tracing`.
+        let variant =
+            pat.ty().as_adt().and_then(|(adt, _)| Self::variant_id_for_adt(pat.ctor(), adt));
+
+        let db = pat.data().unwrap().db;
+        if let Some(variant) = variant {
+            match variant {
+                VariantId::EnumVariantId(v) => {
+                    write!(f, "{}", db.enum_variant_data(v).name.display(db.upcast()))?;
+                }
+                VariantId::StructId(s) => {
+                    write!(f, "{}", db.struct_data(s).name.display(db.upcast()))?
+                }
+                VariantId::UnionId(u) => {
+                    write!(f, "{}", db.union_data(u).name.display(db.upcast()))?
+                }
+            }
+        }
         Ok(())
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index 2327c8df1b4..fe51ec3f821 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -32,7 +32,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::try_const_usize,
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosure},
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx,
     layout::Layout,
     lt_from_placeholder_idx,
@@ -814,9 +814,8 @@ impl HirDisplay for Ty {
 
                             // Don't count Sized but count when it absent
                             // (i.e. when explicit ?Sized bound is set).
-                            let default_sized = SizedByDefault::Sized {
-                                anchor: func.lookup(db.upcast()).module(db.upcast()).krate(),
-                            };
+                            let default_sized =
+                                SizedByDefault::Sized { anchor: func.krate(db.upcast()) };
                             let sized_bounds = bounds
                                 .skip_binders()
                                 .iter()
@@ -1025,7 +1024,7 @@ impl HirDisplay for Ty {
                         let data =
                             (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
                         let bounds = data.substitute(Interner, &parameters);
-                        let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
+                        let krate = func.krate(db.upcast());
                         write_bounds_like_dyn_trait_with_prefix(
                             f,
                             "impl",
@@ -1086,7 +1085,7 @@ impl HirDisplay for Ty {
                 }
                 let sig = ClosureSubst(substs).sig_ty().callable_sig(db);
                 if let Some(sig) = sig {
-                    let (def, _) = db.lookup_intern_closure((*id).into());
+                    let InternedClosure(def, _) = db.lookup_intern_closure((*id).into());
                     let infer = db.infer(def);
                     let (_, kind) = infer.closure_info(id);
                     match f.closure_style {
@@ -1191,7 +1190,7 @@ impl HirDisplay for Ty {
                         let data =
                             (*datas).as_ref().map(|rpit| rpit.impl_traits[idx].bounds.clone());
                         let bounds = data.substitute(Interner, &opaque_ty.substitution);
-                        let krate = func.lookup(db.upcast()).module(db.upcast()).krate();
+                        let krate = func.krate(db.upcast());
                         write_bounds_like_dyn_trait_with_prefix(
                             f,
                             "impl",
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 572df8f7137..c3746f78706 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -21,7 +21,7 @@ use smallvec::SmallVec;
 use stdx::never;
 
 use crate::{
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosure},
     from_placeholder_idx, make_binders,
     mir::{BorrowKind, MirSpan, ProjectionElem},
     static_lifetime, to_chalk_trait_id,
@@ -194,17 +194,15 @@ impl CapturedItem {
                     }
                     let variant_data = f.parent.variant_data(db.upcast());
                     let field = match &*variant_data {
-                        VariantData::Record(fields) => fields[f.local_id]
-                            .name
-                            .as_str()
-                            .unwrap_or("[missing field]")
-                            .to_string(),
+                        VariantData::Record(fields) => {
+                            fields[f.local_id].name.as_str().unwrap_or("[missing field]").to_owned()
+                        }
                         VariantData::Tuple(fields) => fields
                             .iter()
                             .position(|it| it.0 == f.local_id)
                             .unwrap_or_default()
                             .to_string(),
-                        VariantData::Unit => "[missing field]".to_string(),
+                        VariantData::Unit => "[missing field]".to_owned(),
                     };
                     result = format!("{result}.{field}");
                     field_need_paren = false;
@@ -718,7 +716,7 @@ impl InferenceContext<'_> {
 
     fn is_upvar(&self, place: &HirPlace) -> bool {
         if let Some(c) = self.current_closure {
-            let (_, root) = self.db.lookup_intern_closure(c.into());
+            let InternedClosure(_, root) = self.db.lookup_intern_closure(c.into());
             return self.body.is_binding_upvar(place.local, root);
         }
         false
@@ -940,7 +938,7 @@ impl InferenceContext<'_> {
     }
 
     fn analyze_closure(&mut self, closure: ClosureId) -> FnTrait {
-        let (_, root) = self.db.lookup_intern_closure(closure.into());
+        let InternedClosure(_, root) = self.db.lookup_intern_closure(closure.into());
         self.current_closure = Some(closure);
         let Expr::Closure { body, capture_by, .. } = &self.body[root] else {
             unreachable!("Closure expression id is always closure");
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 842f7bdafe7..8b8e97b0081 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -23,6 +23,7 @@ use syntax::ast::RangeOp;
 use crate::{
     autoderef::{builtin_deref, deref_by_trait, Autoderef},
     consteval,
+    db::{InternedClosure, InternedCoroutine},
     infer::{
         coerce::{CoerceMany, CoercionCause},
         find_continuable,
@@ -253,13 +254,17 @@ impl InferenceContext<'_> {
                             .push(ret_ty.clone())
                             .build();
 
-                        let coroutine_id = self.db.intern_coroutine((self.owner, tgt_expr)).into();
+                        let coroutine_id = self
+                            .db
+                            .intern_coroutine(InternedCoroutine(self.owner, tgt_expr))
+                            .into();
                         let coroutine_ty = TyKind::Coroutine(coroutine_id, subst).intern(Interner);
 
                         (None, coroutine_ty, Some((resume_ty, yield_ty)))
                     }
                     ClosureKind::Closure | ClosureKind::Async => {
-                        let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
+                        let closure_id =
+                            self.db.intern_closure(InternedClosure(self.owner, tgt_expr)).into();
                         let closure_ty = TyKind::Closure(
                             closure_id,
                             TyBuilder::subst_for_closure(self.db, self.owner, sig_ty.clone()),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
index 61c82339508..de23ca34990 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs
@@ -469,12 +469,14 @@ impl<'a> InferenceTable<'a> {
         }
     }
 
+    #[tracing::instrument(skip_all)]
     pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
         self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
         self.type_variable_table = snapshot.type_variable_table_snapshot;
         self.pending_obligations = snapshot.pending_obligations;
     }
 
+    #[tracing::instrument(skip_all)]
     pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable<'_>) -> T) -> T {
         let snapshot = self.snapshot();
         let result = f(self);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
index 310c4cc9ffe..be1c8d9094b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout.rs
@@ -19,8 +19,12 @@ use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    consteval::try_const_usize, db::HirDatabase, infer::normalize, layout::adt::struct_variant_idx,
-    utils::ClosureSubst, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
+    consteval::try_const_usize,
+    db::{HirDatabase, InternedClosure},
+    infer::normalize,
+    layout::adt::struct_variant_idx,
+    utils::ClosureSubst,
+    Interner, ProjectionTy, Substitution, TraitEnvironment, Ty,
 };
 
 pub use self::{
@@ -391,7 +395,7 @@ pub fn layout_of_ty_query(
             }
         }
         TyKind::Closure(c, subst) => {
-            let (def, _) = db.lookup_intern_closure((*c).into());
+            let InternedClosure(def, _) = db.lookup_intern_closure((*c).into());
             let infer = db.infer(def);
             let (captures, _) = infer.closure_info(c);
             let fields = captures
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
index 1f2ea753c1b..ba3dfe8100d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/layout/tests.rs
@@ -1,8 +1,7 @@
-use std::collections::HashMap;
-
 use chalk_ir::{AdtId, TyKind};
 use either::Either;
 use hir_def::db::DefDatabase;
+use rustc_hash::FxHashMap;
 use test_fixture::WithFixture;
 use triomphe::Arc;
 
@@ -16,7 +15,7 @@ use crate::{
 mod closure;
 
 fn current_machine_data_layout() -> String {
-    project_model::target_data_layout::get(None, None, &HashMap::default()).unwrap()
+    project_model::target_data_layout::get(None, None, &FxHashMap::default()).unwrap()
 }
 
 fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutError> {
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 288c42405d6..70138633341 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -51,6 +51,7 @@ use std::{
     hash::{BuildHasherDefault, Hash},
 };
 
+use base_db::salsa::impl_intern_value_trivial;
 use chalk_ir::{
     fold::{Shift, TypeFoldable},
     interner::HasInterner,
@@ -228,7 +229,7 @@ impl MemoryMap {
         &self,
         mut f: impl FnMut(&[u8], usize) -> Result<usize, MirEvalError>,
     ) -> Result<FxHashMap<usize, usize>, MirEvalError> {
-        let mut transform = |(addr, val): (&usize, &Box<[u8]>)| {
+        let mut transform = |(addr, val): (&usize, &[u8])| {
             let addr = *addr;
             let align = if addr == 0 { 64 } else { (addr - (addr & (addr - 1))).min(64) };
             f(val, align).map(|it| (addr, it))
@@ -240,7 +241,9 @@ impl MemoryMap {
                 map.insert(addr, val);
                 map
             }),
-            MemoryMap::Complex(cm) => cm.memory.iter().map(transform).collect(),
+            MemoryMap::Complex(cm) => {
+                cm.memory.iter().map(|(addr, val)| transform((addr, val))).collect()
+            }
         }
     }
 
@@ -584,6 +587,7 @@ pub enum ImplTraitId {
     ReturnTypeImplTrait(hir_def::FunctionId, RpitId),
     AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId),
 }
+impl_intern_value_trivial!(ImplTraitId);
 
 #[derive(Clone, PartialEq, Eq, Debug, Hash)]
 pub struct ReturnTypeImplTraits {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
index 386a03d93f3..75ac3b0d66b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -10,7 +10,10 @@ use std::{
     iter,
 };
 
-use base_db::{salsa::Cycle, CrateId};
+use base_db::{
+    salsa::{impl_intern_value_trivial, Cycle},
+    CrateId,
+};
 use chalk_ir::{
     cast::Cast, fold::Shift, fold::TypeFoldable, interner::HasInterner, Mutability, Safety,
 };
@@ -1225,7 +1228,7 @@ impl<'a> TyLoweringContext<'a> {
                 .collect();
 
             if !ctx.unsized_types.borrow().contains(&self_ty) {
-                let krate = func.lookup(ctx.db.upcast()).module(ctx.db.upcast()).krate();
+                let krate = func.krate(ctx.db.upcast());
                 let sized_trait = ctx
                     .db
                     .lang_item(krate, LangItem::Sized)
@@ -1809,6 +1812,7 @@ pub enum CallableDefId {
     StructId(StructId),
     EnumVariantId(EnumVariantId),
 }
+impl_intern_value_trivial!(CallableDefId);
 impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId);
 impl From<CallableDefId> for ModuleDefId {
     fn from(def: CallableDefId) -> ModuleDefId {
@@ -1824,11 +1828,10 @@ impl CallableDefId {
     pub fn krate(self, db: &dyn HirDatabase) -> CrateId {
         let db = db.upcast();
         match self {
-            CallableDefId::FunctionId(f) => f.lookup(db).module(db),
-            CallableDefId::StructId(s) => s.lookup(db).container,
-            CallableDefId::EnumVariantId(e) => e.module(db),
+            CallableDefId::FunctionId(f) => f.krate(db),
+            CallableDefId::StructId(s) => s.krate(db),
+            CallableDefId::EnumVariantId(e) => e.krate(db),
         }
-        .krate()
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
index 1c068bf684a..a4baf572d9e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs
@@ -931,6 +931,15 @@ pub fn iterate_method_candidates_dyn(
     mode: LookupMode,
     callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
+    let _p = tracing::span!(
+        tracing::Level::INFO,
+        "iterate_method_candidates_dyn",
+        ?mode,
+        ?name,
+        traits_in_scope_len = traits_in_scope.len()
+    )
+    .entered();
+
     match mode {
         LookupMode::MethodCall => {
             // For method calls, rust first does any number of autoderef, and
@@ -984,6 +993,7 @@ pub fn iterate_method_candidates_dyn(
     }
 }
 
+#[tracing::instrument(skip_all, fields(name = ?name))]
 fn iterate_method_candidates_with_autoref(
     receiver_ty: &Canonical<Ty>,
     first_adjustment: ReceiverAdjustments,
@@ -1041,6 +1051,7 @@ fn iterate_method_candidates_with_autoref(
     )
 }
 
+#[tracing::instrument(skip_all, fields(name = ?name))]
 fn iterate_method_candidates_by_receiver(
     receiver_ty: &Canonical<Ty>,
     receiver_adjustments: ReceiverAdjustments,
@@ -1088,6 +1099,7 @@ fn iterate_method_candidates_by_receiver(
     ControlFlow::Continue(())
 }
 
+#[tracing::instrument(skip_all, fields(name = ?name))]
 fn iterate_method_candidates_for_self_ty(
     self_ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
@@ -1119,6 +1131,7 @@ fn iterate_method_candidates_for_self_ty(
     )
 }
 
+#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
 fn iterate_trait_method_candidates(
     self_ty: &Ty,
     table: &mut InferenceTable<'_>,
@@ -1175,6 +1188,7 @@ fn iterate_trait_method_candidates(
     ControlFlow::Continue(())
 }
 
+#[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
 fn iterate_inherent_methods(
     self_ty: &Ty,
     table: &mut InferenceTable<'_>,
@@ -1267,6 +1281,7 @@ fn iterate_inherent_methods(
     }
     return ControlFlow::Continue(());
 
+    #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
     fn iterate_inherent_trait_methods(
         self_ty: &Ty,
         table: &mut InferenceTable<'_>,
@@ -1293,6 +1308,7 @@ fn iterate_inherent_methods(
         ControlFlow::Continue(())
     }
 
+    #[tracing::instrument(skip_all, fields(name = ?name, visible_from_module, receiver_ty))]
     fn impls_for_self_ty(
         impls: &InherentImpls,
         self_ty: &Ty,
@@ -1356,6 +1372,7 @@ macro_rules! check_that {
     };
 }
 
+#[tracing::instrument(skip_all, fields(name))]
 fn is_valid_candidate(
     table: &mut InferenceTable<'_>,
     name: Option<&Name>,
@@ -1403,6 +1420,7 @@ enum IsValidCandidate {
     NotVisible,
 }
 
+#[tracing::instrument(skip_all, fields(name))]
 fn is_valid_fn_candidate(
     table: &mut InferenceTable<'_>,
     fn_id: FunctionId,
@@ -1439,15 +1457,15 @@ fn is_valid_fn_candidate(
             _ => unreachable!(),
         };
 
-        let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
-            .fill_with_inference_vars(table)
-            .build();
-
         check_that!(table.unify(&expect_self_ty, self_ty));
 
         if let Some(receiver_ty) = receiver_ty {
             check_that!(data.has_self_param());
 
+            let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone()))
+                .fill_with_inference_vars(table)
+                .build();
+
             let sig = db.callable_item_signature(fn_id.into());
             let expected_receiver =
                 sig.map(|s| s.params()[0].clone()).substitute(Interner, &fn_subst);
@@ -1540,6 +1558,7 @@ pub fn implements_trait_unique(
 
 /// This creates Substs for a trait with the given Self type and type variables
 /// for all other parameters, to query Chalk with it.
+#[tracing::instrument(skip_all)]
 fn generic_implements_goal(
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
index ea4e60cad30..9089c11c5d9 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs
@@ -11,7 +11,10 @@ use stdx::never;
 use triomphe::Arc;
 
 use crate::{
-    db::HirDatabase, mir::Operand, utils::ClosureSubst, ClosureId, Interner, Ty, TyExt, TypeFlags,
+    db::{HirDatabase, InternedClosure},
+    mir::Operand,
+    utils::ClosureSubst,
+    ClosureId, Interner, Ty, TyExt, TypeFlags,
 };
 
 use super::{
@@ -97,7 +100,7 @@ fn moved_out_of_ref(db: &dyn HirDatabase, body: &MirBody) -> Vec<MovedOutOfRef>
                     ty,
                     db,
                     |c, subst, f| {
-                        let (def, _) = db.lookup_intern_closure(c.into());
+                        let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
                         let infer = db.infer(def);
                         let (captures, _) = infer.closure_info(&c);
                         let parent_subst = ClosureSubst(subst).parent_subst();
@@ -215,7 +218,7 @@ fn place_case(db: &dyn HirDatabase, body: &MirBody, lvalue: &Place) -> Projectio
             ty,
             db,
             |c, subst, f| {
-                let (def, _) = db.lookup_intern_closure(c.into());
+                let InternedClosure(def, _) = db.lookup_intern_closure(c.into());
                 let infer = db.infer(def);
                 let (captures, _) = infer.closure_info(&c);
                 let parent_subst = ClosureSubst(subst).parent_subst();
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
index 50c4d00660b..2428678d72b 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs
@@ -25,7 +25,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::{intern_const_scalar, try_const_usize, ConstEvalError},
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosure},
     display::{ClosureStyle, HirDisplay},
     infer::PointerCast,
     layout::{Layout, LayoutError, RustcEnumVariantIdx},
@@ -647,7 +647,7 @@ impl Evaluator<'_> {
             ty.clone(),
             self.db,
             |c, subst, f| {
-                let (def, _) = self.db.lookup_intern_closure(c.into());
+                let InternedClosure(def, _) = self.db.lookup_intern_closure(c.into());
                 let infer = self.db.infer(def);
                 let (captures, _) = infer.closure_info(&c);
                 let parent_subst = ClosureSubst(subst).parent_subst();
@@ -1763,7 +1763,7 @@ impl Evaluator<'_> {
             }
         };
         mem.get(pos..pos + size)
-            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string()))
+            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_owned()))
     }
 
     fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<&mut [u8]> {
@@ -1777,7 +1777,7 @@ impl Evaluator<'_> {
             }
         };
         mem.get_mut(pos..pos + size)
-            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory write".to_string()))
+            .ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory write".to_owned()))
     }
 
     fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
@@ -1800,7 +1800,7 @@ impl Evaluator<'_> {
             return Ok(());
         }
 
-        let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_string());
+        let oob = || MirEvalError::UndefinedBehavior("out of bounds memory write".to_owned());
 
         match (addr, r.addr) {
             (Stack(dst), Stack(src)) => {
@@ -2653,7 +2653,7 @@ pub fn render_const_using_debug_impl(
         ptr: ArenaMap::new(),
         body: db
             .mir_body(owner.into())
-            .map_err(|_| MirEvalError::NotSupported("unreachable".to_string()))?,
+            .map_err(|_| MirEvalError::NotSupported("unreachable".to_owned()))?,
         drop_flags: DropFlags::default(),
     };
     let data = evaluator.allocate_const_in_heap(locals, c)?;
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 b4fb99acae7..d68803fe280 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
@@ -178,7 +178,7 @@ impl Evaluator<'_> {
                     not_supported!("wrong arg count for clone");
                 };
                 let addr = Address::from_bytes(arg.get(self)?)?;
-                let (closure_owner, _) = self.db.lookup_intern_closure((*id).into());
+                let InternedClosure(closure_owner, _) = self.db.lookup_intern_closure((*id).into());
                 let infer = self.db.infer(closure_owner);
                 let (captures, _) = infer.closure_info(id);
                 let layout = self.layout(&self_ty)?;
@@ -304,7 +304,7 @@ impl Evaluator<'_> {
         use LangItem::*;
         let mut args = args.iter();
         match it {
-            BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_string())),
+            BeginPanic => Err(MirEvalError::Panic("<unknown-panic-payload>".to_owned())),
             PanicFmt => {
                 let message = (|| {
                     let resolver = self
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 28d26c6c8ae..1572a6d497c 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -25,7 +25,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::ConstEvalError,
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosure},
     display::HirDisplay,
     infer::{CaptureKind, CapturedItem, TypeMismatch},
     inhabitedness::is_ty_uninhabited_from,
@@ -126,6 +126,10 @@ impl DropScopeToken {
     }
 }
 
+impl Drop for DropScopeToken {
+    fn drop(&mut self) {}
+}
+
 // Uncomment this to make `DropScopeToken` a drop bomb. Unfortunately we can't do this in release, since
 // in cases that mir lowering fails, we don't handle (and don't need to handle) drop scopes so it will be
 // actually reached. `pop_drop_scope_assert_finished` will also detect this case, but doesn't show useful
@@ -1630,7 +1634,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
         self.set_goto(prev_block, begin, span);
         f(self, begin)?;
         let my = mem::replace(&mut self.current_loop_blocks, prev).ok_or(
-            MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_string()),
+            MirLowerError::ImplementationError("current_loop_blocks is corrupt".to_owned()),
         )?;
         if let Some(prev) = prev_label {
             self.labeled_loop_blocks.insert(label.unwrap(), prev);
@@ -1665,7 +1669,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             .current_loop_blocks
             .as_mut()
             .ok_or(MirLowerError::ImplementationError(
-                "Current loop access out of loop".to_string(),
+                "Current loop access out of loop".to_owned(),
             ))?
             .end
         {
@@ -1675,7 +1679,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                 self.current_loop_blocks
                     .as_mut()
                     .ok_or(MirLowerError::ImplementationError(
-                        "Current loop access out of loop".to_string(),
+                        "Current loop access out of loop".to_owned(),
                     ))?
                     .end = Some(s);
                 s
@@ -1973,7 +1977,7 @@ pub fn mir_body_for_closure_query(
     db: &dyn HirDatabase,
     closure: ClosureId,
 ) -> Result<Arc<MirBody>> {
-    let (owner, expr) = db.lookup_intern_closure(closure.into());
+    let InternedClosure(owner, expr) = db.lookup_intern_closure(closure.into());
     let body = db.body(owner);
     let infer = db.infer(owner);
     let Expr::Closure { args, body: root, .. } = &body[expr] else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
index 8d157944020..afe33607d46 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower/as_place.rs
@@ -225,7 +225,7 @@ impl MirLowerCtx<'_> {
                 {
                     let Some(index_fn) = self.infer.method_resolution(expr_id) else {
                         return Err(MirLowerError::UnresolvedMethod(
-                            "[overloaded index]".to_string(),
+                            "[overloaded index]".to_owned(),
                         ));
                     };
                     let Some((base_place, current)) =
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
index 46dec257e89..d2e413f0a33 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs
@@ -19,7 +19,7 @@ use triomphe::Arc;
 
 use crate::{
     consteval::{intern_const_scalar, unknown_const},
-    db::HirDatabase,
+    db::{HirDatabase, InternedClosure},
     from_placeholder_idx,
     infer::normalize,
     utils::{generics, Generics},
@@ -315,7 +315,7 @@ pub fn monomorphized_mir_body_for_closure_query(
     subst: Substitution,
     trait_env: Arc<crate::TraitEnvironment>,
 ) -> Result<Arc<MirBody>, MirLowerError> {
-    let (owner, _) = db.lookup_intern_closure(closure.into());
+    let InternedClosure(owner, _) = db.lookup_intern_closure(closure.into());
     let generics = owner.as_generic_def_id().map(|g_def| generics(db.upcast(), g_def));
     let filler = &mut Filler { db, subst: &subst, trait_env, generics, owner };
     let body = db.mir_body_for_closure(closure)?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index 9804910c878..5e159236f48 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -10,7 +10,7 @@ mod regression;
 mod simple;
 mod traits;
 
-use std::{collections::HashMap, env};
+use std::env;
 
 use base_db::{FileRange, SourceDatabaseExt};
 use expect_test::Expect;
@@ -25,6 +25,7 @@ use hir_def::{
 };
 use hir_expand::{db::ExpandDatabase, InFile};
 use once_cell::race::OnceBool;
+use rustc_hash::FxHashMap;
 use stdx::format_to;
 use syntax::{
     ast::{self, AstNode, HasName},
@@ -90,16 +91,16 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
     let (db, files) = TestDB::with_many_files(ra_fixture);
 
     let mut had_annotations = false;
-    let mut mismatches = HashMap::new();
-    let mut types = HashMap::new();
-    let mut adjustments = HashMap::<_, Vec<_>>::new();
+    let mut mismatches = FxHashMap::default();
+    let mut types = FxHashMap::default();
+    let mut adjustments = FxHashMap::<_, Vec<_>>::default();
     for (file_id, annotations) in db.extract_annotations() {
         for (range, expected) in annotations {
             let file_range = FileRange { file_id, range };
             if only_types {
                 types.insert(file_range, expected);
             } else if expected.starts_with("type: ") {
-                types.insert(file_range, expected.trim_start_matches("type: ").to_string());
+                types.insert(file_range, expected.trim_start_matches("type: ").to_owned());
             } else if expected.starts_with("expected") {
                 mismatches.insert(file_range, expected);
             } else if expected.starts_with("adjustments:") {
@@ -109,7 +110,7 @@ fn check_impl(ra_fixture: &str, allow_none: bool, only_types: bool, display_sour
                         .trim_start_matches("adjustments:")
                         .trim()
                         .split(',')
-                        .map(|it| it.trim().to_string())
+                        .map(|it| it.trim().to_owned())
                         .filter(|it| !it.is_empty())
                         .collect(),
                 );
@@ -330,7 +331,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
         });
         for (node, ty) in &types {
             let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.value.clone()) {
-                (self_param.name().unwrap().syntax().text_range(), "self".to_string())
+                (self_param.name().unwrap().syntax().text_range(), "self".to_owned())
             } else {
                 (node.value.text_range(), node.value.text().to_string().replace('\n', " "))
             };
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
index b0a9361f1c5..2f75338f994 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/macros.rs
@@ -1373,3 +1373,34 @@ pub fn attr_macro() {}
 "#,
     );
 }
+
+#[test]
+fn clone_with_type_bound() {
+    check_types(
+        r#"
+//- minicore: derive, clone, builtin_impls
+#[derive(Clone)]
+struct Float;
+
+trait TensorKind: Clone {
+    /// The primitive type of the tensor.
+    type Primitive: Clone;
+}
+
+impl TensorKind for Float {
+    type Primitive = f64;
+}
+
+#[derive(Clone)]
+struct Tensor<K = Float> where K: TensorKind
+{
+    primitive: K::Primitive,
+}
+
+fn foo(t: Tensor) {
+    let x = t.clone();
+      //^ Tensor<Float>
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index 3a1a4e63ea1..b2232b920aa 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -104,8 +104,8 @@ pub(crate) fn trait_solve_query(
         GoalData::DomainGoal(DomainGoal::Holds(WhereClause::Implemented(it))) => {
             db.trait_data(it.hir_trait_id()).name.display(db.upcast()).to_string()
         }
-        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_string(),
-        _ => "??".to_string(),
+        GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(),
+        _ => "??".to_owned(),
     };
     let _p = tracing::span!(tracing::Level::INFO, "trait_solve_query", ?detail).entered();
     tracing::info!("trait_solve_query({:?})", goal.value.goal);
@@ -187,7 +187,7 @@ struct LoggingRustIrDatabaseLoggingOnDrop<'a>(LoggingRustIrDatabase<Interner, Ch
 
 impl Drop for LoggingRustIrDatabaseLoggingOnDrop<'_> {
     fn drop(&mut self) {
-        eprintln!("chalk program:\n{}", self.0);
+        tracing::info!("chalk program:\n{}", self.0);
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
index 5c369f42e6e..7d637bac096 100644
--- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs
@@ -30,7 +30,7 @@ macro_rules! impl_has_attrs {
         impl HasAttrs for $def {
             fn attrs(self, db: &dyn HirDatabase) -> AttrsWithOwner {
                 let def = AttrDefId::$def_id(self.into());
-                AttrsWithOwner::attrs_with_owner(db.upcast(), def)
+                AttrsWithOwner::new(db.upcast(), def)
             }
             fn attr_id(self) -> AttrDefId {
                 AttrDefId::$def_id(self.into())
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index 2d8f1dbad51..08843a6c999 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -67,6 +67,8 @@ diagnostics![
     NoSuchField,
     PrivateAssocItem,
     PrivateField,
+    RemoveTrailingReturn,
+    RemoveUnnecessaryElse,
     ReplaceFilterMapNextWithFindMap,
     TraitImplIncorrectSafety,
     TraitImplMissingAssocItems,
@@ -342,6 +344,16 @@ pub struct TraitImplRedundantAssocItems {
     pub assoc_item: (Name, AssocItem),
 }
 
+#[derive(Debug)]
+pub struct RemoveTrailingReturn {
+    pub return_expr: InFile<AstPtr<ast::ReturnExpr>>,
+}
+
+#[derive(Debug)]
+pub struct RemoveUnnecessaryElse {
+    pub if_expr: InFile<AstPtr<ast::IfExpr>>,
+}
+
 impl AnyDiagnostic {
     pub(crate) fn body_validation_diagnostic(
         db: &dyn HirDatabase,
@@ -444,6 +456,29 @@ impl AnyDiagnostic {
                     Err(SyntheticSyntax) => (),
                 }
             }
+            BodyValidationDiagnostic::RemoveTrailingReturn { return_expr } => {
+                if let Ok(source_ptr) = source_map.expr_syntax(return_expr) {
+                    // Filters out desugared return expressions (e.g. desugared try operators).
+                    if let Some(ptr) = source_ptr.value.cast::<ast::ReturnExpr>() {
+                        return Some(
+                            RemoveTrailingReturn {
+                                return_expr: InFile::new(source_ptr.file_id, ptr),
+                            }
+                            .into(),
+                        );
+                    }
+                }
+            }
+            BodyValidationDiagnostic::RemoveUnnecessaryElse { if_expr } => {
+                if let Ok(source_ptr) = source_map.expr_syntax(if_expr) {
+                    if let Some(ptr) = source_ptr.value.cast::<ast::IfExpr>() {
+                        return Some(
+                            RemoveUnnecessaryElse { if_expr: InFile::new(source_ptr.file_id, ptr) }
+                                .into(),
+                        );
+                    }
+                }
+            }
         }
         None
     }
@@ -546,9 +581,7 @@ impl AnyDiagnostic {
                             source_map.pat_syntax(pat).expect("unexpected synthetic");
 
                         // cast from Either<Pat, SelfParam> -> Either<_, Pat>
-                        let Some(ptr) = AstPtr::try_from_raw(value.syntax_node_ptr()) else {
-                            return None;
-                        };
+                        let ptr = AstPtr::try_from_raw(value.syntax_node_ptr())?;
                         InFile { file_id, value: ptr }
                     }
                 };
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index 9b99b141fc5..30f402a79f3 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -158,7 +158,8 @@ impl HirDisplay for Adt {
 
 impl HirDisplay for Struct {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
+        let module_id = self.module(f.db).id;
+        write_visibility(module_id, self.visibility(f.db), f)?;
         f.write_str("struct ")?;
         write!(f, "{}", self.name(f.db).display(f.db.upcast()))?;
         let def_id = GenericDefId::AdtId(AdtId::StructId(self.id));
@@ -171,6 +172,7 @@ impl HirDisplay for Struct {
 
             while let Some((id, _)) = it.next() {
                 let field = Field { parent: (*self).into(), id };
+                write_visibility(module_id, field.visibility(f.db), f)?;
                 field.ty(f.db).hir_fmt(f)?;
                 if it.peek().is_some() {
                     f.write_str(", ")?;
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 1e21045e981..32abbc80c6a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -44,7 +44,7 @@ use hir_def::{
     data::adt::VariantData,
     generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
     hir::{BindingAnnotation, BindingId, ExprOrPatId, LabelId, Pat},
-    item_tree::ItemTreeModItemNode,
+    item_tree::ItemTreeNode,
     lang_item::LangItemTarget,
     layout::{self, ReprOptions, TargetDataLayout},
     nameres::{self, diagnostics::DefDiagnostic},
@@ -62,6 +62,7 @@ use hir_expand::{attrs::collect_attrs, name::name, proc_macro::ProcMacroKind, Ma
 use hir_ty::{
     all_super_traits, autoderef, check_orphan_rules,
     consteval::{try_const_usize, unknown_const_as_generic, ConstExt},
+    db::InternedClosure,
     diagnostics::BodyValidationDiagnostic,
     known_const_to_ast,
     layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding},
@@ -563,6 +564,11 @@ impl Module {
                     for diag in db.trait_data_with_diagnostics(t.id).1.iter() {
                         emit_def_diagnostic(db, acc, diag);
                     }
+
+                    for item in t.items(db) {
+                        item.diagnostics(db, acc);
+                    }
+
                     acc.extend(def.diagnostics(db))
                 }
                 ModuleDef::Adt(adt) => {
@@ -730,13 +736,7 @@ impl Module {
             }
 
             for &item in &db.impl_data(impl_def.id).items {
-                let def: DefWithBody = match AssocItem::from(item) {
-                    AssocItem::Function(it) => it.into(),
-                    AssocItem::Const(it) => it.into(),
-                    AssocItem::TypeAlias(_) => continue,
-                };
-
-                def.diagnostics(db, acc);
+                AssocItem::from(item).diagnostics(db, acc);
             }
         }
     }
@@ -1769,7 +1769,7 @@ pub struct Function {
 
 impl Function {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        self.id.lookup(db.upcast()).module(db.upcast()).into()
+        self.id.module(db.upcast()).into()
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -1910,8 +1910,7 @@ impl Function {
         {
             return None;
         }
-        let loc = self.id.lookup(db.upcast());
-        let def_map = db.crate_def_map(loc.krate(db).into());
+        let def_map = db.crate_def_map(HasModule::krate(&self.id, db.upcast()));
         def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
     }
 
@@ -1934,7 +1933,7 @@ impl Function {
         };
         let (result, output) = interpret_mir(db, body, false, None);
         let mut text = match result {
-            Ok(_) => "pass".to_string(),
+            Ok(_) => "pass".to_owned(),
             Err(e) => {
                 let mut r = String::new();
                 _ = e.pretty_print(&mut r, db, &span_formatter);
@@ -2120,7 +2119,7 @@ pub struct Const {
 
 impl Const {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
+        Module { id: self.id.module(db.upcast()) }
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
@@ -2175,7 +2174,7 @@ pub struct Static {
 
 impl Static {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
+        Module { id: self.id.module(db.upcast()) }
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
@@ -2294,7 +2293,7 @@ impl TypeAlias {
     }
 
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
+        Module { id: self.id.module(db.upcast()) }
     }
 
     pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
@@ -2517,11 +2516,13 @@ pub enum AssocItem {
     Const(Const),
     TypeAlias(TypeAlias),
 }
+
 #[derive(Debug, Clone)]
 pub enum AssocItemContainer {
     Trait(Trait),
     Impl(Impl),
 }
+
 pub trait AsAssocItem {
     fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem>;
 }
@@ -2531,16 +2532,19 @@ impl AsAssocItem for Function {
         as_assoc_item(db, AssocItem::Function, self.id)
     }
 }
+
 impl AsAssocItem for Const {
     fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
         as_assoc_item(db, AssocItem::Const, self.id)
     }
 }
+
 impl AsAssocItem for TypeAlias {
     fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
         as_assoc_item(db, AssocItem::TypeAlias, self.id)
     }
 }
+
 impl AsAssocItem for ModuleDef {
     fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
         match self {
@@ -2551,6 +2555,7 @@ impl AsAssocItem for ModuleDef {
         }
     }
 }
+
 impl AsAssocItem for DefWithBody {
     fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
         match self {
@@ -2561,16 +2566,15 @@ impl AsAssocItem for DefWithBody {
     }
 }
 
-fn as_assoc_item<'db, ID, DEF, CTOR, AST>(
+fn as_assoc_item<'db, ID, DEF, LOC>(
     db: &(dyn HirDatabase + 'db),
-    ctor: CTOR,
+    ctor: impl FnOnce(DEF) -> AssocItem,
     id: ID,
 ) -> Option<AssocItem>
 where
-    ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<AST>>,
+    ID: Lookup<Database<'db> = dyn DefDatabase + 'db, Data = AssocItemLoc<LOC>>,
     DEF: From<ID>,
-    CTOR: FnOnce(DEF) -> AssocItem,
-    AST: ItemTreeModItemNode,
+    LOC: ItemTreeNode,
 {
     match id.lookup(db.upcast()).container {
         ItemContainerId::TraitId(_) | ItemContainerId::ImplId(_) => Some(ctor(DEF::from(id))),
@@ -2610,27 +2614,34 @@ impl AssocItem {
         }
     }
 
-    pub fn containing_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
+    pub fn container_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
         match self.container(db) {
             AssocItemContainer::Trait(t) => Some(t),
             _ => None,
         }
     }
 
-    pub fn containing_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
+    pub fn implemented_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
         match self.container(db) {
             AssocItemContainer::Impl(i) => i.trait_(db),
             _ => None,
         }
     }
 
-    pub fn containing_trait_or_trait_impl(self, db: &dyn HirDatabase) -> Option<Trait> {
+    pub fn container_or_implemented_trait(self, db: &dyn HirDatabase) -> Option<Trait> {
         match self.container(db) {
             AssocItemContainer::Trait(t) => Some(t),
             AssocItemContainer::Impl(i) => i.trait_(db),
         }
     }
 
+    pub fn implementing_ty(self, db: &dyn HirDatabase) -> Option<Type> {
+        match self.container(db) {
+            AssocItemContainer::Impl(i) => Some(i.self_ty(db)),
+            _ => None,
+        }
+    }
+
     pub fn as_function(self) -> Option<Function> {
         match self {
             Self::Function(v) => Some(v),
@@ -2651,6 +2662,22 @@ impl AssocItem {
             _ => None,
         }
     }
+
+    pub fn diagnostics(self, db: &dyn HirDatabase, acc: &mut Vec<AnyDiagnostic>) {
+        match self {
+            AssocItem::Function(func) => {
+                DefWithBody::from(func).diagnostics(db, acc);
+            }
+            AssocItem::Const(const_) => {
+                DefWithBody::from(const_).diagnostics(db, acc);
+            }
+            AssocItem::TypeAlias(type_alias) => {
+                for diag in hir_ty::diagnostics::incorrect_case(db, type_alias.id.into()) {
+                    acc.push(diag.into());
+                }
+            }
+        }
+    }
 }
 
 impl HasVisibility for AssocItem {
@@ -3306,7 +3333,7 @@ impl Impl {
     }
 
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
-        db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect()
+        db.impl_data(self.id).items.iter().map(|&it| it.into()).collect()
     }
 
     pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
@@ -3662,7 +3689,7 @@ impl Type {
             .and_then(|it| {
                 let into_future_fn = it.as_function()?;
                 let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
-                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
+                let into_future_trait = assoc_item.container_or_implemented_trait(db)?;
                 Some(into_future_trait.id)
             })
             .or_else(|| {
@@ -4101,6 +4128,14 @@ impl Type {
         name: Option<&Name>,
         callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>,
     ) {
+        let _p = tracing::span!(
+            tracing::Level::INFO,
+            "iterate_method_candidates_dyn",
+            with_local_impls = traits_in_scope.len(),
+            traits_in_scope = traits_in_scope.len(),
+            ?name,
+        )
+        .entered();
         // There should be no inference vars in types passed here
         let canonical = hir_ty::replace_errors_with_variables(&self.ty);
 
@@ -4122,6 +4157,7 @@ impl Type {
         );
     }
 
+    #[tracing::instrument(skip_all, fields(name = ?name))]
     pub fn iterate_path_candidates<T>(
         &self,
         db: &dyn HirDatabase,
@@ -4150,6 +4186,7 @@ impl Type {
         slot
     }
 
+    #[tracing::instrument(skip_all, fields(name = ?name))]
     fn iterate_path_candidates_dyn(
         &self,
         db: &dyn HirDatabase,
@@ -4463,7 +4500,7 @@ impl Callable {
 }
 
 fn closure_source(db: &dyn HirDatabase, closure: ClosureId) -> Option<ast::ClosureExpr> {
-    let (owner, expr_id) = db.lookup_intern_closure(closure.into());
+    let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into());
     let (_, source_map) = db.body_with_source_map(owner);
     let ast = source_map.expr_syntax(expr_id).ok()?;
     let root = ast.file_syntax(db.upcast());
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 2d41243c20e..55e0d7f3b28 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -96,7 +96,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     let dm_lhs = demorganed.lhs()?;
 
     acc.add_group(
-        &GroupLabel("Apply De Morgan's law".to_string()),
+        &GroupLabel("Apply De Morgan's law".to_owned()),
         AssistId("apply_demorgan", AssistKind::RefactorRewrite),
         "Apply De Morgan's law",
         op_range,
@@ -187,7 +187,7 @@ pub(crate) fn apply_demorgan_iterator(acc: &mut Assists, ctx: &AssistContext<'_>
     let op_range = method_call.syntax().text_range();
     let label = format!("Apply De Morgan's law to `Iterator::{}`", name.text().as_str());
     acc.add_group(
-        &GroupLabel("Apply De Morgan's law".to_string()),
+        &GroupLabel("Apply De Morgan's law".to_owned()),
         AssistId("apply_demorgan_iterator", AssistKind::RefactorRewrite),
         label,
         op_range,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
index d231708c55b..61b7b412177 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs
@@ -163,9 +163,8 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
         return None;
     }
     let assoc = func.as_assoc_item(ctx.sema.db)?;
-    match assoc.container(ctx.sema.db) {
-        hir::AssocItemContainer::Impl(impl_) if impl_.self_ty(ctx.sema.db).is_bool() => {}
-        _ => return None,
+    if !assoc.implementing_ty(ctx.sema.db)?.is_bool() {
+        return None;
     }
 
     let target = mcall.syntax().text_range();
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
index 3f478ee7d39..fbc0b9f6739 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_comment_block.rs
@@ -57,7 +57,7 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
 
                     // Don't introduce trailing whitespace
                     if line.is_empty() {
-                        line_prefix.to_string()
+                        line_prefix.to_owned()
                     } else {
                         format!("{line_prefix} {line}")
                     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
index 6f30ffa622d..e1966d476c5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs
@@ -1,6 +1,9 @@
 use std::iter::once;
 
-use ide_db::syntax_helpers::node_ext::{is_pattern_cond, single_let};
+use ide_db::{
+    syntax_helpers::node_ext::{is_pattern_cond, single_let},
+    ty_filter::TryEnum,
+};
 use syntax::{
     ast::{
         self,
@@ -41,13 +44,35 @@ use crate::{
 // }
 // ```
 pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let if_expr: ast::IfExpr = ctx.find_node_at_offset()?;
+    if let Some(let_stmt) = ctx.find_node_at_offset() {
+        let_stmt_to_guarded_return(let_stmt, acc, ctx)
+    } else if let Some(if_expr) = ctx.find_node_at_offset() {
+        if_expr_to_guarded_return(if_expr, acc, ctx)
+    } else {
+        None
+    }
+}
+
+fn if_expr_to_guarded_return(
+    if_expr: ast::IfExpr,
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
     if if_expr.else_branch().is_some() {
         return None;
     }
 
     let cond = if_expr.condition()?;
 
+    let if_token_range = if_expr.if_token()?.text_range();
+    let if_cond_range = cond.syntax().text_range();
+
+    let cursor_in_range =
+        if_token_range.cover(if_cond_range).contains_range(ctx.selection_trimmed());
+    if !cursor_in_range {
+        return None;
+    }
+
     // Check if there is an IfLet that we can handle.
     let (if_let_pat, cond_expr) = if is_pattern_cond(cond.clone()) {
         let let_ = single_let(cond)?;
@@ -148,6 +173,65 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext<'
     )
 }
 
+fn let_stmt_to_guarded_return(
+    let_stmt: ast::LetStmt,
+    acc: &mut Assists,
+    ctx: &AssistContext<'_>,
+) -> Option<()> {
+    let pat = let_stmt.pat()?;
+    let expr = let_stmt.initializer()?;
+
+    let let_token_range = let_stmt.let_token()?.text_range();
+    let let_pattern_range = pat.syntax().text_range();
+    let cursor_in_range =
+        let_token_range.cover(let_pattern_range).contains_range(ctx.selection_trimmed());
+
+    if !cursor_in_range {
+        return None;
+    }
+
+    let try_enum =
+        ctx.sema.type_of_expr(&expr).and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))?;
+
+    let happy_pattern = try_enum.happy_pattern(pat);
+    let target = let_stmt.syntax().text_range();
+
+    let early_expression: ast::Expr = {
+        let parent_block =
+            let_stmt.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?;
+        let parent_container = parent_block.syntax().parent()?;
+
+        match parent_container.kind() {
+            WHILE_EXPR | LOOP_EXPR | FOR_EXPR => make::expr_continue(None),
+            FN => make::expr_return(None),
+            _ => return None,
+        }
+    };
+
+    acc.add(
+        AssistId("convert_to_guarded_return", AssistKind::RefactorRewrite),
+        "Convert to guarded return",
+        target,
+        |edit| {
+            let let_stmt = edit.make_mut(let_stmt);
+            let let_indent_level = IndentLevel::from_node(let_stmt.syntax());
+
+            let replacement = {
+                let let_else_stmt = make::let_else_stmt(
+                    happy_pattern,
+                    let_stmt.ty(),
+                    expr,
+                    ast::make::tail_only_block_expr(early_expression),
+                );
+                let let_else_stmt = let_else_stmt.indent(let_indent_level);
+                let_else_stmt.syntax().clone_for_update()
+            };
+
+            ted::replace(let_stmt.syntax(), replacement)
+        },
+    )
+}
+
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
@@ -451,6 +535,62 @@ fn main() {
     }
 
     #[test]
+    fn convert_let_stmt_inside_fn() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn foo() -> Option<i32> {
+    None
+}
+
+fn main() {
+    let x$0 = foo();
+}
+"#,
+            r#"
+fn foo() -> Option<i32> {
+    None
+}
+
+fn main() {
+    let Some(x) = foo() else { return };
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn convert_let_stmt_inside_loop() {
+        check_assist(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn foo() -> Option<i32> {
+    None
+}
+
+fn main() {
+    loop {
+        let x$0 = foo();
+    }
+}
+"#,
+            r#"
+fn foo() -> Option<i32> {
+    None
+}
+
+fn main() {
+    loop {
+        let Some(x) = foo() else { continue };
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn convert_arbitrary_if_let_patterns() {
         check_assist(
             convert_to_guarded_return,
@@ -594,4 +734,35 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn ignore_inside_if_stmt() {
+        check_assist_not_applicable(
+            convert_to_guarded_return,
+            r#"
+fn main() {
+    if false {
+        foo()$0;
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn ignore_inside_let_initializer() {
+        check_assist_not_applicable(
+            convert_to_guarded_return,
+            r#"
+//- minicore: option
+fn foo() -> Option<i32> {
+    None
+}
+
+fn main() {
+    let x = foo()$0;
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
index c859e98524e..d2649280467 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_doc_comment.rs
@@ -27,9 +27,7 @@ use crate::{
 pub(crate) fn desugar_doc_comment(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let comment = ctx.find_token_at_offset::<ast::Comment>()?;
     // Only allow doc comments
-    let Some(placement) = comment.kind().doc else {
-        return None;
-    };
+    let placement = comment.kind().doc?;
 
     // Only allow comments which are alone on their line
     if let Some(prev) = comment.syntax().prev_token() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 1eb28626f75..d111005c2ec 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -1,4 +1,4 @@
-use std::iter;
+use std::{iter, ops::RangeInclusive};
 
 use ast::make;
 use either::Either;
@@ -12,27 +12,25 @@ use ide_db::{
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
     search::{FileReference, ReferenceCategory, SearchScope},
+    source_change::SourceChangeBuilder,
     syntax_helpers::node_ext::{
         for_each_tail_expr, preorder_expr, walk_expr, walk_pat, walk_patterns_in_expr,
     },
     FxIndexSet, RootDatabase,
 };
-use itertools::Itertools;
-use stdx::format_to;
 use syntax::{
     ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        AstNode, HasGenericParams,
+        self, edit::IndentLevel, edit_in_place::Indent, AstNode, AstToken, HasGenericParams,
+        HasName,
     },
-    match_ast, ted, AstToken, SyntaxElement,
+    match_ast, ted, SyntaxElement,
     SyntaxKind::{self, COMMENT},
     SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T,
 };
 
 use crate::{
     assist_context::{AssistContext, Assists, TreeMutator},
-    utils::generate_impl_text,
+    utils::generate_impl,
     AssistId,
 };
 
@@ -134,17 +132,65 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             let new_indent = IndentLevel::from_node(&insert_after);
             let old_indent = fun.body.indent_level();
 
-            builder.replace(target_range, make_call(ctx, &fun, old_indent));
+            let insert_after = builder.make_syntax_mut(insert_after);
+
+            let call_expr = make_call(ctx, &fun, old_indent);
+
+            // Map the element range to replace into the mutable version
+            let elements = match &fun.body {
+                FunctionBody::Expr(expr) => {
+                    // expr itself becomes the replacement target
+                    let expr = &builder.make_mut(expr.clone());
+                    let node = SyntaxElement::Node(expr.syntax().clone());
+
+                    node.clone()..=node
+                }
+                FunctionBody::Span { parent, elements, .. } => {
+                    // Map the element range into the mutable versions
+                    let parent = builder.make_mut(parent.clone());
+
+                    let start = parent
+                        .syntax()
+                        .children_with_tokens()
+                        .nth(elements.start().index())
+                        .expect("should be able to find mutable start element");
+
+                    let end = parent
+                        .syntax()
+                        .children_with_tokens()
+                        .nth(elements.end().index())
+                        .expect("should be able to find mutable end element");
+
+                    start..=end
+                }
+            };
 
             let has_impl_wrapper =
                 insert_after.ancestors().any(|a| a.kind() == SyntaxKind::IMPL && a != insert_after);
 
+            let fn_def = format_function(ctx, module, &fun, old_indent).clone_for_update();
+
+            if let Some(cap) = ctx.config.snippet_cap {
+                if let Some(name) = fn_def.name() {
+                    builder.add_tabstop_before(cap, name);
+                }
+            }
+
             let fn_def = match fun.self_param_adt(ctx) {
                 Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
-                    let fn_def = format_function(ctx, module, &fun, old_indent, new_indent + 1);
-                    generate_impl_text(&adt, &fn_def).replace("{\n\n", "{")
+                    fn_def.indent(1.into());
+
+                    let impl_ = generate_impl(&adt);
+                    impl_.indent(new_indent);
+                    impl_.get_or_create_assoc_item_list().add_item(fn_def.into());
+
+                    impl_.syntax().clone()
+                }
+                _ => {
+                    fn_def.indent(new_indent);
+
+                    fn_def.syntax().clone()
                 }
-                _ => format_function(ctx, module, &fun, old_indent, new_indent),
             };
 
             // There are external control flows
@@ -177,12 +223,15 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                 }
             }
 
-            let insert_offset = insert_after.text_range().end();
+            // Replace the call site with the call to the new function
+            fixup_call_site(builder, &fun.body);
+            ted::replace_all(elements, vec![call_expr.into()]);
 
-            match ctx.config.snippet_cap {
-                Some(cap) => builder.insert_snippet(cap, insert_offset, fn_def),
-                None => builder.insert(insert_offset, fn_def),
-            };
+            // Insert the newly extracted function (or impl)
+            ted::insert_all_raw(
+                ted::Position::after(insert_after),
+                vec![make::tokens::whitespace(&format!("\n\n{new_indent}")).into(), fn_def.into()],
+            );
         },
     )
 }
@@ -195,7 +244,7 @@ fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef
 
     let default_name = "fun_name";
 
-    let mut name = default_name.to_string();
+    let mut name = default_name.to_owned();
     let mut counter = 0;
     while names_in_scope.contains(&name) {
         counter += 1;
@@ -225,10 +274,10 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
     if let Some(stmt) = ast::Stmt::cast(node.clone()) {
         return match stmt {
             ast::Stmt::Item(_) => None,
-            ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => Some(FunctionBody::from_range(
+            ast::Stmt::ExprStmt(_) | ast::Stmt::LetStmt(_) => FunctionBody::from_range(
                 node.parent().and_then(ast::StmtList::cast)?,
                 node.text_range(),
-            )),
+            ),
         };
     }
 
@@ -241,7 +290,7 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
         }
 
         // Extract the full statements.
-        return Some(FunctionBody::from_range(stmt_list, selection_range));
+        return FunctionBody::from_range(stmt_list, selection_range);
     }
 
     let expr = ast::Expr::cast(node.clone())?;
@@ -371,7 +420,7 @@ impl RetType {
 #[derive(Debug)]
 enum FunctionBody {
     Expr(ast::Expr),
-    Span { parent: ast::StmtList, text_range: TextRange },
+    Span { parent: ast::StmtList, elements: RangeInclusive<SyntaxElement>, text_range: TextRange },
 }
 
 #[derive(Debug)]
@@ -569,26 +618,38 @@ impl FunctionBody {
         }
     }
 
-    fn from_range(parent: ast::StmtList, selected: TextRange) -> FunctionBody {
+    fn from_range(parent: ast::StmtList, selected: TextRange) -> Option<FunctionBody> {
         let full_body = parent.syntax().children_with_tokens();
 
-        let mut text_range = full_body
+        // Get all of the elements intersecting with the selection
+        let mut stmts_in_selection = full_body
             .filter(|it| ast::Stmt::can_cast(it.kind()) || it.kind() == COMMENT)
-            .map(|element| element.text_range())
-            .filter(|&range| selected.intersect(range).filter(|it| !it.is_empty()).is_some())
-            .reduce(|acc, stmt| acc.cover(stmt));
-
-        if let Some(tail_range) = parent
-            .tail_expr()
-            .map(|it| it.syntax().text_range())
-            .filter(|&it| selected.intersect(it).is_some())
+            .filter(|it| selected.intersect(it.text_range()).filter(|it| !it.is_empty()).is_some());
+
+        let first_element = stmts_in_selection.next();
+
+        // If the tail expr is part of the selection too, make that the last element
+        // Otherwise use the last stmt
+        let last_element = if let Some(tail_expr) =
+            parent.tail_expr().filter(|it| selected.intersect(it.syntax().text_range()).is_some())
         {
-            text_range = Some(match text_range {
-                Some(text_range) => text_range.cover(tail_range),
-                None => tail_range,
-            });
-        }
-        Self::Span { parent, text_range: text_range.unwrap_or(selected) }
+            Some(tail_expr.syntax().clone().into())
+        } else {
+            stmts_in_selection.last()
+        };
+
+        let elements = match (first_element, last_element) {
+            (None, _) => {
+                cov_mark::hit!(extract_function_empty_selection_is_not_applicable);
+                return None;
+            }
+            (Some(first), None) => first.clone()..=first,
+            (Some(first), Some(last)) => first..=last,
+        };
+
+        let text_range = elements.start().text_range().cover(elements.end().text_range());
+
+        Some(Self::Span { parent, elements, text_range })
     }
 
     fn indent_level(&self) -> IndentLevel {
@@ -601,7 +662,7 @@ impl FunctionBody {
     fn tail_expr(&self) -> Option<ast::Expr> {
         match &self {
             FunctionBody::Expr(expr) => Some(expr.clone()),
-            FunctionBody::Span { parent, text_range } => {
+            FunctionBody::Span { parent, text_range, .. } => {
                 let tail_expr = parent.tail_expr()?;
                 text_range.contains_range(tail_expr.syntax().text_range()).then_some(tail_expr)
             }
@@ -611,7 +672,7 @@ impl FunctionBody {
     fn walk_expr(&self, cb: &mut dyn FnMut(ast::Expr)) {
         match self {
             FunctionBody::Expr(expr) => walk_expr(expr, cb),
-            FunctionBody::Span { parent, text_range } => {
+            FunctionBody::Span { parent, text_range, .. } => {
                 parent
                     .statements()
                     .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
@@ -634,7 +695,7 @@ impl FunctionBody {
     fn preorder_expr(&self, cb: &mut dyn FnMut(WalkEvent<ast::Expr>) -> bool) {
         match self {
             FunctionBody::Expr(expr) => preorder_expr(expr, cb),
-            FunctionBody::Span { parent, text_range } => {
+            FunctionBody::Span { parent, text_range, .. } => {
                 parent
                     .statements()
                     .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
@@ -657,7 +718,7 @@ impl FunctionBody {
     fn walk_pat(&self, cb: &mut dyn FnMut(ast::Pat)) {
         match self {
             FunctionBody::Expr(expr) => walk_patterns_in_expr(expr, cb),
-            FunctionBody::Span { parent, text_range } => {
+            FunctionBody::Span { parent, text_range, .. } => {
                 parent
                     .statements()
                     .filter(|stmt| text_range.contains_range(stmt.syntax().text_range()))
@@ -1151,7 +1212,7 @@ impl HasTokenAtOffset for FunctionBody {
     fn token_at_offset(&self, offset: TextSize) -> TokenAtOffset<SyntaxToken> {
         match self {
             FunctionBody::Expr(expr) => expr.syntax().token_at_offset(offset),
-            FunctionBody::Span { parent, text_range } => {
+            FunctionBody::Span { parent, text_range, .. } => {
                 match parent.syntax().token_at_offset(offset) {
                     TokenAtOffset::None => TokenAtOffset::None,
                     TokenAtOffset::Single(t) => {
@@ -1316,7 +1377,19 @@ fn impl_type_name(impl_node: &ast::Impl) -> Option<String> {
     Some(impl_node.self_ty()?.to_string())
 }
 
-fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String {
+/// Fixes up the call site before the target expressions are replaced with the call expression
+fn fixup_call_site(builder: &mut SourceChangeBuilder, body: &FunctionBody) {
+    let parent_match_arm = body.parent().and_then(ast::MatchArm::cast);
+
+    if let Some(parent_match_arm) = parent_match_arm {
+        if parent_match_arm.comma_token().is_none() {
+            let parent_match_arm = builder.make_mut(parent_match_arm);
+            ted::append_child_raw(parent_match_arm.syntax(), make::token(T![,]));
+        }
+    }
+}
+
+fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> SyntaxNode {
     let ret_ty = fun.return_type(ctx);
 
     let args = make::arg_list(fun.params.iter().map(|param| param.to_arg(ctx)));
@@ -1334,44 +1407,45 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St
     if fun.control_flow.is_async {
         call_expr = make::expr_await(call_expr);
     }
-    let expr = handler.make_call_expr(call_expr).indent(indent);
 
-    let mut_modifier = |var: &OutlivedLocal| if var.mut_usage_outside_body { "mut " } else { "" };
+    let expr = handler.make_call_expr(call_expr).clone_for_update();
+    expr.indent(indent);
 
-    let mut buf = String::new();
-    match fun.outliving_locals.as_slice() {
-        [] => {}
+    let outliving_bindings = match fun.outliving_locals.as_slice() {
+        [] => None,
         [var] => {
-            let modifier = mut_modifier(var);
             let name = var.local.name(ctx.db());
-            format_to!(buf, "let {modifier}{} = ", name.display(ctx.db()))
+            let name = make::name(&name.display(ctx.db()).to_string());
+            Some(ast::Pat::IdentPat(make::ident_pat(false, var.mut_usage_outside_body, name)))
         }
         vars => {
-            buf.push_str("let (");
-            let bindings = vars.iter().format_with(", ", |local, f| {
-                let modifier = mut_modifier(local);
-                let name = local.local.name(ctx.db());
-                f(&format_args!("{modifier}{}", name.display(ctx.db())))?;
-                Ok(())
+            let binding_pats = vars.iter().map(|var| {
+                let name = var.local.name(ctx.db());
+                let name = make::name(&name.display(ctx.db()).to_string());
+                make::ident_pat(false, var.mut_usage_outside_body, name).into()
             });
-            format_to!(buf, "{bindings}");
-            buf.push_str(") = ");
+            Some(ast::Pat::TuplePat(make::tuple_pat(binding_pats)))
         }
-    }
+    };
 
-    format_to!(buf, "{expr}");
     let parent_match_arm = fun.body.parent().and_then(ast::MatchArm::cast);
-    let insert_comma = parent_match_arm.as_ref().is_some_and(|it| it.comma_token().is_none());
 
-    if insert_comma {
-        buf.push(',');
-    } else if parent_match_arm.is_none()
+    if let Some(bindings) = outliving_bindings {
+        // with bindings that outlive it
+        make::let_stmt(bindings, None, Some(expr)).syntax().clone_for_update()
+    } else if parent_match_arm.as_ref().is_some() {
+        // as a tail expr for a match arm
+        expr.syntax().clone()
+    } else if parent_match_arm.as_ref().is_none()
         && fun.ret_ty.is_unit()
         && (!fun.outliving_locals.is_empty() || !expr.is_block_like())
     {
-        buf.push(';');
+        // as an expr stmt
+        make::expr_stmt(expr).syntax().clone_for_update()
+    } else {
+        // as a tail expr, or a block
+        expr.syntax().clone()
     }
-    buf
 }
 
 enum FlowHandler {
@@ -1500,42 +1574,25 @@ fn format_function(
     module: hir::Module,
     fun: &Function,
     old_indent: IndentLevel,
-    new_indent: IndentLevel,
-) -> String {
-    let mut fn_def = String::new();
-
-    let fun_name = &fun.name;
+) -> ast::Fn {
+    let fun_name = make::name(&fun.name.text());
     let params = fun.make_param_list(ctx, module);
     let ret_ty = fun.make_ret_ty(ctx, module);
-    let body = make_body(ctx, old_indent, new_indent, fun);
-    let const_kw = if fun.mods.is_const { "const " } else { "" };
-    let async_kw = if fun.control_flow.is_async { "async " } else { "" };
-    let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
+    let body = make_body(ctx, old_indent, fun);
     let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
 
-    format_to!(fn_def, "\n\n{new_indent}{const_kw}{async_kw}{unsafe_kw}");
-    match ctx.config.snippet_cap {
-        Some(_) => format_to!(fn_def, "fn $0{fun_name}"),
-        None => format_to!(fn_def, "fn {fun_name}"),
-    }
-
-    if let Some(generic_params) = generic_params {
-        format_to!(fn_def, "{generic_params}");
-    }
-
-    format_to!(fn_def, "{params}");
-
-    if let Some(ret_ty) = ret_ty {
-        format_to!(fn_def, " {ret_ty}");
-    }
-
-    if let Some(where_clause) = where_clause {
-        format_to!(fn_def, " {where_clause}");
-    }
-
-    format_to!(fn_def, " {body}");
-
-    fn_def
+    make::fn_(
+        None,
+        fun_name,
+        generic_params,
+        where_clause,
+        params,
+        body,
+        ret_ty,
+        fun.control_flow.is_async,
+        fun.mods.is_const,
+        fun.control_flow.is_unsafe,
+    )
 }
 
 fn make_generic_params_and_where_clause(
@@ -1716,12 +1773,7 @@ impl FunType {
     }
 }
 
-fn make_body(
-    ctx: &AssistContext<'_>,
-    old_indent: IndentLevel,
-    new_indent: IndentLevel,
-    fun: &Function,
-) -> ast::BlockExpr {
+fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -> ast::BlockExpr {
     let ret_ty = fun.return_type(ctx);
     let handler = FlowHandler::from_ret_ty(fun, &ret_ty);
 
@@ -1732,7 +1784,7 @@ fn make_body(
             match expr {
                 ast::Expr::BlockExpr(block) => {
                     // If the extracted expression is itself a block, there is no need to wrap it inside another block.
-                    let block = block.dedent(old_indent);
+                    block.dedent(old_indent);
                     let elements = block.stmt_list().map_or_else(
                         || Either::Left(iter::empty()),
                         |stmt_list| {
@@ -1752,13 +1804,13 @@ fn make_body(
                     make::hacky_block_expr(elements, block.tail_expr())
                 }
                 _ => {
-                    let expr = expr.dedent(old_indent).indent(IndentLevel(1));
+                    expr.reindent_to(1.into());
 
                     make::block_expr(Vec::new(), Some(expr))
                 }
             }
         }
-        FunctionBody::Span { parent, text_range } => {
+        FunctionBody::Span { parent, text_range, .. } => {
             let mut elements: Vec<_> = parent
                 .syntax()
                 .children_with_tokens()
@@ -1801,8 +1853,8 @@ fn make_body(
                 .map(|node_or_token| match &node_or_token {
                     syntax::NodeOrToken::Node(node) => match ast::Stmt::cast(node.clone()) {
                         Some(stmt) => {
-                            let indented = stmt.dedent(old_indent).indent(body_indent);
-                            let ast_node = indented.syntax().clone_subtree();
+                            stmt.reindent_to(body_indent);
+                            let ast_node = stmt.syntax().clone_subtree();
                             syntax::NodeOrToken::Node(ast_node)
                         }
                         _ => node_or_token,
@@ -1810,13 +1862,15 @@ fn make_body(
                     _ => node_or_token,
                 })
                 .collect::<Vec<SyntaxElement>>();
-            let tail_expr = tail_expr.map(|expr| expr.dedent(old_indent).indent(body_indent));
+            if let Some(tail_expr) = &mut tail_expr {
+                tail_expr.reindent_to(body_indent);
+            }
 
             make::hacky_block_expr(elements, tail_expr)
         }
     };
 
-    let block = match &handler {
+    match &handler {
         FlowHandler::None => block,
         FlowHandler::Try { kind } => {
             let block = with_default_tail_expr(block, make::expr_unit());
@@ -1851,9 +1905,7 @@ fn make_body(
             let args = make::arg_list(iter::once(tail_expr));
             make::expr_call(ok, args)
         }),
-    };
-
-    block.indent(new_indent)
+    }
 }
 
 fn map_tail_expr(block: ast::BlockExpr, f: impl FnOnce(ast::Expr) -> ast::Expr) -> ast::BlockExpr {
@@ -1897,7 +1949,7 @@ fn with_tail_expr(block: ast::BlockExpr, tail_expr: ast::Expr) -> ast::BlockExpr
 }
 
 fn format_type(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> String {
-    ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_string())
+    ty.display_source_code(ctx.db(), module.into(), true).ok().unwrap_or_else(|| "_".to_owned())
 }
 
 fn make_ty(ty: &hir::Type, ctx: &AssistContext<'_>, module: hir::Module) -> ast::Type {
@@ -2552,6 +2604,20 @@ fn $0fun_name(n: u32) -> u32 {
     }
 
     #[test]
+    fn empty_selection_is_not_applicable() {
+        cov_mark::check!(extract_function_empty_selection_is_not_applicable);
+        check_assist_not_applicable(
+            extract_function,
+            r#"
+fn main() {
+    $0
+
+    $0
+}"#,
+        );
+    }
+
+    #[test]
     fn part_of_expr_stmt() {
         check_assist(
             extract_function,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
index 30c3983dc41..af834c8a53d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_module.rs
@@ -1,7 +1,4 @@
-use std::{
-    collections::{HashMap, HashSet},
-    iter,
-};
+use std::iter;
 
 use hir::{HasSource, HirFileIdExt, ModuleSource};
 use ide_db::{
@@ -9,6 +6,7 @@ use ide_db::{
     base_db::FileId,
     defs::{Definition, NameClass, NameRefClass},
     search::{FileReference, SearchScope},
+    FxHashMap, FxHashSet,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -235,9 +233,9 @@ impl Module {
     fn get_usages_and_record_fields(
         &self,
         ctx: &AssistContext<'_>,
-    ) -> (HashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
+    ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>) {
         let mut adt_fields = Vec::new();
-        let mut refs: HashMap<FileId, Vec<(TextRange, String)>> = HashMap::new();
+        let mut refs: FxHashMap<FileId, Vec<(TextRange, String)>> = FxHashMap::default();
 
         //Here impl is not included as each item inside impl will be tied to the parent of
         //implementing block(a struct, enum, etc), if the parent is in selected module, it will
@@ -320,7 +318,7 @@ impl Module {
         &self,
         ctx: &AssistContext<'_>,
         node_def: Definition,
-        refs_in_files: &mut HashMap<FileId, Vec<(TextRange, String)>>,
+        refs_in_files: &mut FxHashMap<FileId, Vec<(TextRange, String)>>,
     ) {
         for (file_id, references) in node_def.usages(&ctx.sema).all() {
             let source_file = ctx.sema.parse(file_id);
@@ -400,7 +398,7 @@ impl Module {
         ctx: &AssistContext<'_>,
     ) -> Vec<TextRange> {
         let mut import_paths_to_be_removed: Vec<TextRange> = vec![];
-        let mut node_set: HashSet<String> = HashSet::new();
+        let mut node_set: FxHashSet<String> = FxHashSet::default();
 
         for item in self.body_items.clone() {
             for x in item.syntax().descendants() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
index 22d16cf6b36..36d31226512 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs
@@ -115,7 +115,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                     let trailing_ws = if prev_ws.is_some_and(|it| it.text().starts_with('\n')) {
                         format!("\n{indent_to}")
                     } else {
-                        " ".to_string()
+                        " ".to_owned()
                     };
 
                     ted::insert_all_raw(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
index 430cd5b080b..70b5efcb645 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/flip_trait_bound.rs
@@ -59,6 +59,11 @@ mod tests {
     }
 
     #[test]
+    fn flip_trait_bound_works_for_dyn() {
+        check_assist(flip_trait_bound, "fn f<'a>(x: dyn Copy $0+ 'a)", "fn f<'a>(x: dyn 'a + Copy)")
+    }
+
+    #[test]
     fn flip_trait_bound_works_for_struct() {
         check_assist(
             flip_trait_bound,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
index d59bd71d312..4f2df5633c3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_methods.rs
@@ -1,7 +1,5 @@
-use std::collections::HashSet;
-
 use hir::{self, HasCrate, HasVisibility};
-use ide_db::path_transform::PathTransform;
+use ide_db::{path_transform::PathTransform, FxHashSet};
 use syntax::{
     ast::{
         self, edit_in_place::Indent, make, AstNode, HasGenericParams, HasName, HasVisibility as _,
@@ -71,7 +69,7 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
 
     let sema_field_ty = ctx.sema.resolve_type(&field_ty)?;
     let mut methods = vec![];
-    let mut seen_names = HashSet::new();
+    let mut seen_names = FxHashSet::default();
 
     for ty in sema_field_ty.autoderef(ctx.db()) {
         let krate = ty.krate(ctx.db());
@@ -163,13 +161,13 @@ pub(crate) fn generate_delegate_methods(acc: &mut Assists, ctx: &AssistContext<'
                     Some(impl_def) => edit.make_mut(impl_def),
                     None => {
                         let name = &strukt_name.to_string();
-                        let params = strukt.generic_param_list();
-                        let ty_params = params;
+                        let ty_params = strukt.generic_param_list();
+                        let ty_args = ty_params.as_ref().map(|it| it.to_generic_args());
                         let where_clause = strukt.where_clause();
 
                         let impl_def = make::impl_(
                             ty_params,
-                            None,
+                            ty_args,
                             make::ty_path(make::ext::ident_path(name)),
                             where_clause,
                             None,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
index 898bd01291a..7a60287f923 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_delegate_trait.rs
@@ -502,9 +502,7 @@ fn generate_args_for_impl(
     trait_params: &Option<GenericParamList>,
     old_trait_args: &FxHashSet<String>,
 ) -> Option<ast::GenericArgList> {
-    let Some(old_impl_args) = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args()) else {
-        return None;
-    };
+    let old_impl_args = old_impl_gpl.map(|gpl| gpl.to_generic_args().generic_args())?;
     // Create pairs of the args of `self_ty` and corresponding `field_ty` to
     // form the substitution list
     let mut arg_substs = FxHashMap::default();
@@ -958,7 +956,8 @@ where
 impl<T> AnotherTrait for S<T>
 where
     T: AnotherTrait,
-{}"#,
+{
+}"#,
         );
     }
 
@@ -1448,7 +1447,8 @@ where
 impl<T> AnotherTrait for S<T>
 where
     T: AnotherTrait,
-{}"#,
+{
+}"#,
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
index f298ce8916d..38b24fd19ca 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_documentation_template.rs
@@ -364,7 +364,7 @@ fn is_in_trait_impl(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
     ctx.sema
         .to_def(ast_func)
         .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
-        .and_then(|assoc_item| assoc_item.containing_trait_impl(ctx.db()))
+        .and_then(|assoc_item| assoc_item.implemented_trait(ctx.db()))
         .is_some()
 }
 
@@ -373,7 +373,7 @@ fn is_in_trait_def(ast_func: &ast::Fn, ctx: &AssistContext<'_>) -> bool {
     ctx.sema
         .to_def(ast_func)
         .and_then(|hir_func| hir_func.as_assoc_item(ctx.db()))
-        .and_then(|assoc_item| assoc_item.containing_trait(ctx.db()))
+        .and_then(|assoc_item| assoc_item.container_trait(ctx.db()))
         .is_some()
 }
 
@@ -416,9 +416,9 @@ fn arguments_from_params(param_list: &ast::ParamList) -> String {
                 true => format!("&mut {name}"),
                 false => name.to_string(),
             },
-            None => "_".to_string(),
+            None => "_".to_owned(),
         },
-        _ => "_".to_string(),
+        _ => "_".to_owned(),
     });
     args_iter.format(", ").to_string()
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
index 681f8c1fcf5..7faf2d5b132 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
@@ -162,7 +162,7 @@ fn make_record_field_list(
 fn name_from_field(field: &ast::RecordExprField) -> ast::Name {
     let text = match field.name_ref() {
         Some(it) => it.to_string(),
-        None => name_from_field_shorthand(field).unwrap_or("unknown".to_string()),
+        None => name_from_field_shorthand(field).unwrap_or("unknown".to_owned()),
     };
     make::name(&text)
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index 50528e1caaa..fe2f8ed6417 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -202,7 +202,7 @@ fn get_adt_source(
     let file = ctx.sema.parse(range.file_id);
     let adt_source =
         ctx.sema.find_node_at_offset_with_macros(file.syntax(), range.range.start())?;
-    find_struct_impl(ctx, &adt_source, &[fn_name.to_string()]).map(|impl_| (impl_, range.file_id))
+    find_struct_impl(ctx, &adt_source, &[fn_name.to_owned()]).map(|impl_| (impl_, range.file_id))
 }
 
 struct FunctionTemplate {
@@ -908,7 +908,7 @@ fn filter_unnecessary_bounds(
         }
     }
 
-    let starting_nodes = necessary_params.iter().map(|param| param_map[param]);
+    let starting_nodes = necessary_params.iter().flat_map(|param| param_map.get(param).copied());
     let reachable = graph.compute_reachable_nodes(starting_nodes);
 
     // Not pretty, but effective. If only there were `Vec::retain_index()`...
@@ -1007,7 +1007,7 @@ fn fn_arg_name(sema: &Semantics<'_, RootDatabase>, arg_expr: &ast::Expr) -> Stri
             name
         }
         Some(name) => name,
-        None => "arg".to_string(),
+        None => "arg".to_owned(),
     }
 }
 
@@ -1033,7 +1033,7 @@ fn fn_arg_type(
         if ty.is_reference() || ty.is_mutable_reference() {
             let famous_defs = &FamousDefs(&ctx.sema, ctx.sema.scope(fn_arg.syntax())?.krate());
             convert_reference_type(ty.strip_references(), ctx.db(), famous_defs)
-                .map(|conversion| conversion.convert_type(ctx.db()))
+                .map(|conversion| conversion.convert_type(ctx.db()).to_string())
                 .or_else(|| ty.display_source_code(ctx.db(), target_module.into(), true).ok())
         } else {
             ty.display_source_code(ctx.db(), target_module.into(), true).ok()
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
index 79307fcec5a..e90a032f1cb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_getter_or_setter.rs
@@ -1,12 +1,12 @@
 use ide_db::{famous_defs::FamousDefs, source_change::SourceChangeBuilder};
 use stdx::{format_to, to_lower_snake_case};
 use syntax::{
-    ast::{self, AstNode, HasName, HasVisibility},
-    TextRange,
+    ast::{self, edit_in_place::Indent, make, AstNode, HasName, HasVisibility},
+    ted, TextRange,
 };
 
 use crate::{
-    utils::{convert_reference_type, find_impl_block_end, find_struct_impl, generate_impl_text},
+    utils::{convert_reference_type, find_struct_impl, generate_impl},
     AssistContext, AssistId, AssistKind, Assists, GroupLabel,
 };
 
@@ -75,7 +75,7 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
 // Generate a getter method.
 //
 // ```
-// # //- minicore: as_ref
+// # //- minicore: as_ref, deref
 // # pub struct String;
 // # impl AsRef<str> for String {
 // #     fn as_ref(&self) -> &str {
@@ -83,6 +83,13 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
 // #     }
 // # }
 // #
+// # impl core::ops::Deref for String {
+// #     type Target = str;
+// #     fn deref(&self) -> &Self::Target {
+// #         ""
+// #     }
+// # }
+// #
 // struct Person {
 //     nam$0e: String,
 // }
@@ -96,13 +103,20 @@ pub(crate) fn generate_setter(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
 // #     }
 // # }
 // #
+// # impl core::ops::Deref for String {
+// #     type Target = str;
+// #     fn deref(&self) -> &Self::Target {
+// #         ""
+// #     }
+// # }
+// #
 // struct Person {
 //     name: String,
 // }
 //
 // impl Person {
 //     fn $0name(&self) -> &str {
-//         self.name.as_ref()
+//         &self.name
 //     }
 // }
 // ```
@@ -200,14 +214,14 @@ fn generate_getter_from_info(
     ctx: &AssistContext<'_>,
     info: &AssistInfo,
     record_field_info: &RecordFieldInfo,
-) -> String {
-    let mut buf = String::with_capacity(512);
-
-    let vis = info.strukt.visibility().map_or(String::new(), |v| format!("{v} "));
+) -> ast::Fn {
     let (ty, body) = if matches!(info.assist_type, AssistType::MutGet) {
         (
-            format!("&mut {}", record_field_info.field_ty),
-            format!("&mut self.{}", record_field_info.field_name),
+            make::ty_ref(record_field_info.field_ty.clone(), true),
+            make::expr_ref(
+                make::expr_field(make::ext::expr_self(), &record_field_info.field_name.text()),
+                true,
+            ),
         )
     } else {
         (|| {
@@ -226,41 +240,52 @@ fn generate_getter_from_info(
         })()
         .unwrap_or_else(|| {
             (
-                format!("&{}", record_field_info.field_ty),
-                format!("&self.{}", record_field_info.field_name),
+                make::ty_ref(record_field_info.field_ty.clone(), false),
+                make::expr_ref(
+                    make::expr_field(make::ext::expr_self(), &record_field_info.field_name.text()),
+                    false,
+                ),
             )
         })
     };
 
-    format_to!(
-        buf,
-        "    {}fn {}(&{}self) -> {} {{
-        {}
-    }}",
-        vis,
-        record_field_info.fn_name,
-        matches!(info.assist_type, AssistType::MutGet).then_some("mut ").unwrap_or_default(),
-        ty,
-        body,
-    );
+    let self_param = if matches!(info.assist_type, AssistType::MutGet) {
+        make::mut_self_param()
+    } else {
+        make::self_param()
+    };
+
+    let strukt = &info.strukt;
+    let fn_name = make::name(&record_field_info.fn_name);
+    let params = make::param_list(Some(self_param), []);
+    let ret_type = Some(make::ret_type(ty));
+    let body = make::block_expr([], Some(body));
 
-    buf
+    make::fn_(strukt.visibility(), fn_name, None, None, params, body, ret_type, false, false, false)
 }
 
-fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldInfo) -> String {
-    let mut buf = String::with_capacity(512);
+fn generate_setter_from_info(info: &AssistInfo, record_field_info: &RecordFieldInfo) -> ast::Fn {
     let strukt = &info.strukt;
-    let fn_name = &record_field_info.fn_name;
+    let field_name = &record_field_info.fn_name;
+    let fn_name = make::name(&format!("set_{field_name}"));
     let field_ty = &record_field_info.field_ty;
-    let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
-    format_to!(
-        buf,
-        "    {vis}fn set_{fn_name}(&mut self, {fn_name}: {field_ty}) {{
-        self.{fn_name} = {fn_name};
-    }}"
-    );
 
-    buf
+    // Make the param list
+    // `(&mut self, $field_name: $field_ty)`
+    let field_param =
+        make::param(make::ident_pat(false, false, make::name(field_name)).into(), field_ty.clone());
+    let params = make::param_list(Some(make::mut_self_param()), [field_param]);
+
+    // Make the assignment body
+    // `self.$field_name = $field_name`
+    let self_expr = make::ext::expr_self();
+    let lhs = make::expr_field(self_expr, field_name);
+    let rhs = make::expr_path(make::ext::ident_path(field_name));
+    let assign_stmt = make::expr_stmt(make::expr_assignment(lhs, rhs));
+    let body = make::block_expr([assign_stmt.into()], None);
+
+    // Make the setter fn
+    make::fn_(strukt.visibility(), fn_name, None, None, params, body, None, false, false, false)
 }
 
 fn extract_and_parse(
@@ -353,74 +378,45 @@ fn build_source_change(
 ) {
     let record_fields_count = info_of_record_fields.len();
 
-    let mut buf = String::with_capacity(512);
+    let impl_def = if let Some(impl_def) = &assist_info.impl_def {
+        // We have an existing impl to add to
+        builder.make_mut(impl_def.clone())
+    } else {
+        // Generate a new impl to add the methods to
+        let impl_def = generate_impl(&ast::Adt::Struct(assist_info.strukt.clone()));
 
-    // Check if an impl exists
-    if let Some(impl_def) = &assist_info.impl_def {
-        // Check if impl is empty
-        if let Some(assoc_item_list) = impl_def.assoc_item_list() {
-            if assoc_item_list.assoc_items().next().is_some() {
-                // If not empty then only insert a new line
-                buf.push('\n');
-            }
-        }
-    }
+        // Insert it after the adt
+        let strukt = builder.make_mut(assist_info.strukt.clone());
+
+        ted::insert_all_raw(
+            ted::Position::after(strukt.syntax()),
+            vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+        );
+
+        impl_def
+    };
+
+    let assoc_item_list = impl_def.get_or_create_assoc_item_list();
 
     for (i, record_field_info) in info_of_record_fields.iter().enumerate() {
-        // this buf inserts a newline at the end of a getter
-        // automatically, if one wants to add one more newline
-        // for separating it from other assoc items, that needs
-        // to be handled separately
-        let mut getter_buf = match assist_info.assist_type {
+        // Make the new getter or setter fn
+        let new_fn = match assist_info.assist_type {
             AssistType::Set => generate_setter_from_info(&assist_info, record_field_info),
             _ => generate_getter_from_info(ctx, &assist_info, record_field_info),
-        };
-
-        // Insert `$0` only for last getter we generate
-        if i == record_fields_count - 1 && ctx.config.snippet_cap.is_some() {
-            getter_buf = getter_buf.replacen("fn ", "fn $0", 1);
-        }
-
-        // For first element we do not merge with '\n', as
-        // that can be inserted by impl_def check defined
-        // above, for other cases which are:
-        //
-        // - impl exists but it empty, here we would ideally
-        // not want to keep newline between impl <struct> {
-        // and fn <fn-name>() { line
-        //
-        // - next if impl itself does not exist, in this
-        // case we ourselves generate a new impl and that
-        // again ends up with the same reasoning as above
-        // for not keeping newline
-        if i == 0 {
-            buf = buf + &getter_buf;
-        } else {
-            buf = buf + "\n" + &getter_buf;
         }
-
-        // We don't insert a new line at the end of
-        // last getter as it will end up in the end
-        // of an impl where we would not like to keep
-        // getter and end of impl ( i.e. `}` ) with an
-        // extra line for no reason
-        if i < record_fields_count - 1 {
-            buf += "\n";
+        .clone_for_update();
+        new_fn.indent(1.into());
+
+        // Insert a tabstop only for last method we generate
+        if i == record_fields_count - 1 {
+            if let Some(cap) = ctx.config.snippet_cap {
+                if let Some(name) = new_fn.name() {
+                    builder.add_tabstop_before(cap, name);
+                }
+            }
         }
-    }
-
-    let start_offset = assist_info
-        .impl_def
-        .as_ref()
-        .and_then(|impl_def| find_impl_block_end(impl_def.to_owned(), &mut buf))
-        .unwrap_or_else(|| {
-            buf = generate_impl_text(&ast::Adt::Struct(assist_info.strukt.clone()), &buf);
-            assist_info.strukt.syntax().text_range().end()
-        });
 
-    match ctx.config.snippet_cap {
-        Some(cap) => builder.insert_snippet(cap, start_offset, buf),
-        None => builder.insert(start_offset, buf),
+        assoc_item_list.add_item(new_fn.clone().into());
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
index d52d778d344..821783c2831 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_impl.rs
@@ -1,10 +1,10 @@
-use syntax::ast::{self, AstNode, HasName};
-
-use crate::{
-    utils::{generate_impl_text, generate_trait_impl_text_intransitive},
-    AssistContext, AssistId, AssistKind, Assists,
+use syntax::{
+    ast::{self, make, AstNode, HasName},
+    ted,
 };
 
+use crate::{utils, AssistContext, AssistId, AssistKind, Assists};
+
 // Assist: generate_impl
 //
 // Adds a new inherent impl for a type.
@@ -20,9 +20,7 @@ use crate::{
 //     data: T,
 // }
 //
-// impl<T: Clone> Ctx<T> {
-//     $0
-// }
+// impl<T: Clone> Ctx<T> {$0}
 // ```
 pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
@@ -38,17 +36,22 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
         format!("Generate impl for `{name}`"),
         target,
         |edit| {
-            let start_offset = nominal.syntax().text_range().end();
-            match ctx.config.snippet_cap {
-                Some(cap) => {
-                    let snippet = generate_impl_text(&nominal, "    $0");
-                    edit.insert_snippet(cap, start_offset, snippet);
-                }
-                None => {
-                    let snippet = generate_impl_text(&nominal, "");
-                    edit.insert(start_offset, snippet);
+            // Generate the impl
+            let impl_ = utils::generate_impl(&nominal);
+
+            // Add a tabstop after the left curly brace
+            if let Some(cap) = ctx.config.snippet_cap {
+                if let Some(l_curly) = impl_.assoc_item_list().and_then(|it| it.l_curly_token()) {
+                    edit.add_tabstop_after_token(cap, l_curly);
                 }
             }
+
+            // Add the impl after the adt
+            let nominal = edit.make_mut(nominal);
+            ted::insert_all_raw(
+                ted::Position::after(nominal.syntax()),
+                vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
+            );
         },
     )
 }
@@ -68,9 +71,7 @@ pub(crate) fn generate_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Optio
 //     data: T,
 // }
 //
-// impl<T: Clone> $0 for Ctx<T> {
-//
-// }
+// impl<T: Clone> ${0:_} for Ctx<T> {}
 // ```
 pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let nominal = ctx.find_node_at_offset::<ast::Adt>()?;
@@ -86,17 +87,22 @@ pub(crate) fn generate_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) ->
         format!("Generate trait impl for `{name}`"),
         target,
         |edit| {
-            let start_offset = nominal.syntax().text_range().end();
-            match ctx.config.snippet_cap {
-                Some(cap) => {
-                    let snippet = generate_trait_impl_text_intransitive(&nominal, "$0", "");
-                    edit.insert_snippet(cap, start_offset, snippet);
-                }
-                None => {
-                    let text = generate_trait_impl_text_intransitive(&nominal, "", "");
-                    edit.insert(start_offset, text);
+            // Generate the impl
+            let impl_ = utils::generate_trait_impl_intransitive(&nominal, make::ty_placeholder());
+
+            // Make the trait type a placeholder snippet
+            if let Some(cap) = ctx.config.snippet_cap {
+                if let Some(trait_) = impl_.trait_() {
+                    edit.add_placeholder_snippet(cap, trait_);
                 }
             }
+
+            // Add the impl after the adt
+            let nominal = edit.make_mut(nominal);
+            ted::insert_all_raw(
+                ted::Position::after(nominal.syntax()),
+                vec![make::tokens::blank_line().into(), impl_.syntax().clone().into()],
+            );
         },
     )
 }
@@ -117,9 +123,7 @@ mod tests {
             r#"
                 struct Foo {}
 
-                impl Foo {
-                    $0
-                }
+                impl Foo {$0}
             "#,
         );
     }
@@ -134,9 +138,7 @@ mod tests {
             r#"
                 struct Foo<T: Clone> {}
 
-                impl<T: Clone> Foo<T> {
-                    $0
-                }
+                impl<T: Clone> Foo<T> {$0}
             "#,
         );
     }
@@ -151,9 +153,7 @@ mod tests {
             r#"
                 struct Foo<'a, T: Foo<'a>> {}
 
-                impl<'a, T: Foo<'a>> Foo<'a, T> {
-                    $0
-                }
+                impl<'a, T: Foo<'a>> Foo<'a, T> {$0}
             "#,
         );
     }
@@ -171,9 +171,7 @@ mod tests {
                 struct Foo<'a, T: Foo<'a>> {}
 
                 #[cfg(feature = "foo")]
-                impl<'a, T: Foo<'a>> Foo<'a, T> {
-                    $0
-                }
+                impl<'a, T: Foo<'a>> Foo<'a, T> {$0}
             "#,
         );
     }
@@ -188,9 +186,7 @@ mod tests {
             r#"
                 struct Defaulted<T = i32> {}
 
-                impl<T> Defaulted<T> {
-                    $0
-                }
+                impl<T> Defaulted<T> {$0}
             "#,
         );
     }
@@ -205,9 +201,7 @@ mod tests {
             r#"
                 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
 
-                impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {
-                    $0
-                }
+                impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> Defaulted<'a, 'b, T, S> {$0}
             "#,
         );
     }
@@ -222,9 +216,7 @@ mod tests {
             r#"
                 struct Defaulted<const N: i32 = 0> {}
 
-                impl<const N: i32> Defaulted<N> {
-                    $0
-                }
+                impl<const N: i32> Defaulted<N> {$0}
             "#,
         );
     }
@@ -254,8 +246,7 @@ mod tests {
                 impl<T> Struct<T>
                 where
                     T: Trait,
-                {
-                    $0
+                {$0
                 }
             "#,
         );
@@ -285,9 +276,7 @@ mod tests {
             r#"
                 struct Foo {}
 
-                impl $0 for Foo {
-
-                }
+                impl ${0:_} for Foo {}
             "#,
         );
     }
@@ -302,9 +291,7 @@ mod tests {
             r#"
                 struct Foo<T: Clone> {}
 
-                impl<T: Clone> $0 for Foo<T> {
-
-                }
+                impl<T: Clone> ${0:_} for Foo<T> {}
             "#,
         );
     }
@@ -319,9 +306,7 @@ mod tests {
             r#"
                 struct Foo<'a, T: Foo<'a>> {}
 
-                impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
-
-                }
+                impl<'a, T: Foo<'a>> ${0:_} for Foo<'a, T> {}
             "#,
         );
     }
@@ -339,9 +324,7 @@ mod tests {
                 struct Foo<'a, T: Foo<'a>> {}
 
                 #[cfg(feature = "foo")]
-                impl<'a, T: Foo<'a>> $0 for Foo<'a, T> {
-
-                }
+                impl<'a, T: Foo<'a>> ${0:_} for Foo<'a, T> {}
             "#,
         );
     }
@@ -356,9 +339,7 @@ mod tests {
             r#"
                 struct Defaulted<T = i32> {}
 
-                impl<T> $0 for Defaulted<T> {
-
-                }
+                impl<T> ${0:_} for Defaulted<T> {}
             "#,
         );
     }
@@ -373,9 +354,7 @@ mod tests {
             r#"
                 struct Defaulted<'a, 'b: 'a, T: Debug + Clone + 'a + 'b = String, const S: usize> {}
 
-                impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> $0 for Defaulted<'a, 'b, T, S> {
-
-                }
+                impl<'a, 'b: 'a, T: Debug + Clone + 'a + 'b, const S: usize> ${0:_} for Defaulted<'a, 'b, T, S> {}
             "#,
         );
     }
@@ -390,9 +369,7 @@ mod tests {
             r#"
                 struct Defaulted<const N: i32 = 0> {}
 
-                impl<const N: i32> $0 for Defaulted<N> {
-
-                }
+                impl<const N: i32> ${0:_} for Defaulted<N> {}
             "#,
         );
     }
@@ -419,11 +396,10 @@ mod tests {
                     inner: T,
                 }
 
-                impl<T> $0 for Struct<T>
+                impl<T> ${0:_} for Struct<T>
                 where
                     T: Trait,
                 {
-
                 }
             "#,
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
index 6bfc69b0ada..4d369e705e8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_is_empty_from_len.rs
@@ -79,7 +79,7 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext<
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }"#
-            .to_string();
+            .to_owned();
             builder.insert(range.end(), code)
         },
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index 7bfd599660d..22c75cd5eef 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -1,12 +1,13 @@
 use ide_db::{
     imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
 };
-use itertools::Itertools;
-use stdx::format_to;
-use syntax::ast::{self, AstNode, HasName, HasVisibility, StructKind};
+use syntax::{
+    ast::{self, edit_in_place::Indent, make, AstNode, HasName, HasVisibility, StructKind},
+    ted,
+};
 
 use crate::{
-    utils::{find_impl_block_start, find_struct_impl, generate_impl_text},
+    utils::{find_struct_impl, generate_impl},
     AssistContext, AssistId, AssistKind, Assists,
 };
 
@@ -26,7 +27,9 @@ use crate::{
 // }
 //
 // impl<T: Clone> Ctx<T> {
-//     fn $0new(data: T) -> Self { Self { data } }
+//     fn $0new(data: T) -> Self {
+//         Self { data }
+//     }
 // }
 // ```
 pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
@@ -46,14 +49,6 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
 
     let target = strukt.syntax().text_range();
     acc.add(AssistId("generate_new", AssistKind::Generate), "Generate `new`", target, |builder| {
-        let mut buf = String::with_capacity(512);
-
-        if impl_def.is_some() {
-            buf.push('\n');
-        }
-
-        let vis = strukt.visibility().map_or(String::new(), |v| format!("{v} "));
-
         let trivial_constructors = field_list
             .fields()
             .map(|f| {
@@ -76,54 +71,79 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                     &ty,
                 )?;
 
-                Some(format!("{name}: {expr}"))
+                Some(make::record_expr_field(make::name_ref(&name.text()), Some(expr)))
             })
             .collect::<Vec<_>>();
 
-        let params = field_list
-            .fields()
-            .enumerate()
-            .filter_map(|(i, f)| {
-                if trivial_constructors[i].is_none() {
-                    let name = f.name()?;
-                    let ty = f.ty()?;
-
-                    Some(format!("{name}: {ty}"))
-                } else {
-                    None
-                }
-            })
-            .format(", ");
+        let params = field_list.fields().enumerate().filter_map(|(i, f)| {
+            if trivial_constructors[i].is_none() {
+                let name = f.name()?;
+                let ty = f.ty()?;
 
-        let fields = field_list
-            .fields()
-            .enumerate()
-            .filter_map(|(i, f)| {
-                let constructor = trivial_constructors[i].clone();
-                if constructor.is_some() {
-                    constructor
-                } else {
-                    Some(f.name()?.to_string())
-                }
-            })
-            .format(", ");
-
-        format_to!(buf, "    {vis}fn new({params}) -> Self {{ Self {{ {fields} }} }}");
-
-        let start_offset = impl_def
-            .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
-            .unwrap_or_else(|| {
-                buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
-                strukt.syntax().text_range().end()
-            });
-
-        match ctx.config.snippet_cap {
-            None => builder.insert(start_offset, buf),
-            Some(cap) => {
-                buf = buf.replace("fn new", "fn $0new");
-                builder.insert_snippet(cap, start_offset, buf);
+                Some(make::param(make::ident_pat(false, false, name).into(), ty))
+            } else {
+                None
+            }
+        });
+        let params = make::param_list(None, params);
+
+        let fields = field_list.fields().enumerate().filter_map(|(i, f)| {
+            let constructor = trivial_constructors[i].clone();
+            if constructor.is_some() {
+                constructor
+            } else {
+                Some(make::record_expr_field(make::name_ref(&f.name()?.text()), None))
+            }
+        });
+        let fields = make::record_expr_field_list(fields);
+
+        let record_expr = make::record_expr(make::ext::ident_path("Self"), fields);
+        let body = make::block_expr(None, Some(record_expr.into()));
+
+        let ret_type = make::ret_type(make::ty_path(make::ext::ident_path("Self")));
+
+        let fn_ = make::fn_(
+            strukt.visibility(),
+            make::name("new"),
+            None,
+            None,
+            params,
+            body,
+            Some(ret_type),
+            false,
+            false,
+            false,
+        )
+        .clone_for_update();
+        fn_.indent(1.into());
+
+        // Add a tabstop before the name
+        if let Some(cap) = ctx.config.snippet_cap {
+            if let Some(name) = fn_.name() {
+                builder.add_tabstop_before(cap, name);
             }
         }
+
+        // Get the mutable version of the impl to modify
+        let impl_def = if let Some(impl_def) = impl_def {
+            builder.make_mut(impl_def)
+        } else {
+            // Generate a new impl to add the method to
+            let impl_def = generate_impl(&ast::Adt::Struct(strukt.clone()));
+
+            // Insert it after the adt
+            let strukt = builder.make_mut(strukt.clone());
+
+            ted::insert_all_raw(
+                ted::Position::after(strukt.syntax()),
+                vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+            );
+
+            impl_def
+        };
+
+        // Add the `new` method at the start of the impl
+        impl_def.get_or_create_assoc_item_list().add_item_at_start(fn_.into());
     })
 }
 
@@ -148,7 +168,9 @@ struct Empty;
 struct Foo { empty: Empty }
 
 impl Foo {
-    fn $0new() -> Self { Self { empty: Empty } }
+    fn $0new() -> Self {
+        Self { empty: Empty }
+    }
 }
 "#,
         );
@@ -165,7 +187,9 @@ struct Empty;
 struct Foo { baz: String, empty: Empty }
 
 impl Foo {
-    fn $0new(baz: String) -> Self { Self { baz, empty: Empty } }
+    fn $0new(baz: String) -> Self {
+        Self { baz, empty: Empty }
+    }
 }
 "#,
         );
@@ -182,7 +206,9 @@ enum Empty { Bar }
 struct Foo { empty: Empty }
 
 impl Foo {
-    fn $0new() -> Self { Self { empty: Empty::Bar } }
+    fn $0new() -> Self {
+        Self { empty: Empty::Bar }
+    }
 }
 "#,
         );
@@ -201,7 +227,9 @@ struct Empty {}
 struct Foo { empty: Empty }
 
 impl Foo {
-    fn $0new(empty: Empty) -> Self { Self { empty } }
+    fn $0new(empty: Empty) -> Self {
+        Self { empty }
+    }
 }
 "#,
         );
@@ -218,7 +246,9 @@ enum Empty { Bar {} }
 struct Foo { empty: Empty }
 
 impl Foo {
-    fn $0new(empty: Empty) -> Self { Self { empty } }
+    fn $0new(empty: Empty) -> Self {
+        Self { empty }
+    }
 }
 "#,
         );
@@ -235,7 +265,9 @@ struct Foo {$0}
 struct Foo {}
 
 impl Foo {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -248,7 +280,9 @@ struct Foo<T: Clone> {$0}
 struct Foo<T: Clone> {}
 
 impl<T: Clone> Foo<T> {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -261,7 +295,9 @@ struct Foo<'a, T: Foo<'a>> {$0}
 struct Foo<'a, T: Foo<'a>> {}
 
 impl<'a, T: Foo<'a>> Foo<'a, T> {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -274,7 +310,9 @@ struct Foo { baz: String $0}
 struct Foo { baz: String }
 
 impl Foo {
-    fn $0new(baz: String) -> Self { Self { baz } }
+    fn $0new(baz: String) -> Self {
+        Self { baz }
+    }
 }
 "#,
         );
@@ -287,7 +325,9 @@ struct Foo { baz: String, qux: Vec<i32> $0}
 struct Foo { baz: String, qux: Vec<i32> }
 
 impl Foo {
-    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
+    fn $0new(baz: String, qux: Vec<i32>) -> Self {
+        Self { baz, qux }
+    }
 }
 "#,
         );
@@ -304,7 +344,9 @@ struct Foo { pub baz: String, pub qux: Vec<i32> $0}
 struct Foo { pub baz: String, pub qux: Vec<i32> }
 
 impl Foo {
-    fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
+    fn $0new(baz: String, qux: Vec<i32>) -> Self {
+        Self { baz, qux }
+    }
 }
 "#,
         );
@@ -323,7 +365,9 @@ impl Foo {}
 struct Foo {}
 
 impl Foo {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -340,7 +384,9 @@ impl Foo {
 struct Foo {}
 
 impl Foo {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 
     fn qux(&self) {}
 }
@@ -363,7 +409,9 @@ impl Foo {
 struct Foo {}
 
 impl Foo {
-    fn $0new() -> Self { Self {  } }
+    fn $0new() -> Self {
+        Self {  }
+    }
 
     fn qux(&self) {}
     fn baz() -> i32 {
@@ -385,7 +433,9 @@ pub struct Foo {$0}
 pub struct Foo {}
 
 impl Foo {
-    pub fn $0new() -> Self { Self {  } }
+    pub fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -398,7 +448,9 @@ pub(crate) struct Foo {$0}
 pub(crate) struct Foo {}
 
 impl Foo {
-    pub(crate) fn $0new() -> Self { Self {  } }
+    pub(crate) fn $0new() -> Self {
+        Self {  }
+    }
 }
 "#,
         );
@@ -493,7 +545,9 @@ pub struct Source<T> {
 }
 
 impl<T> Source<T> {
-    pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }
+    pub fn $0new(file_id: HirFileId, ast: T) -> Self {
+        Self { file_id, ast }
+    }
 
     pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
         Source { file_id: self.file_id, ast: f(self.ast) }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
index 8881aa69f29..24094de22c8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_trait_from_impl.rs
@@ -118,7 +118,7 @@ pub(crate) fn generate_trait_from_impl(acc: &mut Assists, ctx: &AssistContext<'_
             let arg_list = if let Some(genpars) = impl_ast.generic_param_list() {
                 genpars.to_generic_args().to_string()
             } else {
-                "".to_string()
+                "".to_owned()
             };
 
             if let Some(snippet_cap) = ctx.config.snippet_cap {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
index 4ba33ada48c..11b22b65205 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_call.rs
@@ -415,7 +415,24 @@ fn inline(
         let expr: &ast::Expr = expr;
 
         let mut insert_let_stmt = || {
-            let ty = sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty.clone());
+            let param_ty = match param_ty {
+                None => None,
+                Some(param_ty) => {
+                    if sema.hir_file_for(param_ty.syntax()).is_macro() {
+                        if let Some(param_ty) =
+                            ast::Type::cast(insert_ws_into(param_ty.syntax().clone()))
+                        {
+                            Some(param_ty)
+                        } else {
+                            Some(param_ty.clone_for_update())
+                        }
+                    } else {
+                        Some(param_ty.clone_for_update())
+                    }
+                }
+            };
+            let ty: Option<syntax::ast::Type> =
+                sema.type_of_expr(expr).filter(TypeInfo::has_adjustment).and(param_ty);
 
             let is_self = param
                 .name(sema.db)
@@ -1735,4 +1752,47 @@ pub fn main() {
 "#,
         )
     }
+
+    #[test]
+    fn inline_call_with_reference_in_macros() {
+        check_assist(
+            inline_call,
+            r#"
+fn _write_u64(s: &mut u64, x: u64) {
+    *s += x;
+}
+macro_rules! impl_write {
+    ($(($ty:ident, $meth:ident),)*) => {$(
+        fn _hash(inner_self_: &u64, state: &mut u64) {
+            $meth(state, *inner_self_)
+        }
+    )*}
+}
+impl_write! { (u64, _write_u64), }
+fn _hash2(self_: &u64, state: &mut u64) {
+    $0_hash(&self_, state);
+}
+"#,
+            r#"
+fn _write_u64(s: &mut u64, x: u64) {
+    *s += x;
+}
+macro_rules! impl_write {
+    ($(($ty:ident, $meth:ident),)*) => {$(
+        fn _hash(inner_self_: &u64, state: &mut u64) {
+            $meth(state, *inner_self_)
+        }
+    )*}
+}
+impl_write! { (u64, _write_u64), }
+fn _hash2(self_: &u64, state: &mut u64) {
+    {
+        let inner_self_: &u64 = &self_;
+        let state: &mut u64 = state;
+      _write_u64(state, *inner_self_)
+    };
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index 18437453761..111ea50fdc9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -60,7 +60,7 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
 
         let id = AssistId("inline_const_as_literal", AssistKind::RefactorInline);
 
-        let label = "Inline const as literal".to_string();
+        let label = "Inline const as literal".to_owned();
         let target = variable.syntax().text_range();
 
         return acc.add(id, label, target, |edit| {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
index c1beb46c809..0c9e971dd23 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_macro.rs
@@ -41,7 +41,7 @@ pub(crate) fn inline_macro(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
 
     acc.add(
         AssistId("inline_macro", AssistKind::RefactorInline),
-        "Inline macro".to_string(),
+        "Inline macro".to_owned(),
         text_range,
         |builder| builder.replace(text_range, expanded.to_string()),
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
index 5982e9d61db..e2f3d9edcd1 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/inline_type_alias.rs
@@ -3,12 +3,12 @@
 // - Remove unused aliases if there are no longer any users, see inline_call.rs.
 
 use hir::{HasSource, PathResolution};
+use ide_db::FxHashMap;
 use ide_db::{
     defs::Definition, imports::insert_use::ast_to_remove_for_path_in_use_stmt,
     search::FileReference,
 };
 use itertools::Itertools;
-use std::collections::HashMap;
 use syntax::{
     ast::{self, make, HasGenericParams, HasName},
     ted, AstNode, NodeOrToken, SyntaxNode,
@@ -189,14 +189,14 @@ fn inline(alias_def: &ast::TypeAlias, alias_instance: &ast::PathType) -> Option<
     Some(repl)
 }
 
-struct LifetimeMap(HashMap<String, ast::Lifetime>);
+struct LifetimeMap(FxHashMap<String, ast::Lifetime>);
 
 impl LifetimeMap {
     fn new(
         instance_args: &Option<ast::GenericArgList>,
         alias_generics: &ast::GenericParamList,
     ) -> Option<Self> {
-        let mut inner = HashMap::new();
+        let mut inner = FxHashMap::default();
 
         let wildcard_lifetime = make::lifetime("'_");
         let lifetimes = alias_generics
@@ -231,14 +231,14 @@ impl LifetimeMap {
     }
 }
 
-struct ConstAndTypeMap(HashMap<String, SyntaxNode>);
+struct ConstAndTypeMap(FxHashMap<String, SyntaxNode>);
 
 impl ConstAndTypeMap {
     fn new(
         instance_args: &Option<ast::GenericArgList>,
         alias_generics: &ast::GenericParamList,
     ) -> Option<Self> {
-        let mut inner = HashMap::new();
+        let mut inner = FxHashMap::default();
         let instance_generics = generic_args_to_const_and_type_generics(instance_args);
         let alias_generics = generic_param_list_to_const_and_type_generics(alias_generics);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
index f7da88b2c18..dee74afcbe2 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/into_to_qualified_from.rs
@@ -48,7 +48,7 @@ pub(crate) fn into_to_qualified_from(acc: &mut Assists, ctx: &AssistContext<'_>)
     let fnc = sema.resolve_method_call(&method_call)?;
     let scope = sema.scope(method_call.syntax())?;
     // Check if the method call refers to Into trait.
-    if fnc.as_assoc_item(db)?.containing_trait_impl(db)?
+    if fnc.as_assoc_item(db)?.implemented_trait(db)?
         == FamousDefs(sema, scope.krate()).core_convert_Into()?
     {
         let type_call = sema.type_of_expr(&method_call.clone().into())?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index c5aa9755bc0..62909c586e3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -129,7 +129,7 @@ fn generate_unique_lifetime_param_name(
                 type_params.lifetime_params().map(|p| p.syntax().text().to_string()).collect();
             ('a'..='z').map(|it| format!("'{it}")).find(|it| !used_lifetime_params.contains(it))
         }
-        None => Some("'a".to_string()),
+        None => Some("'a".to_owned()),
     }
     .map(|it| make::lifetime(&it))
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
index aae9f20d4ea..4608e9494bc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/merge_match_arms.rs
@@ -1,5 +1,6 @@
 use hir::Type;
-use std::{collections::HashMap, iter::successors};
+use ide_db::FxHashMap;
+use std::iter::successors;
 use syntax::{
     algo::neighbor,
     ast::{self, AstNode, HasName},
@@ -95,7 +96,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool {
 }
 
 fn are_same_types(
-    current_arm_types: &HashMap<String, Option<Type>>,
+    current_arm_types: &FxHashMap<String, Option<Type>>,
     arm: &ast::MatchArm,
     ctx: &AssistContext<'_>,
 ) -> bool {
@@ -114,11 +115,11 @@ fn are_same_types(
 fn get_arm_types(
     context: &AssistContext<'_>,
     arm: &ast::MatchArm,
-) -> HashMap<String, Option<Type>> {
-    let mut mapping: HashMap<String, Option<Type>> = HashMap::new();
+) -> FxHashMap<String, Option<Type>> {
+    let mut mapping: FxHashMap<String, Option<Type>> = FxHashMap::default();
 
     fn recurse(
-        map: &mut HashMap<String, Option<Type>>,
+        map: &mut FxHashMap<String, Option<Type>>,
         ctx: &AssistContext<'_>,
         pat: &Option<ast::Pat>,
     ) {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
index 166b25c69e1..048906d9d9f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_module_to_file.rs
@@ -75,7 +75,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
             let contents = {
                 let items = module_items.dedent(IndentLevel(1)).to_string();
                 let mut items =
-                    items.trim_start_matches('{').trim_end_matches('}').trim().to_string();
+                    items.trim_start_matches('{').trim_end_matches('}').trim().to_owned();
                 if !items.is_empty() {
                     items.push('\n');
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
index 7e3fef516bf..a13799f9b13 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/number_representation.rs
@@ -33,7 +33,7 @@ pub(crate) fn reformat_number_literal(acc: &mut Assists, ctx: &AssistContext<'_>
     }
 
     let radix = literal.radix();
-    let mut converted = prefix.to_string();
+    let mut converted = prefix.to_owned();
     converted.push_str(&add_group_separators(value, group_size(radix)));
     converted.push_str(suffix);
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
index 08648718490..63a09ce2e97 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/qualify_path.rs
@@ -203,7 +203,7 @@ fn item_as_trait(db: &RootDatabase, item: hir::ItemInNs) -> Option<hir::Trait> {
 
     match item_module_def {
         hir::ModuleDef::Trait(trait_) => Some(trait_),
-        _ => item_module_def.as_assoc_item(db)?.containing_trait(db),
+        _ => item_module_def.as_assoc_item(db)?.container_trait(db),
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
index 35bf84c4349..d67b259d2f5 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_unused_imports.rs
@@ -1,11 +1,11 @@
-use std::collections::{hash_map::Entry, HashMap};
+use std::collections::hash_map::Entry;
 
 use hir::{HirFileIdExt, InFile, InRealFile, Module, ModuleSource};
 use ide_db::{
     base_db::FileRange,
     defs::Definition,
     search::{FileReference, ReferenceCategory, SearchScope},
-    RootDatabase,
+    FxHashMap, RootDatabase,
 };
 use syntax::{ast, AstNode};
 use text_edit::TextRange;
@@ -44,7 +44,7 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
     let uses = uses_up.chain(uses_down).collect::<Vec<_>>();
 
     // Maps use nodes to the scope that we should search through to find
-    let mut search_scopes = HashMap::<Module, Vec<SearchScope>>::new();
+    let mut search_scopes = FxHashMap::<Module, Vec<SearchScope>>::default();
 
     // iterator over all unused use trees
     let mut unused = uses
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 788cc846c2a..3420d906dea 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -2,15 +2,17 @@ use hir::{InFile, MacroFileIdExt, ModuleDef};
 use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator};
 use itertools::Itertools;
 use syntax::{
-    ast::{self, AstNode, HasName},
+    ast::{self, make, AstNode, HasName},
+    ted,
     SyntaxKind::WHITESPACE,
+    T,
 };
 
 use crate::{
     assist_context::{AssistContext, Assists, SourceChangeBuilder},
     utils::{
-        add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
-        generate_trait_impl_text, render_snippet, Cursor, DefaultMethods, IgnoreAssocItems,
+        add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body, generate_trait_impl,
+        DefaultMethods, IgnoreAssocItems,
     },
     AssistId, AssistKind,
 };
@@ -132,35 +134,59 @@ fn add_assist(
         label,
         target,
         |builder| {
-            let insert_pos = adt.syntax().text_range().end();
+            let insert_after = ted::Position::after(builder.make_mut(adt.clone()).syntax());
+
             let impl_def_with_items =
                 impl_def_from_trait(&ctx.sema, adt, &annotated_name, trait_, replace_trait_path);
             update_attribute(builder, old_derives, old_tree, old_trait_path, attr);
-            let trait_path = replace_trait_path.to_string();
+
+            let trait_path = make::ty_path(replace_trait_path.clone());
+
             match (ctx.config.snippet_cap, impl_def_with_items) {
                 (None, _) => {
-                    builder.insert(insert_pos, generate_trait_impl_text(adt, &trait_path, ""))
+                    let impl_def = generate_trait_impl(adt, trait_path);
+
+                    ted::insert_all(
+                        insert_after,
+                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                    );
+                }
+                (Some(cap), None) => {
+                    let impl_def = generate_trait_impl(adt, trait_path);
+
+                    if let Some(l_curly) =
+                        impl_def.assoc_item_list().and_then(|it| it.l_curly_token())
+                    {
+                        builder.add_tabstop_after_token(cap, l_curly);
+                    }
+
+                    ted::insert_all(
+                        insert_after,
+                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                    );
                 }
-                (Some(cap), None) => builder.insert_snippet(
-                    cap,
-                    insert_pos,
-                    generate_trait_impl_text(adt, &trait_path, "    $0"),
-                ),
                 (Some(cap), Some((impl_def, first_assoc_item))) => {
-                    let mut cursor = Cursor::Before(first_assoc_item.syntax());
-                    let placeholder;
+                    let mut added_snippet = false;
                     if let ast::AssocItem::Fn(ref func) = first_assoc_item {
                         if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast)
                         {
                             if m.syntax().text() == "todo!()" {
-                                placeholder = m;
-                                cursor = Cursor::Replace(placeholder.syntax());
+                                // Make the `todo!()` a placeholder
+                                builder.add_placeholder_snippet(cap, m);
+                                added_snippet = true;
                             }
                         }
                     }
 
-                    let rendered = render_snippet(cap, impl_def.syntax(), cursor);
-                    builder.insert_snippet(cap, insert_pos, format!("\n\n{rendered}"))
+                    if !added_snippet {
+                        // If we haven't already added a snippet, add a tabstop before the generated function
+                        builder.add_tabstop_before(cap, first_assoc_item);
+                    }
+
+                    ted::insert_all(
+                        insert_after,
+                        vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                    );
                 }
             };
         },
@@ -190,28 +216,7 @@ fn impl_def_from_trait(
     if trait_items.is_empty() {
         return None;
     }
-    let impl_def = {
-        use syntax::ast::Impl;
-        let text = generate_trait_impl_text(adt, trait_path.to_string().as_str(), "");
-        // FIXME: `generate_trait_impl_text` currently generates two newlines
-        // at the front, but these leading newlines should really instead be
-        // inserted at the same time the impl is inserted
-        assert_eq!(&text[..2], "\n\n", "`generate_trait_impl_text` output changed");
-        let parse = syntax::SourceFile::parse(&text[2..]);
-        let node = match parse.tree().syntax().descendants().find_map(Impl::cast) {
-            Some(it) => it,
-            None => {
-                panic!(
-                    "Failed to make ast node `{}` from text {}",
-                    std::any::type_name::<Impl>(),
-                    text
-                )
-            }
-        };
-        let node = node.clone_for_update();
-        assert_eq!(node.syntax().text_range().start(), 0.into());
-        node
-    };
+    let impl_def = generate_trait_impl(adt, make::ty_path(trait_path.clone()));
 
     let first_assoc_item =
         add_trait_assoc_items_to_impl(sema, &trait_items, trait_, &impl_def, target_scope);
@@ -238,20 +243,34 @@ fn update_attribute(
     let has_more_derives = !new_derives.is_empty();
 
     if has_more_derives {
-        let new_derives = format!("({})", new_derives.iter().format(", "));
-        builder.replace(old_tree.syntax().text_range(), new_derives);
+        let old_tree = builder.make_mut(old_tree.clone());
+
+        // Make the paths into flat lists of tokens in a vec
+        let tt = new_derives.iter().map(|path| path.syntax().clone()).map(|node| {
+            node.descendants_with_tokens()
+                .filter_map(|element| element.into_token())
+                .collect::<Vec<_>>()
+        });
+        // ...which are interspersed with ", "
+        let tt = Itertools::intersperse(tt, vec![make::token(T![,]), make::tokens::single_space()]);
+        // ...wrap them into the appropriate `NodeOrToken` variant
+        let tt = tt.flatten().map(syntax::NodeOrToken::Token);
+        // ...and make them into a flat list of tokens
+        let tt = tt.collect::<Vec<_>>();
+
+        let new_tree = make::token_tree(T!['('], tt).clone_for_update();
+        ted::replace(old_tree.syntax(), new_tree.syntax());
     } else {
-        let attr_range = attr.syntax().text_range();
-        builder.delete(attr_range);
-
-        if let Some(line_break_range) = attr
-            .syntax()
-            .next_sibling_or_token()
-            .filter(|t| t.kind() == WHITESPACE)
-            .map(|t| t.text_range())
+        // Remove the attr and any trailing whitespace
+        let attr = builder.make_mut(attr.clone());
+
+        if let Some(line_break) =
+            attr.syntax().next_sibling_or_token().filter(|t| t.kind() == WHITESPACE)
         {
-            builder.delete(line_break_range);
+            ted::remove(line_break)
         }
+
+        ted::remove(attr.syntax())
     }
 }
 
@@ -1168,9 +1187,7 @@ struct Foo {
     bar: String,
 }
 
-impl Debug for Foo {
-    $0
-}
+impl Debug for Foo {$0}
             "#,
         )
     }
@@ -1191,9 +1208,7 @@ pub struct Foo {
     bar: String,
 }
 
-impl Debug for Foo {
-    $0
-}
+impl Debug for Foo {$0}
             "#,
         )
     }
@@ -1211,9 +1226,7 @@ struct Foo {}
 #[derive(Display, Serialize)]
 struct Foo {}
 
-impl Debug for Foo {
-    $0
-}
+impl Debug for Foo {$0}
             "#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs
index 03e6dfebebf..8a9e669630b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/unwrap_result_return_type.rs
@@ -47,9 +47,7 @@ pub(crate) fn unwrap_result_return_type(acc: &mut Assists, ctx: &AssistContext<'
         return None;
     }
 
-    let Some(ok_type) = unwrap_result_type(type_ref) else {
-        return None;
-    };
+    let ok_type = unwrap_result_type(type_ref)?;
 
     acc.add(
         AssistId("unwrap_result_return_type", AssistKind::RefactorRewrite),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
index 573d69b5c6d..9b6f7d018ee 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests.rs
@@ -474,7 +474,7 @@ pub fn test_some_range(a: int) -> bool {
             &db,
             &cfg,
             AssistResolveStrategy::Single(SingleResolve {
-                assist_id: "SOMETHING_MISMATCHING".to_string(),
+                assist_id: "SOMETHING_MISMATCHING".to_owned(),
                 assist_kind: AssistKind::RefactorExtract,
             }),
             frange,
@@ -520,7 +520,7 @@ pub fn test_some_range(a: int) -> bool {
             &db,
             &cfg,
             AssistResolveStrategy::Single(SingleResolve {
-                assist_id: "extract_variable".to_string(),
+                assist_id: "extract_variable".to_owned(),
                 assist_kind: AssistKind::RefactorExtract,
             }),
             frange,
@@ -687,12 +687,21 @@ pub fn test_some_range(a: int) -> bool {
                                             delete: 59..60,
                                         },
                                         Indel {
-                                            insert: "\n\nfn $0fun_name() -> i32 {\n    5\n}",
+                                            insert: "\n\nfn fun_name() -> i32 {\n    5\n}",
                                             delete: 110..110,
                                         },
                                     ],
                                 },
-                                None,
+                                Some(
+                                    SnippetEdit(
+                                        [
+                                            (
+                                                0,
+                                                124..124,
+                                            ),
+                                        ],
+                                    ),
+                                ),
                             ),
                         },
                         file_system_edits: [],
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 8d7c49d52c2..8ad735d0ae8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1429,7 +1429,7 @@ fn doctest_generate_getter() {
     check_doc_test(
         "generate_getter",
         r#####"
-//- minicore: as_ref
+//- minicore: as_ref, deref
 pub struct String;
 impl AsRef<str> for String {
     fn as_ref(&self) -> &str {
@@ -1437,6 +1437,13 @@ impl AsRef<str> for String {
     }
 }
 
+impl core::ops::Deref for String {
+    type Target = str;
+    fn deref(&self) -> &Self::Target {
+        ""
+    }
+}
+
 struct Person {
     nam$0e: String,
 }
@@ -1449,13 +1456,20 @@ impl AsRef<str> for String {
     }
 }
 
+impl core::ops::Deref for String {
+    type Target = str;
+    fn deref(&self) -> &Self::Target {
+        ""
+    }
+}
+
 struct Person {
     name: String,
 }
 
 impl Person {
     fn $0name(&self) -> &str {
-        self.name.as_ref()
+        &self.name
     }
 }
 "#####,
@@ -1499,9 +1513,7 @@ struct Ctx<T: Clone> {
     data: T,
 }
 
-impl<T: Clone> Ctx<T> {
-    $0
-}
+impl<T: Clone> Ctx<T> {$0}
 "#####,
     )
 }
@@ -1589,7 +1601,9 @@ struct Ctx<T: Clone> {
 }
 
 impl<T: Clone> Ctx<T> {
-    fn $0new(data: T) -> Self { Self { data } }
+    fn $0new(data: T) -> Self {
+        Self { data }
+    }
 }
 "#####,
     )
@@ -1688,9 +1702,7 @@ struct Ctx<T: Clone> {
     data: T,
 }
 
-impl<T: Clone> $0 for Ctx<T> {
-
-}
+impl<T: Clone> ${0:_} for Ctx<T> {}
 "#####,
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs
index 088d93f9a6b..847cb1af51e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/sourcegen.rs
@@ -15,7 +15,7 @@ fn sourcegen_assists_docs() {
         let mut buf = "
 use super::check_doc_test;
 "
-        .to_string();
+        .to_owned();
         for assist in assists.iter() {
             for (idx, section) in assist.sections.iter().enumerate() {
                 let test_id =
@@ -101,7 +101,7 @@ impl Assist {
                 let mut assist = Assist { id, location, sections: Vec::new() };
 
                 while lines.peek().is_some() {
-                    let doc = take_until(lines.by_ref(), "```").trim().to_string();
+                    let doc = take_until(lines.by_ref(), "```").trim().to_owned();
                     assert!(
                         (doc.chars().next().unwrap().is_ascii_uppercase() && doc.ends_with('.'))
                             || !assist.sections.is_empty(),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index eeb3d80d07b..a4f14326751 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -1,12 +1,10 @@
 //! Assorted functions shared by several assists.
 
-use std::ops;
-
 pub(crate) use gen_trait_fn_body::gen_trait_fn_body;
 use hir::{db::HirDatabase, HasAttrs as HirHasAttrs, HirDisplay, InFile, Semantics};
 use ide_db::{
     famous_defs::FamousDefs, path_transform::PathTransform,
-    syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase, SnippetCap,
+    syntax_helpers::insert_whitespace_into_node::insert_ws_into, RootDatabase,
 };
 use stdx::format_to;
 use syntax::{
@@ -217,43 +215,6 @@ pub fn add_trait_assoc_items_to_impl(
     first_item.unwrap()
 }
 
-#[derive(Clone, Copy, Debug)]
-pub(crate) enum Cursor<'a> {
-    Replace(&'a SyntaxNode),
-    Before(&'a SyntaxNode),
-}
-
-impl<'a> Cursor<'a> {
-    fn node(self) -> &'a SyntaxNode {
-        match self {
-            Cursor::Replace(node) | Cursor::Before(node) => node,
-        }
-    }
-}
-
-pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor<'_>) -> String {
-    assert!(cursor.node().ancestors().any(|it| it == *node));
-    let range = cursor.node().text_range() - node.text_range().start();
-    let range: ops::Range<usize> = range.into();
-
-    let mut placeholder = cursor.node().to_string();
-    escape(&mut placeholder);
-    let tab_stop = match cursor {
-        Cursor::Replace(placeholder) => format!("${{0:{placeholder}}}"),
-        Cursor::Before(placeholder) => format!("$0{placeholder}"),
-    };
-
-    let mut buf = node.to_string();
-    buf.replace_range(range, &tab_stop);
-    return buf;
-
-    fn escape(buf: &mut String) {
-        stdx::replace(buf, '{', r"\{");
-        stdx::replace(buf, '}', r"\}");
-        stdx::replace(buf, '$', r"\$");
-    }
-}
-
 pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
     node.children_with_tokens()
         .find(|it| !matches!(it.kind(), WHITESPACE | COMMENT | ATTR))
@@ -445,15 +406,6 @@ fn has_any_fn(imp: &ast::Impl, names: &[String]) -> bool {
     false
 }
 
-/// Find the start of the `impl` block for the given `ast::Impl`.
-//
-// FIXME: this partially overlaps with `find_struct_impl`
-pub(crate) fn find_impl_block_start(impl_def: ast::Impl, buf: &mut String) -> Option<TextSize> {
-    buf.push('\n');
-    let start = impl_def.assoc_item_list().and_then(|it| it.l_curly_token())?.text_range().end();
-    Some(start)
-}
-
 /// Find the end of the `impl` block for the given `ast::Impl`.
 //
 // FIXME: this partially overlaps with `find_struct_impl`
@@ -470,6 +422,7 @@ pub(crate) fn find_impl_block_end(impl_def: ast::Impl, buf: &mut String) -> Opti
 
 /// Generates the surrounding `impl Type { <code> }` including type and lifetime
 /// parameters.
+// FIXME: migrate remaining uses to `generate_impl`
 pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
     generate_impl_text_inner(adt, None, true, code)
 }
@@ -478,6 +431,7 @@ pub(crate) fn generate_impl_text(adt: &ast::Adt, code: &str) -> String {
 /// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
 ///
 /// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
+// FIXME: migrate remaining uses to `generate_trait_impl`
 pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &str) -> String {
     generate_impl_text_inner(adt, Some(trait_text), true, code)
 }
@@ -486,6 +440,7 @@ pub(crate) fn generate_trait_impl_text(adt: &ast::Adt, trait_text: &str, code: &
 /// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
 ///
 /// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
+// FIXME: migrate remaining uses to `generate_trait_impl_intransitive`
 pub(crate) fn generate_trait_impl_text_intransitive(
     adt: &ast::Adt,
     trait_text: &str,
@@ -516,7 +471,7 @@ fn generate_impl_text_inner(
                         // Add the current trait to `bounds` if the trait is transitive,
                         // meaning `impl<T> Trait for U<T>` requires `T: Trait`.
                         if trait_is_transitive {
-                            bounds.push(make::type_bound(trait_));
+                            bounds.push(make::type_bound_text(trait_));
                         }
                     };
                     // `{ty_param}: {bounds}`
@@ -574,6 +529,101 @@ fn generate_impl_text_inner(
     buf
 }
 
+/// Generates the corresponding `impl Type {}` including type and lifetime
+/// parameters.
+pub(crate) fn generate_impl(adt: &ast::Adt) -> ast::Impl {
+    generate_impl_inner(adt, None, true)
+}
+
+/// Generates the corresponding `impl <trait> for Type {}` including type
+/// and lifetime parameters, with `<trait>` appended to `impl`'s generic parameters' bounds.
+///
+/// This is useful for traits like `PartialEq`, since `impl<T> PartialEq for U<T>` often requires `T: PartialEq`.
+pub(crate) fn generate_trait_impl(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
+    generate_impl_inner(adt, Some(trait_), true)
+}
+
+/// Generates the corresponding `impl <trait> for Type {}` including type
+/// and lifetime parameters, with `impl`'s generic parameters' bounds kept as-is.
+///
+/// This is useful for traits like `From<T>`, since `impl<T> From<T> for U<T>` doesn't require `T: From<T>`.
+pub(crate) fn generate_trait_impl_intransitive(adt: &ast::Adt, trait_: ast::Type) -> ast::Impl {
+    generate_impl_inner(adt, Some(trait_), false)
+}
+
+fn generate_impl_inner(
+    adt: &ast::Adt,
+    trait_: Option<ast::Type>,
+    trait_is_transitive: bool,
+) -> ast::Impl {
+    // Ensure lifetime params are before type & const params
+    let generic_params = adt.generic_param_list().map(|generic_params| {
+        let lifetime_params =
+            generic_params.lifetime_params().map(ast::GenericParam::LifetimeParam);
+        let ty_or_const_params = generic_params.type_or_const_params().map(|param| {
+            match param {
+                ast::TypeOrConstParam::Type(param) => {
+                    let param = param.clone_for_update();
+                    // remove defaults since they can't be specified in impls
+                    param.remove_default();
+                    let mut bounds =
+                        param.type_bound_list().map_or_else(Vec::new, |it| it.bounds().collect());
+                    if let Some(trait_) = &trait_ {
+                        // Add the current trait to `bounds` if the trait is transitive,
+                        // meaning `impl<T> Trait for U<T>` requires `T: Trait`.
+                        if trait_is_transitive {
+                            bounds.push(make::type_bound(trait_.clone()));
+                        }
+                    };
+                    // `{ty_param}: {bounds}`
+                    let param =
+                        make::type_param(param.name().unwrap(), make::type_bound_list(bounds));
+                    ast::GenericParam::TypeParam(param)
+                }
+                ast::TypeOrConstParam::Const(param) => {
+                    let param = param.clone_for_update();
+                    // remove defaults since they can't be specified in impls
+                    param.remove_default();
+                    ast::GenericParam::ConstParam(param)
+                }
+            }
+        });
+
+        make::generic_param_list(itertools::chain(lifetime_params, ty_or_const_params))
+    });
+    let generic_args =
+        generic_params.as_ref().map(|params| params.to_generic_args().clone_for_update());
+    let ty = make::ty_path(make::ext::ident_path(&adt.name().unwrap().text()));
+
+    let impl_ = match trait_ {
+        Some(trait_) => make::impl_trait(
+            false,
+            None,
+            None,
+            generic_params,
+            generic_args,
+            false,
+            trait_,
+            ty,
+            None,
+            adt.where_clause(),
+            None,
+        ),
+        None => make::impl_(generic_params, generic_args, ty, adt.where_clause(), None),
+    }
+    .clone_for_update();
+
+    // Copy any cfg attrs from the original adt
+    let cfg_attrs = adt
+        .attrs()
+        .filter(|attr| attr.as_simple_call().map(|(name, _arg)| name == "cfg").unwrap_or(false));
+    for attr in cfg_attrs {
+        impl_.add_attr(attr.clone_for_update());
+    }
+
+    impl_
+}
+
 pub(crate) fn add_method_to_adt(
     builder: &mut SourceChangeBuilder,
     adt: &ast::Adt,
@@ -600,6 +650,7 @@ pub(crate) fn add_method_to_adt(
 pub(crate) struct ReferenceConversion {
     conversion: ReferenceConversionType,
     ty: hir::Type,
+    impls_deref: bool,
 }
 
 #[derive(Debug)]
@@ -619,10 +670,10 @@ enum ReferenceConversionType {
 }
 
 impl ReferenceConversion {
-    pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> String {
-        match self.conversion {
+    pub(crate) fn convert_type(&self, db: &dyn HirDatabase) -> ast::Type {
+        let ty = match self.conversion {
             ReferenceConversionType::Copy => self.ty.display(db).to_string(),
-            ReferenceConversionType::AsRefStr => "&str".to_string(),
+            ReferenceConversionType::AsRefStr => "&str".to_owned(),
             ReferenceConversionType::AsRefSlice => {
                 let type_argument_name =
                     self.ty.type_arguments().next().unwrap().display(db).to_string();
@@ -646,17 +697,27 @@ impl ReferenceConversion {
                     type_arguments.next().unwrap().display(db).to_string();
                 format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
             }
-        }
+        };
+
+        make::ty(&ty)
     }
 
-    pub(crate) fn getter(&self, field_name: String) -> String {
+    pub(crate) fn getter(&self, field_name: String) -> ast::Expr {
+        let expr = make::expr_field(make::ext::expr_self(), &field_name);
+
         match self.conversion {
-            ReferenceConversionType::Copy => format!("self.{field_name}"),
+            ReferenceConversionType::Copy => expr,
             ReferenceConversionType::AsRefStr
             | ReferenceConversionType::AsRefSlice
             | ReferenceConversionType::Dereferenced
             | ReferenceConversionType::Option
-            | ReferenceConversionType::Result => format!("self.{field_name}.as_ref()"),
+            | ReferenceConversionType::Result => {
+                if self.impls_deref {
+                    make::expr_ref(expr, false)
+                } else {
+                    make::expr_method_call(expr, make::name_ref("as_ref"), make::arg_list([]))
+                }
+            }
         }
     }
 }
@@ -675,54 +736,64 @@ pub(crate) fn convert_reference_type(
         .or_else(|| handle_dereferenced(&ty, db, famous_defs))
         .or_else(|| handle_option_as_ref(&ty, db, famous_defs))
         .or_else(|| handle_result_as_ref(&ty, db, famous_defs))
-        .map(|conversion| ReferenceConversion { ty, conversion })
+        .map(|(conversion, impls_deref)| ReferenceConversion { ty, conversion, impls_deref })
+}
+
+fn could_deref_to_target(ty: &hir::Type, target: &hir::Type, db: &dyn HirDatabase) -> bool {
+    let ty_ref = hir::Type::reference(ty, hir::Mutability::Shared);
+    let target_ref = hir::Type::reference(target, hir::Mutability::Shared);
+    ty_ref.could_coerce_to(db, &target_ref)
 }
 
-fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<ReferenceConversionType> {
-    ty.is_copy(db).then_some(ReferenceConversionType::Copy)
+fn handle_copy(ty: &hir::Type, db: &dyn HirDatabase) -> Option<(ReferenceConversionType, bool)> {
+    ty.is_copy(db).then_some((ReferenceConversionType::Copy, true))
 }
 
 fn handle_as_ref_str(
     ty: &hir::Type,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversionType> {
+) -> Option<(ReferenceConversionType, bool)> {
     let str_type = hir::BuiltinType::str().ty(db);
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type])
-        .then_some(ReferenceConversionType::AsRefStr)
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[str_type.clone()])
+        .then_some((ReferenceConversionType::AsRefStr, could_deref_to_target(ty, &str_type, db)))
 }
 
 fn handle_as_ref_slice(
     ty: &hir::Type,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversionType> {
+) -> Option<(ReferenceConversionType, bool)> {
     let type_argument = ty.type_arguments().next()?;
     let slice_type = hir::Type::new_slice(type_argument);
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type])
-        .then_some(ReferenceConversionType::AsRefSlice)
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[slice_type.clone()]).then_some((
+        ReferenceConversionType::AsRefSlice,
+        could_deref_to_target(ty, &slice_type, db),
+    ))
 }
 
 fn handle_dereferenced(
     ty: &hir::Type,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversionType> {
+) -> Option<(ReferenceConversionType, bool)> {
     let type_argument = ty.type_arguments().next()?;
 
-    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument])
-        .then_some(ReferenceConversionType::Dereferenced)
+    ty.impls_trait(db, famous_defs.core_convert_AsRef()?, &[type_argument.clone()]).then_some((
+        ReferenceConversionType::Dereferenced,
+        could_deref_to_target(ty, &type_argument, db),
+    ))
 }
 
 fn handle_option_as_ref(
     ty: &hir::Type,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversionType> {
+) -> Option<(ReferenceConversionType, bool)> {
     if ty.as_adt() == famous_defs.core_option_Option()?.ty(db).as_adt() {
-        Some(ReferenceConversionType::Option)
+        Some((ReferenceConversionType::Option, false))
     } else {
         None
     }
@@ -732,9 +803,9 @@ fn handle_result_as_ref(
     ty: &hir::Type,
     db: &dyn HirDatabase,
     famous_defs: &FamousDefs<'_, '_>,
-) -> Option<ReferenceConversionType> {
+) -> Option<(ReferenceConversionType, bool)> {
     if ty.as_adt() == famous_defs.core_result_Result()?.ty(db).as_adt() {
-        Some(ReferenceConversionType::Result)
+        Some((ReferenceConversionType::Result, false))
     } else {
         None
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
index 78dee24a6d3..1859825b3d6 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils/suggest_name.rs
@@ -1,9 +1,7 @@
 //! This module contains functions to suggest names for expressions, functions and other items
 
-use std::collections::HashSet;
-
 use hir::Semantics;
-use ide_db::RootDatabase;
+use ide_db::{FxHashSet, RootDatabase};
 use itertools::Itertools;
 use stdx::to_lower_snake_case;
 use syntax::{
@@ -78,8 +76,8 @@ pub(crate) fn for_unique_generic_name(
             ast::GenericParam::TypeParam(t) => t.name().unwrap().to_string(),
             p => p.to_string(),
         })
-        .collect::<HashSet<_>>();
-    let mut name = name.to_string();
+        .collect::<FxHashSet<_>>();
+    let mut name = name.to_owned();
     let base_len = name.len();
     let mut count = 0;
     while param_names.contains(&name) {
@@ -167,7 +165,7 @@ pub(crate) fn for_variable(expr: &ast::Expr, sema: &Semantics<'_, RootDatabase>)
         }
     }
 
-    "var_name".to_string()
+    "var_name".to_owned()
 }
 
 fn normalize(name: &str) -> Option<String> {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index 00135a6d202..24a1f9492e2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -4,7 +4,10 @@ use ide_db::FxHashSet;
 use syntax::SmolStr;
 
 use crate::{
-    context::{CompletionContext, DotAccess, DotAccessKind, ExprCtx, PathCompletionCtx, Qualified},
+    context::{
+        CompletionContext, DotAccess, DotAccessExprCtx, DotAccessKind, PathCompletionCtx,
+        PathExprCtx, Qualified,
+    },
     CompletionItem, CompletionItemKind, Completions,
 };
 
@@ -51,7 +54,7 @@ pub(crate) fn complete_undotted_self(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx: &PathCompletionCtx,
-    expr_ctx: &ExprCtx,
+    expr_ctx: &PathExprCtx,
 ) {
     if !ctx.config.enable_self_on_the_fly {
         return;
@@ -66,7 +69,7 @@ pub(crate) fn complete_undotted_self(
         return;
     }
     let self_param = match expr_ctx {
-        ExprCtx { self_param: Some(self_param), .. } => self_param,
+        PathExprCtx { self_param: Some(self_param), .. } => self_param,
         _ => return,
     };
 
@@ -82,6 +85,10 @@ pub(crate) fn complete_undotted_self(
                     receiver: None,
                     receiver_ty: None,
                     kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
+                    ctx: DotAccessExprCtx {
+                        in_block_expr: expr_ctx.in_block_expr,
+                        in_breakable: expr_ctx.in_breakable,
+                    },
                 },
                 Some(hir::known::SELF_PARAM),
                 field,
@@ -99,6 +106,10 @@ pub(crate) fn complete_undotted_self(
                 receiver: None,
                 receiver_ty: None,
                 kind: DotAccessKind::Method { has_parens: false },
+                ctx: DotAccessExprCtx {
+                    in_block_expr: expr_ctx.in_block_expr,
+                    in_breakable: expr_ctx.in_breakable,
+                },
             },
             func,
             Some(hir::known::SELF_PARAM),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
index 1433216d611..77fd5dd98b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs
@@ -5,7 +5,7 @@ use syntax::ast;
 
 use crate::{
     completions::record::add_default_update,
-    context::{ExprCtx, PathCompletionCtx, Qualified},
+    context::{BreakableKind, PathCompletionCtx, PathExprCtx, Qualified},
     CompletionContext, Completions,
 };
 
@@ -13,16 +13,16 @@ pub(crate) fn complete_expr_path(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx @ PathCompletionCtx { qualified, .. }: &PathCompletionCtx,
-    expr_ctx: &ExprCtx,
+    expr_ctx: &PathExprCtx,
 ) {
     let _p = tracing::span!(tracing::Level::INFO, "complete_expr_path").entered();
     if !ctx.qualifier_ctx.none() {
         return;
     }
 
-    let &ExprCtx {
+    let &PathExprCtx {
         in_block_expr,
-        in_loop_body,
+        in_breakable,
         after_if_expr,
         in_condition,
         incomplete_let,
@@ -290,7 +290,7 @@ pub(crate) fn complete_expr_path(
                         add_keyword("mut", "mut ");
                     }
 
-                    if in_loop_body {
+                    if in_breakable != BreakableKind::None {
                         if in_block_expr {
                             add_keyword("continue", "continue;");
                             add_keyword("break", "break;");
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
index f9cde44667b..b67d82c20d8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/extern_crate.rs
@@ -46,7 +46,7 @@ mod other_mod {}
 
         let completion_list = completion_list_no_kw(case);
 
-        assert_eq!("md other_crate_a\n".to_string(), completion_list);
+        assert_eq!("md other_crate_a\n".to_owned(), completion_list);
     }
 
     #[test]
@@ -66,6 +66,6 @@ mod other_mod {}
 
         let completion_list = completion_list_no_kw(case);
 
-        assert_eq!("md other_crate_a\n".to_string(), completion_list);
+        assert_eq!("md other_crate_a\n".to_owned(), completion_list);
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 0e04ad35d33..b9f91d34b2c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -395,6 +395,14 @@ fn import_assets_for_path(
     potential_import_name: &str,
     qualifier: Option<ast::Path>,
 ) -> Option<ImportAssets> {
+    let _p = tracing::span!(
+        tracing::Level::INFO,
+        "import_assets_for_path",
+        ?potential_import_name,
+        ?qualifier
+    )
+    .entered();
+
     let fuzzy_name_length = potential_import_name.len();
     let mut assets_for_path = ImportAssets::for_fuzzy_path(
         ctx.module,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
index addd9dac1a7..0a6a8633a2c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list.rs
@@ -1,7 +1,7 @@
 //! Completion of paths and keywords at item list position.
 
 use crate::{
-    context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
+    context::{ItemListKind, PathCompletionCtx, PathExprCtx, Qualified},
     CompletionContext, Completions,
 };
 
@@ -11,7 +11,7 @@ pub(crate) fn complete_item_list_in_expr(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx: &PathCompletionCtx,
-    expr_ctx: &ExprCtx,
+    expr_ctx: &PathExprCtx,
 ) {
     if !expr_ctx.in_block_expr {
         return;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
index b9ab2afca2b..ed32a5db23e 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/keyword.rs
@@ -81,11 +81,13 @@ fn foo(a: A) { a.$0 }
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
                 sn dbgr                   dbg!(&expr)
+                sn deref                  *expr
                 sn let                    let
                 sn letm                   let mut
                 sn match                  match expr {}
                 sn ref                    &expr
                 sn refm                   &mut expr
+                sn return                 return expr
                 sn unsafe                 unsafe {}
             "#]],
         );
@@ -106,11 +108,13 @@ fn foo() {
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
                 sn dbgr                   dbg!(&expr)
+                sn deref                  *expr
                 sn let                    let
                 sn letm                   let mut
                 sn match                  match expr {}
                 sn ref                    &expr
                 sn refm                   &mut expr
+                sn return                 return expr
                 sn unsafe                 unsafe {}
             "#]],
         );
@@ -133,11 +137,13 @@ fn foo(a: A) { a.$0 }
                 sn call                   function(expr)
                 sn dbg                    dbg!(expr)
                 sn dbgr                   dbg!(&expr)
+                sn deref                  *expr
                 sn let                    let
                 sn letm                   let mut
                 sn match                  match expr {}
                 sn ref                    &expr
                 sn refm                   &mut expr
+                sn return                 return expr
                 sn unsafe                 unsafe {}
             "#]],
         );
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
index af83d4104f7..72c0885e92f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs
@@ -2,6 +2,7 @@
 
 mod format_like;
 
+use hir::ItemInNs;
 use ide_db::{
     documentation::{Documentation, HasDocs},
     imports::insert_use::ImportScope,
@@ -17,7 +18,7 @@ use text_edit::TextEdit;
 
 use crate::{
     completions::postfix::format_like::add_format_like_completions,
-    context::{CompletionContext, DotAccess, DotAccessKind},
+    context::{BreakableKind, CompletionContext, DotAccess, DotAccessKind},
     item::{Builder, CompletionRelevancePostfixMatch},
     CompletionItem, CompletionItemKind, CompletionRelevance, Completions, SnippetScope,
 };
@@ -44,6 +45,7 @@ pub(crate) fn complete_postfix(
         ),
         _ => return,
     };
+    let expr_ctx = &dot_access.ctx;
 
     let receiver_text = get_receiver_text(dot_receiver, receiver_is_ambiguous_float_literal);
 
@@ -59,16 +61,22 @@ pub(crate) fn complete_postfix(
 
     if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
         if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
-            if let &[hir::AssocItem::Function(drop_fn)] = &*drop_trait.items(ctx.db) {
-                cov_mark::hit!(postfix_drop_completion);
-                // FIXME: check that `drop` is in scope, use fully qualified path if it isn't/if shadowed
-                let mut item = postfix_snippet(
-                    "drop",
-                    "fn drop(&mut self)",
-                    &format!("drop($0{receiver_text})"),
-                );
-                item.set_documentation(drop_fn.docs(ctx.db));
-                item.add_to(acc, ctx.db);
+            if let Some(drop_fn) = ctx.famous_defs().core_mem_drop() {
+                if let Some(path) = ctx.module.find_use_path(
+                    ctx.db,
+                    ItemInNs::Values(drop_fn.into()),
+                    ctx.config.prefer_no_std,
+                    ctx.config.prefer_prelude,
+                ) {
+                    cov_mark::hit!(postfix_drop_completion);
+                    let mut item = postfix_snippet(
+                        "drop",
+                        "fn drop(&mut self)",
+                        &format!("{path}($0{receiver_text})", path = path.display(ctx.db)),
+                    );
+                    item.set_documentation(drop_fn.docs(ctx.db));
+                    item.add_to(acc, ctx.db);
+                }
             }
         }
     }
@@ -140,6 +148,7 @@ pub(crate) fn complete_postfix(
 
     postfix_snippet("ref", "&expr", &format!("&{receiver_text}")).add_to(acc, ctx.db);
     postfix_snippet("refm", "&mut expr", &format!("&mut {receiver_text}")).add_to(acc, ctx.db);
+    postfix_snippet("deref", "*expr", &format!("*{receiver_text}")).add_to(acc, ctx.db);
 
     let mut unsafe_should_be_wrapped = true;
     if dot_receiver.syntax().kind() == BLOCK_EXPR {
@@ -224,6 +233,28 @@ pub(crate) fn complete_postfix(
             add_format_like_completions(acc, ctx, &dot_receiver, cap, &literal_text);
         }
     }
+
+    postfix_snippet(
+        "return",
+        "return expr",
+        &format!(
+            "return {receiver_text}{semi}",
+            semi = if expr_ctx.in_block_expr { ";" } else { "" }
+        ),
+    )
+    .add_to(acc, ctx.db);
+
+    if let BreakableKind::Block | BreakableKind::Loop = expr_ctx.in_breakable {
+        postfix_snippet(
+            "break",
+            "break expr",
+            &format!(
+                "break {receiver_text}{semi}",
+                semi = if expr_ctx.in_block_expr { ";" } else { "" }
+            ),
+        )
+        .add_to(acc, ctx.db);
+    }
 }
 
 fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String {
@@ -295,7 +326,7 @@ fn build_postfix_snippet_builder<'ctx>(
         delete_range: TextRange,
     ) -> impl Fn(&str, &str, &str) -> Builder + 'ctx {
         move |label, detail, snippet| {
-            let edit = TextEdit::replace(delete_range, snippet.to_string());
+            let edit = TextEdit::replace(delete_range, snippet.to_owned());
             let mut item =
                 CompletionItem::new(CompletionItemKind::Snippet, ctx.source_range(), label);
             item.detail(detail).snippet_edit(cap, edit);
@@ -368,6 +399,7 @@ fn main() {
                 sn call   function(expr)
                 sn dbg    dbg!(expr)
                 sn dbgr   dbg!(&expr)
+                sn deref  *expr
                 sn if     if expr {}
                 sn let    let
                 sn letm   let mut
@@ -375,6 +407,7 @@ fn main() {
                 sn not    !expr
                 sn ref    &expr
                 sn refm   &mut expr
+                sn return return expr
                 sn unsafe unsafe {}
                 sn while  while expr {}
             "#]],
@@ -399,11 +432,13 @@ fn main() {
                 sn call   function(expr)
                 sn dbg    dbg!(expr)
                 sn dbgr   dbg!(&expr)
+                sn deref  *expr
                 sn if     if expr {}
                 sn match  match expr {}
                 sn not    !expr
                 sn ref    &expr
                 sn refm   &mut expr
+                sn return return expr
                 sn unsafe unsafe {}
                 sn while  while expr {}
             "#]],
@@ -424,11 +459,13 @@ fn main() {
                 sn call   function(expr)
                 sn dbg    dbg!(expr)
                 sn dbgr   dbg!(&expr)
+                sn deref  *expr
                 sn let    let
                 sn letm   let mut
                 sn match  match expr {}
                 sn ref    &expr
                 sn refm   &mut expr
+                sn return return expr
                 sn unsafe unsafe {}
             "#]],
         )
@@ -448,6 +485,7 @@ fn main() {
                 sn call   function(expr)
                 sn dbg    dbg!(expr)
                 sn dbgr   dbg!(&expr)
+                sn deref  *expr
                 sn if     if expr {}
                 sn let    let
                 sn letm   let mut
@@ -455,6 +493,7 @@ fn main() {
                 sn not    !expr
                 sn ref    &expr
                 sn refm   &mut expr
+                sn return return expr
                 sn unsafe unsafe {}
                 sn while  while expr {}
             "#]],
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
index e53d1cc6322..1dcf41f8dd2 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs
@@ -6,7 +6,7 @@ use syntax::{
 };
 
 use crate::{
-    context::{DotAccess, DotAccessKind, PatternContext},
+    context::{DotAccess, DotAccessExprCtx, DotAccessKind, PatternContext},
     CompletionContext, CompletionItem, CompletionItemKind, CompletionRelevance,
     CompletionRelevancePostfixMatch, Completions,
 };
@@ -118,12 +118,17 @@ fn complete_fields(
     missing_fields: Vec<(hir::Field, hir::Type)>,
 ) {
     for (field, ty) in missing_fields {
+        // This should call something else, we shouldn't be synthesizing a DotAccess here
         acc.add_field(
             ctx,
             &DotAccess {
                 receiver: None,
                 receiver_ty: None,
                 kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal: false },
+                ctx: DotAccessExprCtx {
+                    in_block_expr: false,
+                    in_breakable: crate::context::BreakableKind::None,
+                },
             },
             None,
             field,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
index a0191922050..e831113350a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/snippet.rs
@@ -3,7 +3,7 @@
 use ide_db::{documentation::Documentation, imports::insert_use::ImportScope, SnippetCap};
 
 use crate::{
-    context::{ExprCtx, ItemListKind, PathCompletionCtx, Qualified},
+    context::{ItemListKind, PathCompletionCtx, PathExprCtx, Qualified},
     item::Builder,
     CompletionContext, CompletionItem, CompletionItemKind, Completions, SnippetScope,
 };
@@ -12,7 +12,7 @@ pub(crate) fn complete_expr_snippet(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
     path_ctx: &PathCompletionCtx,
-    &ExprCtx { in_block_expr, .. }: &ExprCtx,
+    &PathExprCtx { in_block_expr, .. }: &PathExprCtx,
 ) {
     if !matches!(path_ctx.qualified, Qualified::No) {
         return;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 2c0370c58f7..2a0004f60b8 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -45,13 +45,13 @@ pub(crate) enum Visible {
 
 /// Existing qualifiers for the thing we are currently completing.
 #[derive(Debug, Default)]
-pub(super) struct QualifierCtx {
-    pub(super) unsafe_tok: Option<SyntaxToken>,
-    pub(super) vis_node: Option<ast::Visibility>,
+pub(crate) struct QualifierCtx {
+    pub(crate) unsafe_tok: Option<SyntaxToken>,
+    pub(crate) vis_node: Option<ast::Visibility>,
 }
 
 impl QualifierCtx {
-    pub(super) fn none(&self) -> bool {
+    pub(crate) fn none(&self) -> bool {
         self.unsafe_tok.is_none() && self.vis_node.is_none()
     }
 }
@@ -60,27 +60,27 @@ impl QualifierCtx {
 #[derive(Debug)]
 pub(crate) struct PathCompletionCtx {
     /// If this is a call with () already there (or {} in case of record patterns)
-    pub(super) has_call_parens: bool,
+    pub(crate) has_call_parens: bool,
     /// If this has a macro call bang !
-    pub(super) has_macro_bang: bool,
+    pub(crate) has_macro_bang: bool,
     /// The qualifier of the current path.
-    pub(super) qualified: Qualified,
+    pub(crate) qualified: Qualified,
     /// The parent of the path we are completing.
-    pub(super) parent: Option<ast::Path>,
+    pub(crate) parent: Option<ast::Path>,
     #[allow(dead_code)]
     /// The path of which we are completing the segment
-    pub(super) path: ast::Path,
+    pub(crate) path: ast::Path,
     /// The path of which we are completing the segment in the original file
     pub(crate) original_path: Option<ast::Path>,
-    pub(super) kind: PathKind,
+    pub(crate) kind: PathKind,
     /// Whether the path segment has type args or not.
-    pub(super) has_type_args: bool,
+    pub(crate) has_type_args: bool,
     /// Whether the qualifier comes from a use tree parent or not
     pub(crate) use_tree_parent: bool,
 }
 
 impl PathCompletionCtx {
-    pub(super) fn is_trivial_path(&self) -> bool {
+    pub(crate) fn is_trivial_path(&self) -> bool {
         matches!(
             self,
             PathCompletionCtx {
@@ -97,9 +97,9 @@ impl PathCompletionCtx {
 
 /// The kind of path we are completing right now.
 #[derive(Debug, PartialEq, Eq)]
-pub(super) enum PathKind {
+pub(crate) enum PathKind {
     Expr {
-        expr_ctx: ExprCtx,
+        expr_ctx: PathExprCtx,
     },
     Type {
         location: TypeLocation,
@@ -132,9 +132,9 @@ pub(crate) struct AttrCtx {
 }
 
 #[derive(Debug, PartialEq, Eq)]
-pub(crate) struct ExprCtx {
+pub(crate) struct PathExprCtx {
     pub(crate) in_block_expr: bool,
-    pub(crate) in_loop_body: bool,
+    pub(crate) in_breakable: BreakableKind,
     pub(crate) after_if_expr: bool,
     /// Whether this expression is the direct condition of an if or while expression
     pub(crate) in_condition: bool,
@@ -221,7 +221,7 @@ pub(crate) enum TypeAscriptionTarget {
 
 /// The kind of item list a [`PathKind::Item`] belongs to.
 #[derive(Debug, PartialEq, Eq)]
-pub(super) enum ItemListKind {
+pub(crate) enum ItemListKind {
     SourceFile,
     Module,
     Impl,
@@ -231,7 +231,7 @@ pub(super) enum ItemListKind {
 }
 
 #[derive(Debug)]
-pub(super) enum Qualified {
+pub(crate) enum Qualified {
     No,
     With {
         path: ast::Path,
@@ -259,37 +259,37 @@ pub(super) enum Qualified {
 
 /// The state of the pattern we are completing.
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub(super) struct PatternContext {
-    pub(super) refutability: PatternRefutability,
-    pub(super) param_ctx: Option<ParamContext>,
-    pub(super) has_type_ascription: bool,
-    pub(super) parent_pat: Option<ast::Pat>,
-    pub(super) ref_token: Option<SyntaxToken>,
-    pub(super) mut_token: Option<SyntaxToken>,
+pub(crate) struct PatternContext {
+    pub(crate) refutability: PatternRefutability,
+    pub(crate) param_ctx: Option<ParamContext>,
+    pub(crate) has_type_ascription: bool,
+    pub(crate) parent_pat: Option<ast::Pat>,
+    pub(crate) ref_token: Option<SyntaxToken>,
+    pub(crate) mut_token: Option<SyntaxToken>,
     /// The record pattern this name or ref is a field of
-    pub(super) record_pat: Option<ast::RecordPat>,
-    pub(super) impl_: Option<ast::Impl>,
+    pub(crate) record_pat: Option<ast::RecordPat>,
+    pub(crate) impl_: Option<ast::Impl>,
     /// List of missing variants in a match expr
-    pub(super) missing_variants: Vec<hir::Variant>,
+    pub(crate) missing_variants: Vec<hir::Variant>,
 }
 
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub(super) struct ParamContext {
-    pub(super) param_list: ast::ParamList,
-    pub(super) param: ast::Param,
-    pub(super) kind: ParamKind,
+pub(crate) struct ParamContext {
+    pub(crate) param_list: ast::ParamList,
+    pub(crate) param: ast::Param,
+    pub(crate) kind: ParamKind,
 }
 
 /// The state of the lifetime we are completing.
 #[derive(Debug)]
-pub(super) struct LifetimeContext {
-    pub(super) lifetime: Option<ast::Lifetime>,
-    pub(super) kind: LifetimeKind,
+pub(crate) struct LifetimeContext {
+    pub(crate) lifetime: Option<ast::Lifetime>,
+    pub(crate) kind: LifetimeKind,
 }
 
 /// The kind of lifetime we are completing.
 #[derive(Debug)]
-pub(super) enum LifetimeKind {
+pub(crate) enum LifetimeKind {
     LifetimeParam { is_decl: bool, param: ast::LifetimeParam },
     Lifetime,
     LabelRef,
@@ -298,16 +298,16 @@ pub(super) enum LifetimeKind {
 
 /// The state of the name we are completing.
 #[derive(Debug)]
-pub(super) struct NameContext {
+pub(crate) struct NameContext {
     #[allow(dead_code)]
-    pub(super) name: Option<ast::Name>,
-    pub(super) kind: NameKind,
+    pub(crate) name: Option<ast::Name>,
+    pub(crate) kind: NameKind,
 }
 
 /// The kind of the name we are completing.
 #[derive(Debug)]
 #[allow(dead_code)]
-pub(super) enum NameKind {
+pub(crate) enum NameKind {
     Const,
     ConstParam,
     Enum,
@@ -331,15 +331,15 @@ pub(super) enum NameKind {
 
 /// The state of the NameRef we are completing.
 #[derive(Debug)]
-pub(super) struct NameRefContext {
+pub(crate) struct NameRefContext {
     /// NameRef syntax in the original file
-    pub(super) nameref: Option<ast::NameRef>,
-    pub(super) kind: NameRefKind,
+    pub(crate) nameref: Option<ast::NameRef>,
+    pub(crate) kind: NameRefKind,
 }
 
 /// The kind of the NameRef we are completing.
 #[derive(Debug)]
-pub(super) enum NameRefKind {
+pub(crate) enum NameRefKind {
     Path(PathCompletionCtx),
     DotAccess(DotAccess),
     /// Position where we are only interested in keyword completions
@@ -355,7 +355,7 @@ pub(super) enum NameRefKind {
 
 /// The identifier we are currently completing.
 #[derive(Debug)]
-pub(super) enum CompletionAnalysis {
+pub(crate) enum CompletionAnalysis {
     Name(NameContext),
     NameRef(NameRefContext),
     Lifetime(LifetimeContext),
@@ -376,14 +376,15 @@ pub(super) enum CompletionAnalysis {
 
 /// Information about the field or method access we are completing.
 #[derive(Debug)]
-pub(super) struct DotAccess {
-    pub(super) receiver: Option<ast::Expr>,
-    pub(super) receiver_ty: Option<TypeInfo>,
-    pub(super) kind: DotAccessKind,
+pub(crate) struct DotAccess {
+    pub(crate) receiver: Option<ast::Expr>,
+    pub(crate) receiver_ty: Option<TypeInfo>,
+    pub(crate) kind: DotAccessKind,
+    pub(crate) ctx: DotAccessExprCtx,
 }
 
 #[derive(Debug)]
-pub(super) enum DotAccessKind {
+pub(crate) enum DotAccessKind {
     Field {
         /// True if the receiver is an integer and there is no ident in the original file after it yet
         /// like `0.$0`
@@ -394,6 +395,21 @@ pub(super) enum DotAccessKind {
     },
 }
 
+#[derive(Debug, PartialEq, Eq)]
+pub(crate) struct DotAccessExprCtx {
+    pub(crate) in_block_expr: bool,
+    pub(crate) in_breakable: BreakableKind,
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub(crate) enum BreakableKind {
+    None,
+    Loop,
+    For,
+    While,
+    Block,
+}
+
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum ParamKind {
     Function(ast::Fn),
@@ -404,39 +420,39 @@ pub(crate) enum ParamKind {
 /// exactly is the cursor, syntax-wise.
 #[derive(Debug)]
 pub(crate) struct CompletionContext<'a> {
-    pub(super) sema: Semantics<'a, RootDatabase>,
-    pub(super) scope: SemanticsScope<'a>,
-    pub(super) db: &'a RootDatabase,
-    pub(super) config: &'a CompletionConfig,
-    pub(super) position: FilePosition,
+    pub(crate) sema: Semantics<'a, RootDatabase>,
+    pub(crate) scope: SemanticsScope<'a>,
+    pub(crate) db: &'a RootDatabase,
+    pub(crate) config: &'a CompletionConfig,
+    pub(crate) position: FilePosition,
 
     /// The token before the cursor, in the original file.
-    pub(super) original_token: SyntaxToken,
+    pub(crate) original_token: SyntaxToken,
     /// The token before the cursor, in the macro-expanded file.
-    pub(super) token: SyntaxToken,
+    pub(crate) token: SyntaxToken,
     /// The crate of the current file.
-    pub(super) krate: hir::Crate,
+    pub(crate) krate: hir::Crate,
     /// The module of the `scope`.
-    pub(super) module: hir::Module,
+    pub(crate) module: hir::Module,
     /// Whether nightly toolchain is used. Cached since this is looked up a lot.
     is_nightly: bool,
 
     /// The expected name of what we are completing.
     /// This is usually the parameter name of the function argument we are completing.
-    pub(super) expected_name: Option<NameOrNameRef>,
+    pub(crate) expected_name: Option<NameOrNameRef>,
     /// The expected type of what we are completing.
-    pub(super) expected_type: Option<Type>,
+    pub(crate) expected_type: Option<Type>,
 
-    pub(super) qualifier_ctx: QualifierCtx,
+    pub(crate) qualifier_ctx: QualifierCtx,
 
-    pub(super) locals: FxHashMap<Name, Local>,
+    pub(crate) locals: FxHashMap<Name, Local>,
 
     /// The module depth of the current module of the cursor position.
     /// - crate-root
     ///  - mod foo
     ///   - mod bar
     /// Here depth will be 2
-    pub(super) depth_from_crate_root: usize,
+    pub(crate) depth_from_crate_root: usize,
 }
 
 impl CompletionContext<'_> {
@@ -634,7 +650,7 @@ impl CompletionContext<'_> {
 
 // CompletionContext construction
 impl<'a> CompletionContext<'a> {
-    pub(super) fn new(
+    pub(crate) fn new(
         db: &'a RootDatabase,
         position @ FilePosition { file_id, offset }: FilePosition,
         config: &'a CompletionConfig,
@@ -649,7 +665,7 @@ impl<'a> CompletionContext<'a> {
         // actual completion.
         let file_with_fake_ident = {
             let parse = db.parse(file_id);
-            let edit = Indel::insert(offset, COMPLETION_MARKER.to_string());
+            let edit = Indel::insert(offset, COMPLETION_MARKER.to_owned());
             parse.reparse(&edit).tree()
         };
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index c06b64df1c5..92af6889778 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -11,10 +11,11 @@ use syntax::{
 };
 
 use crate::context::{
-    AttrCtx, CompletionAnalysis, DotAccess, DotAccessKind, ExprCtx, ItemListKind, LifetimeContext,
-    LifetimeKind, NameContext, NameKind, NameRefContext, NameRefKind, ParamContext, ParamKind,
-    PathCompletionCtx, PathKind, PatternContext, PatternRefutability, Qualified, QualifierCtx,
-    TypeAscriptionTarget, TypeLocation, COMPLETION_MARKER,
+    AttrCtx, BreakableKind, CompletionAnalysis, DotAccess, DotAccessExprCtx, DotAccessKind,
+    ItemListKind, LifetimeContext, LifetimeKind, NameContext, NameKind, NameRefContext,
+    NameRefKind, ParamContext, ParamKind, PathCompletionCtx, PathExprCtx, PathKind, PatternContext,
+    PatternRefutability, Qualified, QualifierCtx, TypeAscriptionTarget, TypeLocation,
+    COMPLETION_MARKER,
 };
 
 struct ExpansionResult {
@@ -623,7 +624,8 @@ fn classify_name_ref(
                 let kind = NameRefKind::DotAccess(DotAccess {
                     receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
                     kind: DotAccessKind::Field { receiver_is_ambiguous_float_literal },
-                    receiver
+                    receiver,
+                    ctx: DotAccessExprCtx { in_block_expr: is_in_block(field.syntax()), in_breakable: is_in_breakable(field.syntax()) }
                 });
                 return Some(make_res(kind));
             },
@@ -636,7 +638,8 @@ fn classify_name_ref(
                 let kind = NameRefKind::DotAccess(DotAccess {
                     receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
                     kind: DotAccessKind::Method { has_parens: method.arg_list().map_or(false, |it| it.l_paren_token().is_some()) },
-                    receiver
+                    receiver,
+                    ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
                 });
                 return Some(make_res(kind));
             },
@@ -659,13 +662,6 @@ fn classify_name_ref(
         use_tree_parent: false,
     };
 
-    let is_in_block = |it: &SyntaxNode| {
-        it.parent()
-            .map(|node| {
-                ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind())
-            })
-            .unwrap_or(false)
-    };
     let func_update_record = |syn: &SyntaxNode| {
         if let Some(record_expr) = syn.ancestors().nth(2).and_then(ast::RecordExpr::cast) {
             find_node_in_file_compensated(sema, original_file, &record_expr)
@@ -932,7 +928,7 @@ fn classify_name_ref(
     let make_path_kind_expr = |expr: ast::Expr| {
         let it = expr.syntax();
         let in_block_expr = is_in_block(it);
-        let in_loop_body = is_in_loop_body(it);
+        let in_loop_body = is_in_breakable(it);
         let after_if_expr = after_if_expr(it.clone());
         let ref_expr_parent =
             path.as_single_name_ref().and_then(|_| it.parent()).and_then(ast::RefExpr::cast);
@@ -998,9 +994,9 @@ fn classify_name_ref(
         };
 
         PathKind::Expr {
-            expr_ctx: ExprCtx {
+            expr_ctx: PathExprCtx {
                 in_block_expr,
-                in_loop_body,
+                in_breakable: in_loop_body,
                 after_if_expr,
                 in_condition,
                 ref_expr_parent,
@@ -1202,7 +1198,7 @@ fn classify_name_ref(
     if path_ctx.is_trivial_path() {
         // fetch the full expression that may have qualifiers attached to it
         let top_node = match path_ctx.kind {
-            PathKind::Expr { expr_ctx: ExprCtx { in_block_expr: true, .. } } => {
+            PathKind::Expr { expr_ctx: PathExprCtx { in_block_expr: true, .. } } => {
                 parent.ancestors().find(|it| ast::PathExpr::can_cast(it.kind())).and_then(|p| {
                     let parent = p.parent()?;
                     if ast::StmtList::can_cast(parent.kind()) {
@@ -1467,21 +1463,30 @@ fn is_in_token_of_for_loop(path: &ast::Path) -> bool {
     .unwrap_or(false)
 }
 
-fn is_in_loop_body(node: &SyntaxNode) -> bool {
+fn is_in_breakable(node: &SyntaxNode) -> BreakableKind {
     node.ancestors()
         .take_while(|it| it.kind() != SyntaxKind::FN && it.kind() != SyntaxKind::CLOSURE_EXPR)
         .find_map(|it| {
-            let loop_body = match_ast! {
+            let (breakable, loop_body) = match_ast! {
                 match it {
-                    ast::ForExpr(it) => it.loop_body(),
-                    ast::WhileExpr(it) => it.loop_body(),
-                    ast::LoopExpr(it) => it.loop_body(),
-                    _ => None,
+                    ast::ForExpr(it) => (BreakableKind::For, it.loop_body()),
+                    ast::WhileExpr(it) => (BreakableKind::While, it.loop_body()),
+                    ast::LoopExpr(it) => (BreakableKind::Loop, it.loop_body()),
+                    ast::BlockExpr(it) => return it.label().map(|_| BreakableKind::Block),
+                    _ => return None,
                 }
             };
-            loop_body.filter(|it| it.syntax().text_range().contains_range(node.text_range()))
+            loop_body
+                .filter(|it| it.syntax().text_range().contains_range(node.text_range()))
+                .map(|_| breakable)
         })
-        .is_some()
+        .unwrap_or(BreakableKind::None)
+}
+
+fn is_in_block(node: &SyntaxNode) -> bool {
+    node.parent()
+        .map(|node| ast::ExprStmt::can_cast(node.kind()) || ast::StmtList::can_cast(node.kind()))
+        .unwrap_or(false)
 }
 
 fn previous_non_trivia_token(e: impl Into<SyntaxElement>) -> Option<SyntaxToken> {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
index bcf169f4653..8552a20392a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -553,7 +553,7 @@ impl Builder {
         self.detail = detail.map(Into::into);
         if let Some(detail) = &self.detail {
             if never!(detail.contains('\n'), "multiline detail:\n{}", detail) {
-                self.detail = Some(detail.split('\n').next().unwrap().to_string());
+                self.detail = Some(detail.split('\n').next().unwrap().to_owned());
             }
         }
         self
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 733523d3694..912f2fba2b3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -64,6 +64,7 @@ pub use crate::{
 // - `expr.ref` -> `&expr`
 // - `expr.refm` -> `&mut expr`
 // - `expr.let` -> `let $0 = expr;`
+// - `expr.lete` -> `let $1 = expr else { $0 };`
 // - `expr.letm` -> `let mut $0 = expr;`
 // - `expr.not` -> `!expr`
 // - `expr.dbg` -> `dbg!(expr)`
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
index 4d49d2f4987..2ed080a8347 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -112,7 +112,7 @@ impl<'a> RenderContext<'a> {
         };
         is_assoc_deprecated
             || assoc
-                .containing_trait_or_trait_impl(db)
+                .container_or_implemented_trait(db)
                 .map(|trait_| self.is_deprecated(trait_))
                 .unwrap_or(false)
     }
@@ -167,14 +167,14 @@ pub(crate) fn render_field(
         if !expected_fn_type {
             if let Some(receiver) = &dot_access.receiver {
                 if let Some(receiver) = ctx.completion.sema.original_ast_node(receiver.clone()) {
-                    builder.insert(receiver.syntax().text_range().start(), "(".to_string());
-                    builder.insert(ctx.source_range().end(), ")".to_string());
+                    builder.insert(receiver.syntax().text_range().start(), "(".to_owned());
+                    builder.insert(ctx.source_range().end(), ")".to_owned());
 
                     let is_parens_needed =
                         !matches!(dot_access.kind, DotAccessKind::Method { has_parens: true });
 
                     if is_parens_needed {
-                        builder.insert(ctx.source_range().end(), "()".to_string());
+                        builder.insert(ctx.source_range().end(), "()".to_owned());
                     }
                 }
             }
@@ -2199,12 +2199,14 @@ fn main() {
                 sn while []
                 sn ref []
                 sn refm []
+                sn deref []
                 sn unsafe []
                 sn match []
                 sn box []
                 sn dbg []
                 sn dbgr []
                 sn call []
+                sn return []
             "#]],
         );
     }
@@ -2227,6 +2229,7 @@ fn main() {
                 me f() []
                 sn ref []
                 sn refm []
+                sn deref []
                 sn unsafe []
                 sn match []
                 sn box []
@@ -2235,6 +2238,7 @@ fn main() {
                 sn call []
                 sn let []
                 sn letm []
+                sn return []
             "#]],
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
index a2bfac994ff..0d24882156d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs
@@ -23,7 +23,7 @@ fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem>
         .set_relevance(ctx.completion_relevance());
 
     if let Some(actm) = const_.as_assoc_item(db) {
-        if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
+        if let Some(trt) = actm.container_or_implemented_trait(db) {
             item.trait_name(trt.name(db).to_smol_str());
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index 4ae7ea861c7..27186a2b7ff 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -75,7 +75,7 @@ fn render(
     let ret_type = func.ret_type(db);
     let assoc_item = func.as_assoc_item(db);
 
-    let trait_ = assoc_item.and_then(|trait_| trait_.containing_trait_or_trait_impl(db));
+    let trait_ = assoc_item.and_then(|trait_| trait_.container_or_implemented_trait(db));
     let is_op_method = trait_.map_or(false, |trait_| completion.is_ops_trait(trait_));
 
     let is_item_from_notable_trait =
@@ -145,7 +145,7 @@ fn render(
         }
         None => {
             if let Some(actm) = assoc_item {
-                if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
+                if let Some(trt) = actm.container_or_implemented_trait(db) {
                     item.trait_name(trt.name(db).to_smol_str());
                 }
             }
@@ -184,12 +184,12 @@ pub(super) fn add_call_parens<'b>(
                         }
                         None => {
                             let name = match param.ty().as_adt() {
-                                None => "_".to_string(),
+                                None => "_".to_owned(),
                                 Some(adt) => adt
                                     .name(ctx.db)
                                     .as_text()
                                     .map(|s| to_lower_snake_case(s.as_str()))
-                                    .unwrap_or_else(|| "_".to_string()),
+                                    .unwrap_or_else(|| "_".to_owned()),
                             };
                             f(&format_args!("${{{}:{name}}}", index + offset))
                         }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
index a5f851566cb..c07966f7a7a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs
@@ -140,7 +140,7 @@ fn render_pat(
         StructKind::Record => {
             render_record_as_pat(ctx.db(), ctx.snippet_cap(), fields, name, fields_omitted)
         }
-        StructKind::Unit => name.to_string(),
+        StructKind::Unit => name.to_owned(),
     };
 
     let needs_ascription = matches!(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
index b192309e93f..8f80793dd72 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs
@@ -47,7 +47,7 @@ fn render(
         .set_relevance(ctx.completion_relevance());
 
     if let Some(actm) = type_alias.as_assoc_item(db) {
-        if let Some(trt) = actm.containing_trait_or_trait_impl(db) {
+        if let Some(trt) = actm.container_or_implemented_trait(db) {
             item.trait_name(trt.name(db).to_smol_str());
         }
     }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
index a9a01a3a30f..28238de4559 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/variant.rs
@@ -23,7 +23,7 @@ pub(crate) fn render_record_lit(
     path: &str,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
-        return RenderedLiteral { literal: path.to_string(), detail: path.to_string() };
+        return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
     }
     let completions = fields.iter().enumerate().format_with(", ", |(idx, field), f| {
         if snippet_cap.is_some() {
@@ -52,7 +52,7 @@ pub(crate) fn render_tuple_lit(
     path: &str,
 ) -> RenderedLiteral {
     if snippet_cap.is_none() {
-        return RenderedLiteral { literal: path.to_string(), detail: path.to_string() };
+        return RenderedLiteral { literal: path.to_owned(), detail: path.to_owned() };
     }
     let completions = fields.iter().enumerate().format_with(", ", |(idx, _), f| {
         if snippet_cap.is_some() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 758c254a882..78907a2896c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -362,6 +362,27 @@ fn completes_in_loop_ctx() {
             sn ppd
         "#]],
     );
+    check_empty(
+        r"fn my() { loop { foo.$0 } }",
+        expect![[r#"
+            sn box    Box::new(expr)
+            sn break  break expr
+            sn call   function(expr)
+            sn dbg    dbg!(expr)
+            sn dbgr   dbg!(&expr)
+            sn deref  *expr
+            sn if     if expr {}
+            sn let    let
+            sn letm   let mut
+            sn match  match expr {}
+            sn not    !expr
+            sn ref    &expr
+            sn refm   &mut expr
+            sn return return expr
+            sn unsafe unsafe {}
+            sn while  while expr {}
+        "#]],
+    );
 }
 
 #[test]
@@ -1115,9 +1136,11 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     );
@@ -1139,9 +1162,11 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     );
@@ -1167,9 +1192,11 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     );
@@ -1191,9 +1218,11 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     );
@@ -1215,9 +1244,11 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     );
@@ -1238,11 +1269,13 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn if     if expr {}
             sn match  match expr {}
             sn not    !expr
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
             sn while  while expr {}
         "#]],
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
index 2d6234e310c..613f33309f5 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/proc_macros.rs
@@ -29,11 +29,13 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn let    let
             sn letm   let mut
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     )
@@ -60,11 +62,13 @@ fn main() {
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn let    let
             sn letm   let mut
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     )
@@ -93,11 +97,13 @@ fn main() {}
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn let    let
             sn letm   let mut
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     )
@@ -126,11 +132,13 @@ fn main() {}
             sn call   function(expr)
             sn dbg    dbg!(expr)
             sn dbgr   dbg!(&expr)
+            sn deref  *expr
             sn let    let
             sn letm   let mut
             sn match  match expr {}
             sn ref    &expr
             sn refm   &mut expr
+            sn return return expr
             sn unsafe unsafe {}
         "#]],
     )
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
index f96fb71f289..a87d16c789f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs
@@ -1157,11 +1157,13 @@ fn here_we_go() {
             sn call              function(expr)
             sn dbg               dbg!(expr)
             sn dbgr              dbg!(&expr)
+            sn deref             *expr
             sn let               let
             sn letm              let mut
             sn match             match expr {}
             sn ref               &expr
             sn refm              &mut expr
+            sn return            return expr
             sn unsafe            unsafe {}
         "#]],
     );
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index 81f2f87d962..d95d94ec72e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -206,7 +206,7 @@ impl Definition {
             // docs are missing, for assoc items of trait impls try to fall back to the docs of the
             // original item of the trait
             let assoc = self.as_assoc_item(db)?;
-            let trait_ = assoc.containing_trait_impl(db)?;
+            let trait_ = assoc.implemented_trait(db)?;
             let name = Some(assoc.name(db)?);
             let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
             item.docs(db)
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
index 722517a7677..4edfa37b329 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/famous_defs.rs
@@ -1,7 +1,7 @@
 //! See [`FamousDefs`].
 
 use base_db::{CrateOrigin, LangCrateOrigin, SourceDatabase};
-use hir::{Crate, Enum, Macro, Module, ScopeDef, Semantics, Trait};
+use hir::{Crate, Enum, Function, Macro, Module, ScopeDef, Semantics, Trait};
 
 use crate::RootDatabase;
 
@@ -110,6 +110,10 @@ impl FamousDefs<'_, '_> {
         self.find_macro("core:macros:builtin:derive")
     }
 
+    pub fn core_mem_drop(&self) -> Option<Function> {
+        self.find_function("core:mem:drop")
+    }
+
     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
         IntoIterator::into_iter([
             self.std(),
@@ -149,6 +153,13 @@ impl FamousDefs<'_, '_> {
         }
     }
 
+    fn find_function(&self, path: &str) -> Option<Function> {
+        match self.find_def(path)? {
+            hir::ScopeDef::ModuleDef(hir::ModuleDef::Function(it)) => Some(it),
+            _ => None,
+        }
+    }
+
     fn find_lang_crate(&self, origin: LangCrateOrigin) -> Option<Crate> {
         let krate = self.1;
         let db = self.0.db;
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
index 677c8fd54c0..2fc07933200 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/generated/lints.rs
@@ -5047,17 +5047,6 @@ against are compatible with those of the `#[ffi_pure]`.
 "##,
     },
     Lint {
-        label: "ffi_returns_twice",
-        description: r##"# `ffi_returns_twice`
-
-The tracking issue for this feature is: [#58314]
-
-[#58314]: https://github.com/rust-lang/rust/issues/58314
-
-------------------------
-"##,
-    },
-    Lint {
         label: "float_gamma",
         description: r##"# `float_gamma`
 
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
index cb3f01f3458..a71d8e9002d 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/import_assets.rs
@@ -529,7 +529,7 @@ fn trait_applicable_items(
             return None;
         }
 
-        let assoc_item_trait = assoc.containing_trait(db)?;
+        let assoc_item_trait = assoc.container_trait(db)?;
         if related_traits.contains(&assoc_item_trait) {
             return None;
         }
@@ -550,8 +550,7 @@ fn trait_applicable_items(
             None,
             |assoc| {
                 if required_assoc_items.contains(&assoc) {
-                    let located_trait =
-                        assoc.containing_trait(db).filter(|&it| scope_filter(it))?;
+                    let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
                     let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
                     let import_path = trait_import_paths
                         .entry(trait_item)
@@ -576,8 +575,7 @@ fn trait_applicable_items(
             |function| {
                 let assoc = function.as_assoc_item(db)?;
                 if required_assoc_items.contains(&assoc) {
-                    let located_trait =
-                        assoc.containing_trait(db).filter(|&it| scope_filter(it))?;
+                    let located_trait = assoc.container_trait(db).filter(|&it| scope_filter(it))?;
                     let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
                     let import_path = trait_import_paths
                         .entry(trait_item)
@@ -605,6 +603,7 @@ fn assoc_to_item(assoc: AssocItem) -> ItemInNs {
     }
 }
 
+#[tracing::instrument(skip_all)]
 fn get_mod_path(
     db: &RootDatabase,
     item_to_search: ItemInNs,
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
index f29f91eea84..bd5c464c557 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/imports/insert_use.rs
@@ -214,7 +214,7 @@ fn insert_use_with_alias_option(
         };
     }
 
-    let mut use_tree = make::use_tree(path.clone(), None, alias, false);
+    let mut use_tree = make::use_tree(path, None, alias, false);
     if mb == Some(MergeBehavior::One) && use_tree.path().is_some() {
         use_tree = use_tree.clone_for_update();
         use_tree.wrap_in_tree_list();
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
index fc230818193..49594aee9f3 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
@@ -203,7 +203,7 @@ mod tests {
     use expect_test::{expect, Expect};
 
     fn check(input: &str, expect: &Expect) {
-        let (output, exprs) = parse_format_exprs(input).unwrap_or(("-".to_string(), vec![]));
+        let (output, exprs) = parse_format_exprs(input).unwrap_or(("-".to_owned(), vec![]));
         let outcome_repr = if !exprs.is_empty() {
             format!("{output}; {}", with_placeholders(exprs).join(", "))
         } else {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/tests/sourcegen_lints.rs b/src/tools/rust-analyzer/crates/ide-db/src/tests/sourcegen_lints.rs
index c8cf87d3c20..86ed01c8e74 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/tests/sourcegen_lints.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/tests/sourcegen_lints.rs
@@ -52,7 +52,7 @@ pub struct LintGroup {
     generate_lint_descriptor(sh, &mut contents);
     contents.push('\n');
 
-    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_string());
+    let cargo = std::env::var("CARGO").unwrap_or_else(|_| "cargo".to_owned());
     let unstable_book = project_root().join("./target/unstable-book-gen");
     cmd!(
         sh,
@@ -241,6 +241,7 @@ fn unescape(s: &str) -> String {
     s.replace(r#"\""#, "").replace(r#"\n"#, "\n").replace(r#"\r"#, "")
 }
 
+#[allow(clippy::print_stderr)]
 fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
     let file_content = std::fs::read_to_string(path).unwrap();
     let mut clippy_lints: Vec<ClippyLint> = Vec::new();
@@ -282,7 +283,7 @@ fn generate_descriptor_clippy(buf: &mut String, path: &Path) {
             let line = &line[..up_to];
 
             let clippy_lint = clippy_lints.last_mut().expect("clippy lint must already exist");
-            clippy_lint.help = unescape(line).trim().to_string();
+            clippy_lint.help = unescape(line).trim().to_owned();
         }
     }
     clippy_lints.sort_by(|lint, lint2| lint.id.cmp(&lint2.id));
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
index bbdfd81d653..ee7c448bb89 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/traits.rs
@@ -75,7 +75,7 @@ pub fn get_missing_assoc_items(
 pub(crate) fn convert_to_def_in_trait(db: &dyn HirDatabase, def: Definition) -> Definition {
     (|| {
         let assoc = def.as_assoc_item(db)?;
-        let trait_ = assoc.containing_trait_impl(db)?;
+        let trait_ = assoc.implemented_trait(db)?;
         assoc_item_of_trait(db, assoc, trait_)
     })()
     .unwrap_or(def)
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 9f754f9c6fc..7db5ea04fbd 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -16,7 +16,7 @@ pub(crate) fn inactive_code(
     }
 
     let inactive = DnfExpr::new(d.cfg.clone()).why_inactive(&d.opts);
-    let mut message = "code is inactive due to #[cfg] directives".to_string();
+    let mut message = "code is inactive due to #[cfg] directives".to_owned();
 
     if let Some(inactive) = inactive {
         let inactive_reasons = inactive.to_string();
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
index 3b4d400912f..9f56e104145 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incoherent_impl.rs
@@ -9,7 +9,7 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::RustcHardError("E0210"),
-        "cannot define inherent `impl` for foreign type".to_string(),
+        "cannot define inherent `impl` for foreign type".to_owned(),
         InFile::new(d.file_id, d.impl_.into()),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index f5a6aa11979..dd64b93e454 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -52,7 +52,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
 
 #[cfg(test)]
 mod change_case {
-    use crate::tests::{check_diagnostics, check_fix};
+    use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
 
     #[test]
     fn test_rename_incorrect_case() {
@@ -388,14 +388,13 @@ mod F {
 
     #[test]
     fn complex_ignore() {
-        // FIXME: this should trigger errors for the second case.
         check_diagnostics(
             r#"
 trait T { fn a(); }
 struct U {}
 impl T for U {
     fn a() {
-        #[allow(non_snake_case)]
+        #[allow(non_snake_case, non_upper_case_globals)]
         trait __BitFlagsOk {
             const HiImAlsoBad: u8 = 2;
             fn Dirty(&self) -> bool { false }
@@ -403,7 +402,9 @@ impl T for U {
 
         trait __BitFlagsBad {
             const HiImAlsoBad: u8 = 2;
+               // ^^^^^^^^^^^ 💡 warn: Constant `HiImAlsoBad` should have UPPER_SNAKE_CASE name, e.g. `HI_IM_ALSO_BAD`
             fn Dirty(&self) -> bool { false }
+            // ^^^^^💡 warn: Function `Dirty` should have snake_case name, e.g. `dirty`
         }
     }
 }
@@ -462,20 +463,60 @@ extern {
     }
 
     #[test]
-    fn bug_traits_arent_checked() {
-        // FIXME: Traits and functions in traits aren't currently checked by
-        // r-a, even though rustc will complain about them.
+    fn incorrect_trait_and_assoc_item_names() {
         check_diagnostics(
             r#"
 trait BAD_TRAIT {
+   // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
+    const bad_const: u8;
+       // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
+    type BAD_TYPE;
+      // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType`
     fn BAD_FUNCTION();
+    // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
     fn BadFunction();
+    // ^^^^^^^^^^^ 💡 warn: Function `BadFunction` should have snake_case name, e.g. `bad_function`
 }
     "#,
         );
     }
 
     #[test]
+    fn no_diagnostics_for_trait_impl_assoc_items_except_pats_in_body() {
+        cov_mark::check!(trait_impl_assoc_const_incorrect_case_ignored);
+        cov_mark::check!(trait_impl_assoc_type_incorrect_case_ignored);
+        cov_mark::check_count!(trait_impl_assoc_func_name_incorrect_case_ignored, 2);
+        check_diagnostics_with_disabled(
+            r#"
+trait BAD_TRAIT {
+   // ^^^^^^^^^ 💡 warn: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
+    const bad_const: u8;
+       // ^^^^^^^^^ 💡 warn: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
+    type BAD_TYPE;
+      // ^^^^^^^^ 💡 warn: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType`
+    fn BAD_FUNCTION(BAD_PARAM: u8);
+    // ^^^^^^^^^^^^ 💡 warn: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
+                 // ^^^^^^^^^ 💡 warn: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
+    fn BadFunction();
+    // ^^^^^^^^^^^ 💡 warn: Function `BadFunction` should have snake_case name, e.g. `bad_function`
+}
+
+impl BAD_TRAIT for () {
+    const bad_const: u8 = 0;
+    type BAD_TYPE = ();
+    fn BAD_FUNCTION(BAD_PARAM: u8) {
+                 // ^^^^^^^^^ 💡 warn: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
+        let BAD_VAR = 0;
+         // ^^^^^^^ 💡 warn: Variable `BAD_VAR` should have snake_case name, e.g. `bad_var`
+    }
+    fn BadFunction() {}
+}
+    "#,
+            std::iter::once("unused_variables".to_owned()),
+        );
+    }
+
+    #[test]
     fn allow_attributes() {
         check_diagnostics(
             r#"
@@ -519,6 +560,14 @@ pub const some_const: u8 = 10;
 
 #[allow(non_upper_case_globals)]
 pub static SomeStatic: u8 = 10;
+
+#[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+trait BAD_TRAIT {
+    const bad_const: u8;
+    type BAD_TYPE;
+    fn BAD_FUNCTION(BAD_PARAM: u8);
+    fn BadFunction();
+}
     "#,
         );
     }
@@ -578,6 +627,20 @@ pub const some_const: u8 = 10;
 #[deny(non_upper_case_globals)]
 pub static SomeStatic: u8 = 10;
          //^^^^^^^^^^ 💡 error: Static variable `SomeStatic` should have UPPER_SNAKE_CASE name, e.g. `SOME_STATIC`
+
+#[deny(non_snake_case, non_camel_case_types, non_upper_case_globals)]
+trait BAD_TRAIT {
+   // ^^^^^^^^^ 💡 error: Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
+    const bad_const: u8;
+       // ^^^^^^^^^ 💡 error: Constant `bad_const` should have UPPER_SNAKE_CASE name, e.g. `BAD_CONST`
+    type BAD_TYPE;
+      // ^^^^^^^^ 💡 error: Type alias `BAD_TYPE` should have CamelCase name, e.g. `BadType`
+    fn BAD_FUNCTION(BAD_PARAM: u8);
+    // ^^^^^^^^^^^^ 💡 error: Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
+                 // ^^^^^^^^^ 💡 error: Parameter `BAD_PARAM` should have snake_case name, e.g. `bad_param`
+    fn BadFunction();
+    // ^^^^^^^^^^^ 💡 error: Function `BadFunction` should have snake_case name, e.g. `bad_function`
+}
     "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index d330973aaaa..241fddbb906 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -42,12 +42,12 @@ impl State {
             v.push("Deserialize");
         }
         match v.as_slice() {
-            [] => "".to_string(),
+            [] => "".to_owned(),
             [x] => format!("#[derive({x})]\n"),
             [x, y] => format!("#[derive({x}, {y})]\n"),
             _ => {
                 never!();
-                "".to_string()
+                "".to_owned()
             }
         }
     }
@@ -176,7 +176,7 @@ mod tests {
     #[test]
     fn diagnostic_for_simple_case() {
         let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("syntax-error".to_string());
+        config.disabled.insert("syntax-error".to_owned());
         check_diagnostics_with_config(
             config,
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index fc5c715981f..e4cb53f3a2f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -99,7 +99,7 @@ pub macro panic {
 
         // FIXME: This is a false-positive, the file is actually linked in via
         // `include!` macro
-        config.disabled.insert("unlinked-file".to_string());
+        config.disabled.insert("unlinked-file".to_owned());
 
         check_diagnostics_with_config(
             config,
@@ -268,8 +268,8 @@ fn f() {
     #[test]
     fn include_does_not_break_diagnostics() {
         let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("inactive-code".to_string());
-        config.disabled.insert("unlinked-file".to_string());
+        config.disabled.insert("inactive-code".to_owned());
+        config.disabled.insert("unlinked-file".to_owned());
         check_diagnostics_with_config(
             config,
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
index 66ebf593505..41c762c85b2 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mismatched_arg_count.rs
@@ -199,7 +199,7 @@ fn f() {
         // future, but we shouldn't emit an argument count diagnostic here
         check_diagnostics(
             r#"
-trait Foo { fn method(&self, arg: usize) {} }
+trait Foo { fn method(&self, _arg: usize) {} }
 
 fn f() {
     let x;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
index 37ac912f064..c70f39eb286 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -59,9 +59,15 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
 
     let current_module =
         ctx.sema.scope(d.field_list_parent.to_node(&root).syntax()).map(|it| it.module());
+    let range = InFile::new(d.file, d.field_list_parent.text_range())
+        .original_node_file_range_rooted(ctx.sema.db);
 
-    let build_text_edit = |parent_syntax, new_syntax: &SyntaxNode, old_syntax| {
+    let build_text_edit = |new_syntax: &SyntaxNode, old_syntax| {
         let edit = {
+            let old_range = ctx.sema.original_range_opt(old_syntax)?;
+            if old_range.file_id != range.file_id {
+                return None;
+            }
             let mut builder = TextEdit::builder();
             if d.file.is_macro() {
                 // we can't map the diff up into the macro input unfortunately, as the macro loses all
@@ -69,8 +75,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 // This has the downside that the cursor will be moved in macros by doing it without a diff
                 // but that is a trade off we can make.
                 // FIXME: this also currently discards a lot of whitespace in the input... we really need a formatter here
-                let range = ctx.sema.original_range_opt(old_syntax)?;
-                builder.replace(range.range, new_syntax.to_string());
+                builder.replace(old_range.range, new_syntax.to_string());
             } else {
                 algo::diff(old_syntax, new_syntax).into_text_edit(&mut builder);
             }
@@ -79,8 +84,8 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
         Some(vec![fix(
             "fill_missing_fields",
             "Fill struct fields",
-            SourceChange::from_text_edit(d.file.original_file(ctx.sema.db), edit),
-            ctx.sema.original_range(parent_syntax).range,
+            SourceChange::from_text_edit(range.file_id, edit),
+            range.range,
         )])
     };
 
@@ -143,11 +148,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 );
                 new_field_list.add_field(field.clone_for_update());
             }
-            build_text_edit(
-                field_list_parent.syntax(),
-                new_field_list.syntax(),
-                old_field_list.syntax(),
-            )
+            build_text_edit(new_field_list.syntax(), old_field_list.syntax())
         }
         Either::Right(field_list_parent) => {
             let missing_fields = ctx.sema.record_pattern_missing_fields(field_list_parent);
@@ -160,11 +161,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                 ));
                 new_field_list.add_field(field.clone_for_update());
             }
-            build_text_edit(
-                field_list_parent.syntax(),
-                new_field_list.syntax(),
-                old_field_list.syntax(),
-            )
+            build_text_edit(new_field_list.syntax(), old_field_list.syntax())
         }
     }
 }
@@ -173,7 +170,7 @@ fn make_ty(ty: &hir::Type, db: &dyn HirDatabase, module: hir::Module) -> ast::Ty
     let ty_str = match ty.as_adt() {
         Some(adt) => adt.name(db).display(db.upcast()).to_string(),
         None => {
-            ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_string())
+            ty.display_source_code(db, module.into(), false).ok().unwrap_or_else(|| "_".to_owned())
         }
     };
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
index cb6d568442d..17dc679e055 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
@@ -31,7 +31,7 @@ mod tests {
     #[test]
     fn empty_body() {
         let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("syntax-error".to_string());
+        config.disabled.insert("syntax-error".to_owned());
         check_diagnostics_with_config(
             config,
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 773a075f8f5..bdb55a9d98a 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -19,7 +19,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Diagno
         for source in d.local.sources(ctx.sema.db) {
             let Some(ast) = source.name() else { continue };
             // FIXME: macros
-            edit_builder.insert(ast.value.syntax().text_range().start(), "mut ".to_string());
+            edit_builder.insert(ast.value.syntax().text_range().start(), "mut ".to_owned());
         }
         let edit = edit_builder.finish();
         Some(vec![fix(
@@ -86,7 +86,7 @@ pub(super) fn token(parent: &SyntaxNode, kind: SyntaxKind) -> Option<SyntaxToken
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix};
+    use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
 
     #[test]
     fn unused_mut_simple() {
@@ -428,7 +428,7 @@ fn main() {
 }
 "#,
         );
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 enum X {}
 fn g() -> X {
@@ -448,8 +448,9 @@ fn main(b: bool) {
     &mut x;
 }
 "#,
+            std::iter::once("remove-unnecessary-else".to_owned()),
         );
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn main(b: bool) {
     if b {
@@ -462,6 +463,7 @@ fn main(b: bool) {
     &mut x;
 }
 "#,
+            std::iter::once("remove-unnecessary-else".to_owned()),
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
index 3179a632e26..e91e64c81b0 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/private_field.rs
@@ -86,4 +86,30 @@ fn main() {
 "#,
         );
     }
+
+    #[test]
+    fn block_module_madness2() {
+        check_diagnostics(
+            r#"
+fn main() {
+    use crate as ForceParentBlockDefMap;
+    let strukt = {
+        use crate as ForceParentBlockDefMap;
+        {
+            pub struct Struct {
+                field: (),
+            }
+            {
+                use crate as ForceParentBlockDefMap;
+                {
+                    Struct { field: () }
+                }
+            }
+        }
+    };
+    strukt.field;
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
new file mode 100644
index 00000000000..a0d5d742d36
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_trailing_return.rs
@@ -0,0 +1,375 @@
+use hir::{db::ExpandDatabase, diagnostics::RemoveTrailingReturn};
+use ide_db::{assists::Assist, base_db::FileRange, source_change::SourceChange};
+use syntax::{ast, AstNode};
+use text_edit::TextEdit;
+
+use crate::{adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
+
+// Diagnostic: remove-trailing-return
+//
+// This diagnostic is triggered when there is a redundant `return` at the end of a function
+// or closure.
+pub(crate) fn remove_trailing_return(
+    ctx: &DiagnosticsContext<'_>,
+    d: &RemoveTrailingReturn,
+) -> Diagnostic {
+    let display_range = adjusted_display_range(ctx, d.return_expr, &|return_expr| {
+        return_expr
+            .syntax()
+            .parent()
+            .and_then(ast::ExprStmt::cast)
+            .map(|stmt| stmt.syntax().text_range())
+    });
+    Diagnostic::new(
+        DiagnosticCode::Clippy("needless_return"),
+        "replace return <expr>; with <expr>",
+        display_range,
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveTrailingReturn) -> Option<Vec<Assist>> {
+    let root = ctx.sema.db.parse_or_expand(d.return_expr.file_id);
+    let return_expr = d.return_expr.value.to_node(&root);
+    let stmt = return_expr.syntax().parent().and_then(ast::ExprStmt::cast);
+
+    let FileRange { range, file_id } =
+        ctx.sema.original_range_opt(stmt.as_ref().map_or(return_expr.syntax(), AstNode::syntax))?;
+    if Some(file_id) != d.return_expr.file_id.file_id() {
+        return None;
+    }
+
+    let replacement =
+        return_expr.expr().map_or_else(String::new, |expr| format!("{}", expr.syntax().text()));
+    let edit = TextEdit::replace(range, replacement);
+    let source_change = SourceChange::from_text_edit(file_id, edit);
+
+    Some(vec![fix(
+        "remove_trailing_return",
+        "Replace return <expr>; with <expr>",
+        source_change,
+        range,
+    )])
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{
+        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_fix_with_disabled,
+    };
+
+    #[test]
+    fn remove_trailing_return() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    return 2;
+} //^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_inner_function() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    fn bar() -> u8 {
+        return 2;
+    } //^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+    bar()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_closure() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    let bar = || return 2;
+    bar()      //^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+}
+"#,
+        );
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    let bar = || {
+        return 2;
+    };//^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+    bar()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_unit() {
+        check_diagnostics(
+            r#"
+fn foo() {
+    return
+} //^^^^^^ 💡 weak: replace return <expr>; with <expr>
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_no_semi() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    return 2
+} //^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_in_if() {
+        check_diagnostics_with_disabled(
+            r#"
+fn foo(x: usize) -> u8 {
+    if x > 0 {
+        return 1;
+      //^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+    } else {
+        return 0;
+    } //^^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+}
+"#,
+            std::iter::once("remove-unnecessary-else".to_owned()),
+        );
+    }
+
+    #[test]
+    fn remove_trailing_return_in_match() {
+        check_diagnostics(
+            r#"
+fn foo<T, E>(x: Result<T, E>) -> u8 {
+    match x {
+        Ok(_) => return 1,
+               //^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+        Err(_) => return 0,
+    }           //^^^^^^^^ 💡 weak: replace return <expr>; with <expr>
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_no_return_keyword() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    3
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_not_last_statement() {
+        check_diagnostics(
+            r#"
+fn foo() -> u8 {
+    if true { return 2; }
+    3
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_with_expr() {
+        check_fix(
+            r#"
+fn foo() -> u8 {
+    return$0 2;
+}
+"#,
+            r#"
+fn foo() -> u8 {
+    2
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_with_unit() {
+        check_fix(
+            r#"
+fn foo() {
+    return$0/*ensure tidy is happy*/
+}
+"#,
+            r#"
+fn foo() {
+    /*ensure tidy is happy*/
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_with_expr_no_semi() {
+        check_fix(
+            r#"
+fn foo() -> u8 {
+    return$0 2
+}
+"#,
+            r#"
+fn foo() -> u8 {
+    2
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_in_inner_function() {
+        check_fix(
+            r#"
+fn foo() -> u8 {
+    fn bar() -> u8 {
+        return$0 2;
+    }
+    bar()
+}
+"#,
+            r#"
+fn foo() -> u8 {
+    fn bar() -> u8 {
+        2
+    }
+    bar()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_in_closure() {
+        check_fix(
+            r#"
+fn foo() -> u8 {
+    let bar = || return$0 2;
+    bar()
+}
+"#,
+            r#"
+fn foo() -> u8 {
+    let bar = || 2;
+    bar()
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn foo() -> u8 {
+    let bar = || {
+        return$0 2;
+    };
+    bar()
+}
+"#,
+            r#"
+fn foo() -> u8 {
+    let bar = || {
+        2
+    };
+    bar()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_in_if() {
+        check_fix_with_disabled(
+            r#"
+fn foo(x: usize) -> u8 {
+    if x > 0 {
+        return$0 1;
+    } else {
+        0
+    }
+}
+"#,
+            r#"
+fn foo(x: usize) -> u8 {
+    if x > 0 {
+        1
+    } else {
+        0
+    }
+}
+"#,
+            std::iter::once("remove-unnecessary-else".to_owned()),
+        );
+        check_fix(
+            r#"
+fn foo(x: usize) -> u8 {
+    if x > 0 {
+        1
+    } else {
+        return$0 0;
+    }
+}
+"#,
+            r#"
+fn foo(x: usize) -> u8 {
+    if x > 0 {
+        1
+    } else {
+        0
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn replace_in_match() {
+        check_fix(
+            r#"
+fn foo<T, E>(x: Result<T, E>) -> u8 {
+    match x {
+        Ok(_) => return$0 1,
+        Err(_) => 0,
+    }
+}
+"#,
+            r#"
+fn foo<T, E>(x: Result<T, E>) -> u8 {
+    match x {
+        Ok(_) => 1,
+        Err(_) => 0,
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn foo<T, E>(x: Result<T, E>) -> u8 {
+    match x {
+        Ok(_) => 1,
+        Err(_) => return$0 0,
+    }
+}
+"#,
+            r#"
+fn foo<T, E>(x: Result<T, E>) -> u8 {
+    match x {
+        Ok(_) => 1,
+        Err(_) => 0,
+    }
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
new file mode 100644
index 00000000000..ae8241ec2c6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/remove_unnecessary_else.rs
@@ -0,0 +1,390 @@
+use hir::{db::ExpandDatabase, diagnostics::RemoveUnnecessaryElse, HirFileIdExt};
+use ide_db::{assists::Assist, source_change::SourceChange};
+use itertools::Itertools;
+use syntax::{
+    ast::{self, edit::IndentLevel},
+    AstNode, SyntaxToken, TextRange,
+};
+use text_edit::TextEdit;
+
+use crate::{
+    adjusted_display_range, fix, Diagnostic, DiagnosticCode, DiagnosticsContext, Severity,
+};
+
+// Diagnostic: remove-unnecessary-else
+//
+// This diagnostic is triggered when there is an `else` block for an `if` expression whose
+// then branch diverges (e.g. ends with a `return`, `continue`, `break` e.t.c).
+pub(crate) fn remove_unnecessary_else(
+    ctx: &DiagnosticsContext<'_>,
+    d: &RemoveUnnecessaryElse,
+) -> Diagnostic {
+    let display_range = adjusted_display_range(ctx, d.if_expr, &|if_expr| {
+        if_expr.else_token().as_ref().map(SyntaxToken::text_range)
+    });
+    Diagnostic::new(
+        DiagnosticCode::Ra("remove-unnecessary-else", Severity::WeakWarning),
+        "remove unnecessary else block",
+        display_range,
+    )
+    .with_fixes(fixes(ctx, d))
+}
+
+fn fixes(ctx: &DiagnosticsContext<'_>, d: &RemoveUnnecessaryElse) -> Option<Vec<Assist>> {
+    let root = ctx.sema.db.parse_or_expand(d.if_expr.file_id);
+    let if_expr = d.if_expr.value.to_node(&root);
+    let if_expr = ctx.sema.original_ast_node(if_expr.clone())?;
+
+    let mut indent = IndentLevel::from_node(if_expr.syntax());
+    let has_parent_if_expr = if_expr.syntax().parent().and_then(ast::IfExpr::cast).is_some();
+    if has_parent_if_expr {
+        indent = indent + 1;
+    }
+    let else_replacement = match if_expr.else_branch()? {
+        ast::ElseBranch::Block(ref block) => {
+            block.statements().map(|stmt| format!("\n{indent}{stmt}")).join("")
+        }
+        ast::ElseBranch::IfExpr(ref nested_if_expr) => {
+            format!("\n{indent}{nested_if_expr}")
+        }
+    };
+    let (replacement, range) = if has_parent_if_expr {
+        let base_indent = IndentLevel::from_node(if_expr.syntax());
+        let then_indent = base_indent + 1;
+        let then_child_indent = then_indent + 1;
+
+        let condition = if_expr.condition()?;
+        let then_stmts = if_expr
+            .then_branch()?
+            .statements()
+            .map(|stmt| format!("\n{then_child_indent}{stmt}"))
+            .join("");
+        let then_replacement =
+            format!("\n{then_indent}if {condition} {{{then_stmts}\n{then_indent}}}",);
+        let replacement = format!("{{{then_replacement}{else_replacement}\n{base_indent}}}");
+        (replacement, if_expr.syntax().text_range())
+    } else {
+        (
+            else_replacement,
+            TextRange::new(
+                if_expr.then_branch()?.syntax().text_range().end(),
+                if_expr.syntax().text_range().end(),
+            ),
+        )
+    };
+
+    let edit = TextEdit::replace(range, replacement);
+    let source_change =
+        SourceChange::from_text_edit(d.if_expr.file_id.original_file(ctx.sema.db), edit);
+
+    Some(vec![fix(
+        "remove_unnecessary_else",
+        "Remove unnecessary else block",
+        source_change,
+        range,
+    )])
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_diagnostics, check_diagnostics_with_disabled, check_fix};
+
+    fn check_diagnostics_with_needless_return_disabled(ra_fixture: &str) {
+        check_diagnostics_with_disabled(ra_fixture, std::iter::once("needless_return".to_owned()));
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_return() {
+        check_diagnostics_with_needless_return_disabled(
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    } else {
+    //^^^^ 💡 weak: remove unnecessary else block
+        do_something_else();
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    } else$0 {
+        do_something_else();
+    }
+}
+"#,
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    }
+    do_something_else();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_return2() {
+        check_diagnostics_with_needless_return_disabled(
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    } else if qux {
+    //^^^^ 💡 weak: remove unnecessary else block
+        do_something_else();
+    } else {
+        do_something_else2();
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    } else$0 if qux {
+        do_something_else();
+    } else {
+        do_something_else2();
+    }
+}
+"#,
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    }
+    if qux {
+        do_something_else();
+    } else {
+        do_something_else2();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_return_in_child_if_expr() {
+        check_diagnostics_with_needless_return_disabled(
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else if qux {
+        return bar;
+    } else {
+    //^^^^ 💡 weak: remove unnecessary else block
+        do_something_else();
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else if qux {
+        return bar;
+    } else$0 {
+        do_something_else();
+    }
+}
+"#,
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else {
+        if qux {
+            return bar;
+        }
+        do_something_else();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_break() {
+        check_diagnostics(
+            r#"
+fn test() {
+    loop {
+        if foo {
+            break;
+        } else {
+        //^^^^ 💡 weak: remove unnecessary else block
+            do_something_else();
+        }
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    loop {
+        if foo {
+            break;
+        } else$0 {
+            do_something_else();
+        }
+    }
+}
+"#,
+            r#"
+fn test() {
+    loop {
+        if foo {
+            break;
+        }
+        do_something_else();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_continue() {
+        check_diagnostics(
+            r#"
+fn test() {
+    loop {
+        if foo {
+            continue;
+        } else {
+        //^^^^ 💡 weak: remove unnecessary else block
+            do_something_else();
+        }
+    }
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    loop {
+        if foo {
+            continue;
+        } else$0 {
+            do_something_else();
+        }
+    }
+}
+"#,
+            r#"
+fn test() {
+    loop {
+        if foo {
+            continue;
+        }
+        do_something_else();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn remove_unnecessary_else_for_never() {
+        check_diagnostics(
+            r#"
+fn test() {
+    if foo {
+        never();
+    } else {
+    //^^^^ 💡 weak: remove unnecessary else block
+        do_something_else();
+    }
+}
+
+fn never() -> ! {
+    loop {}
+}
+"#,
+        );
+        check_fix(
+            r#"
+fn test() {
+    if foo {
+        never();
+    } else$0 {
+        do_something_else();
+    }
+}
+
+fn never() -> ! {
+    loop {}
+}
+"#,
+            r#"
+fn test() {
+    if foo {
+        never();
+    }
+    do_something_else();
+}
+
+fn never() -> ! {
+    loop {}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_no_else_branch() {
+        check_diagnostics(
+            r#"
+fn test() {
+    if foo {
+        return bar;
+    }
+
+    do_something_else();
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_no_divergence() {
+        check_diagnostics(
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else {
+        do_something_else();
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn no_diagnostic_if_no_divergence_in_else_branch() {
+        check_diagnostics_with_needless_return_disabled(
+            r#"
+fn test() {
+    if foo {
+        do_something();
+    } else {
+        return bar;
+    }
+}
+"#,
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
index 72896b891bd..6d3dcf31ab4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/replace_filter_map_next_with_find_map.rs
@@ -63,8 +63,8 @@ mod tests {
     #[track_caller]
     pub(crate) fn check_diagnostics(ra_fixture: &str) {
         let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("inactive-code".to_string());
-        config.disabled.insert("E0599".to_string());
+        config.disabled.insert("inactive-code".to_owned());
+        config.disabled.insert("E0599".to_owned());
         check_diagnostics_with_config(config, ra_fixture)
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
index d36813381e4..78a04e15424 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_orphan.rs
@@ -13,7 +13,7 @@ pub(crate) fn trait_impl_orphan(
         ctx,
         DiagnosticCode::RustcHardError("E0117"),
         "only traits defined in the current crate can be implemented for arbitrary types"
-            .to_string(),
+            .to_owned(),
         InFile::new(d.file_id, d.impl_.into()),
     )
     // Not yet checked for false positives
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
index f58fcd1f7e2..00710ef5076 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/trait_impl_redundant_assoc_item.rs
@@ -103,7 +103,7 @@ fn quickfix_for_redundant_assoc_item(
 
     Some(vec![Assist {
         id: AssistId("add assoc item def into trait def", AssistKind::QuickFix),
-        label: Label::new("Add assoc item def into trait def".to_string()),
+        label: Label::new("Add assoc item def into trait def".to_owned()),
         group: None,
         target: range,
         source_change: Some(source_change_builder.finish()),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 750189beecb..e93eea8ce29 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -120,7 +120,7 @@ fn add_missing_ok_or_some(
 
     let mut builder = TextEdit::builder();
     builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
-    builder.insert(expr.syntax().text_range().end(), ")".to_string());
+    builder.insert(expr.syntax().text_range().end(), ")".to_owned());
     let source_change =
         SourceChange::from_text_edit(expr_ptr.file_id.original_file(ctx.sema.db), builder.finish());
     let name = format!("Wrap in {variant_name}");
@@ -174,7 +174,7 @@ fn str_ref_to_owned(
     let expr = expr_ptr.value.to_node(&root);
     let expr_range = expr.syntax().text_range();
 
-    let to_owned = ".to_owned()".to_string();
+    let to_owned = ".to_owned()".to_owned();
 
     let edit = TextEdit::insert(expr.syntax().text_range().end(), to_owned);
     let source_change =
@@ -186,7 +186,9 @@ fn str_ref_to_owned(
 
 #[cfg(test)]
 mod tests {
-    use crate::tests::{check_diagnostics, check_fix, check_no_fix};
+    use crate::tests::{
+        check_diagnostics, check_diagnostics_with_disabled, check_fix, check_no_fix,
+    };
 
     #[test]
     fn missing_reference() {
@@ -718,7 +720,7 @@ struct Bar {
 
     #[test]
     fn return_no_value() {
-        check_diagnostics(
+        check_diagnostics_with_disabled(
             r#"
 fn f() -> i32 {
     return;
@@ -727,6 +729,7 @@ fn f() -> i32 {
 }
 fn g() { return; }
 "#,
+            std::iter::once("needless_return".to_owned()),
         );
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
index 996b6eda59c..06f176f86f4 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unimplemented_builtin_macro.rs
@@ -10,7 +10,7 @@ pub(crate) fn unimplemented_builtin_macro(
     Diagnostic::new_with_syntax_node_ptr(
         ctx,
         DiagnosticCode::Ra("unimplemented-builtin-macro", Severity::WeakWarning),
-        "unimplemented built-in macro".to_string(),
+        "unimplemented built-in macro".to_owned(),
         d.node,
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
index 0e7a5720d4d..65abfd8a294 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_field.rs
@@ -65,7 +65,7 @@ fn method_fix(
     let FileRange { range, file_id } = ctx.sema.original_range_opt(expr.syntax())?;
     Some(vec![Assist {
         id: AssistId("expected-field-found-method-call-fix", AssistKind::QuickFix),
-        label: Label::new("Use parentheses to call the method".to_string()),
+        label: Label::new("Use parentheses to call the method".to_owned()),
         group: None,
         target: range,
         source_change: Some(SourceChange::from_text_edit(
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
index 9f8fee67f31..648d081898c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_method.rs
@@ -101,7 +101,7 @@ fn field_fix(
     };
     Some(Assist {
         id: AssistId("expected-method-found-field-fix", AssistKind::QuickFix),
-        label: Label::new("Use parentheses to call the value of the field".to_string()),
+        label: Label::new("Use parentheses to call the value of the field".to_owned()),
         group: None,
         target: range,
         source_change: Some(SourceChange::from_iter([
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
index 1604decf907..11556883249 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_module.rs
@@ -16,7 +16,7 @@ pub(crate) fn unresolved_module(
         ctx,
         DiagnosticCode::RustcHardError("E0583"),
         match &*d.candidates {
-            [] => "unresolved module".to_string(),
+            [] => "unresolved module".to_owned(),
             [candidate] => format!("unresolved module, can't find module file: {candidate}"),
             [candidates @ .., last] => {
                 format!(
@@ -46,7 +46,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::UnresolvedModule) -> Option<Vec<
                             anchor: d.decl.file_id.original_file(ctx.sema.db),
                             path: candidate.clone(),
                         },
-                        initial_contents: "".to_string(),
+                        initial_contents: "".to_owned(),
                     }
                     .into(),
                     unresolved_module.syntax().text_range(),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
index 015a3d6b2ce..7ea50c496fb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
@@ -27,12 +27,12 @@ pub(crate) fn unresolved_proc_macro(
 
     let not_expanded_message = match &d.macro_name {
         Some(name) => format!("proc macro `{name}` not expanded"),
-        None => "proc macro not expanded".to_string(),
+        None => "proc macro not expanded".to_owned(),
     };
     let severity = if config_enabled { Severity::Error } else { Severity::WeakWarning };
     let def_map = ctx.sema.db.crate_def_map(d.krate);
     let message = if config_enabled {
-        def_map.proc_macro_loading_error().unwrap_or("proc macro not found in the built dylib")
+        def_map.proc_macro_loading_error().unwrap_or("internal error")
     } else {
         match d.kind {
             hir::MacroKind::Attr if proc_macros_enabled => "attribute macro expansion is disabled",
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 8dce2af23e3..863a7ab783e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -40,7 +40,7 @@ pub(crate) fn useless_braces(
         acc.push(
             Diagnostic::new(
                 DiagnosticCode::RustcLint("unused_braces"),
-                "Unnecessary braces in use statement".to_string(),
+                "Unnecessary braces in use statement".to_owned(),
                 FileRange { file_id, range: use_range },
             )
             .with_main_node(InFile::new(file_id.into(), node.clone()))
@@ -112,7 +112,7 @@ mod a {
         );
 
         let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("syntax-error".to_string());
+        config.disabled.insert("syntax-error".to_owned());
         check_diagnostics_with_config(
             config,
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 5ad7069e317..9d21bb4cd9f 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -43,6 +43,8 @@ mod handlers {
     pub(crate) mod no_such_field;
     pub(crate) mod private_assoc_item;
     pub(crate) mod private_field;
+    pub(crate) mod remove_trailing_return;
+    pub(crate) mod remove_unnecessary_else;
     pub(crate) mod replace_filter_map_next_with_find_map;
     pub(crate) mod trait_impl_incorrect_safety;
     pub(crate) mod trait_impl_missing_assoc_item;
@@ -73,8 +75,6 @@ mod handlers {
 #[cfg(test)]
 mod tests;
 
-use std::collections::HashMap;
-
 use hir::{diagnostics::AnyDiagnostic, InFile, Semantics};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
@@ -384,6 +384,8 @@ pub fn diagnostics(
             AnyDiagnostic::UnusedVariable(d) => handlers::unused_variables::unused_variables(&ctx, &d),
             AnyDiagnostic::BreakOutsideOfLoop(d) => handlers::break_outside_of_loop::break_outside_of_loop(&ctx, &d),
             AnyDiagnostic::MismatchedTupleStructPatArgCount(d) => handlers::mismatched_arg_count::mismatched_tuple_struct_pat_arg_count(&ctx, &d),
+            AnyDiagnostic::RemoveTrailingReturn(d) => handlers::remove_trailing_return::remove_trailing_return(&ctx, &d),
+            AnyDiagnostic::RemoveUnnecessaryElse(d) => handlers::remove_unnecessary_else::remove_unnecessary_else(&ctx, &d),
         };
         res.push(d)
     }
@@ -413,18 +415,18 @@ pub fn diagnostics(
 
 // `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
 
-static RUSTC_LINT_GROUPS_DICT: Lazy<HashMap<&str, Vec<&str>>> =
+static RUSTC_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> =
     Lazy::new(|| build_group_dict(DEFAULT_LINT_GROUPS, &["warnings", "__RA_EVERY_LINT"], ""));
 
-static CLIPPY_LINT_GROUPS_DICT: Lazy<HashMap<&str, Vec<&str>>> =
+static CLIPPY_LINT_GROUPS_DICT: Lazy<FxHashMap<&str, Vec<&str>>> =
     Lazy::new(|| build_group_dict(CLIPPY_LINT_GROUPS, &["__RA_EVERY_LINT"], "clippy::"));
 
 fn build_group_dict(
     lint_group: &'static [LintGroup],
     all_groups: &'static [&'static str],
     prefix: &'static str,
-) -> HashMap<&'static str, Vec<&'static str>> {
-    let mut r: HashMap<&str, Vec<&str>> = HashMap::new();
+) -> FxHashMap<&'static str, Vec<&'static str>> {
+    let mut r: FxHashMap<&str, Vec<&str>> = FxHashMap::default();
     for g in lint_group {
         for child in g.children {
             r.entry(child.strip_prefix(prefix).unwrap())
@@ -561,7 +563,7 @@ fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
     assert!(!id.contains(' '));
     Assist {
         id: AssistId(id, AssistKind::QuickFix),
-        label: Label::new(label.to_string()),
+        label: Label::new(label.to_owned()),
         group: None,
         target,
         source_change: None,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
index f394a491b51..b62bb5affdd 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/tests.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::print_stderr)]
 #[cfg(not(feature = "in-rust-tree"))]
 mod sourcegen;
 
@@ -33,13 +34,35 @@ pub(crate) fn check_fixes(ra_fixture_before: &str, ra_fixtures_after: Vec<&str>)
 
 #[track_caller]
 fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
+    let mut config = DiagnosticsConfig::test_sample();
+    config.expr_fill_default = ExprFillDefaultMode::Default;
+    check_nth_fix_with_config(config, nth, ra_fixture_before, ra_fixture_after)
+}
+
+#[track_caller]
+pub(crate) fn check_fix_with_disabled(
+    ra_fixture_before: &str,
+    ra_fixture_after: &str,
+    disabled: impl Iterator<Item = String>,
+) {
+    let mut config = DiagnosticsConfig::test_sample();
+    config.expr_fill_default = ExprFillDefaultMode::Default;
+    config.disabled.extend(disabled);
+    check_nth_fix_with_config(config, 0, ra_fixture_before, ra_fixture_after)
+}
+
+#[track_caller]
+fn check_nth_fix_with_config(
+    config: DiagnosticsConfig,
+    nth: usize,
+    ra_fixture_before: &str,
+    ra_fixture_after: &str,
+) {
     let after = trim_indent(ra_fixture_after);
 
     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
-    let mut conf = DiagnosticsConfig::test_sample();
-    conf.expr_fill_default = ExprFillDefaultMode::Default;
     let diagnostic =
-        super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
+        super::diagnostics(&db, &config, &AssistResolveStrategy::All, file_position.file_id)
             .pop()
             .expect("no diagnostics");
     let fix = &diagnostic
@@ -85,7 +108,17 @@ pub(crate) fn check_no_fix(ra_fixture: &str) {
 #[track_caller]
 pub(crate) fn check_diagnostics(ra_fixture: &str) {
     let mut config = DiagnosticsConfig::test_sample();
-    config.disabled.insert("inactive-code".to_string());
+    config.disabled.insert("inactive-code".to_owned());
+    check_diagnostics_with_config(config, ra_fixture)
+}
+
+#[track_caller]
+pub(crate) fn check_diagnostics_with_disabled(
+    ra_fixture: &str,
+    disabled: impl Iterator<Item = String>,
+) {
+    let mut config = DiagnosticsConfig::test_sample();
+    config.disabled.extend(disabled);
     check_diagnostics_with_config(config, ra_fixture)
 }
 
@@ -174,7 +207,8 @@ fn minicore_smoke_test() {
         let source = minicore.source_code();
         let mut config = DiagnosticsConfig::test_sample();
         // This should be ignored since we conditionally remove code which creates single item use with braces
-        config.disabled.insert("unused_braces".to_string());
+        config.disabled.insert("unused_braces".to_owned());
+        config.disabled.insert("unused_variables".to_owned());
         check_diagnostics_with_config(config, &source);
     }
 
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
index 060897a6852..fb98e956847 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -456,7 +456,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                         SyntaxElement::Token(t) => Some(t.clone()),
                         SyntaxElement::Node(n) => n.first_token(),
                     })
-                    .map(|p| p.text().to_string());
+                    .map(|p| p.text().to_owned());
                 let first_matched_token = child.clone();
                 let mut last_matched_token = child;
                 // Read code tokens util we reach one equal to the next token from our pattern
@@ -706,7 +706,7 @@ where
 // we are trying to match that bit of code. This saves us having to pass a boolean into all the bits
 // of code that can make the decision to not match.
 thread_local! {
-    pub static RECORDING_MATCH_FAIL_REASONS: Cell<bool> = Cell::new(false);
+    pub static RECORDING_MATCH_FAIL_REASONS: Cell<bool> = const { Cell::new(false) };
 }
 
 fn recording_match_fail_reasons() -> bool {
@@ -795,7 +795,7 @@ mod tests {
         let edits = match_finder.edits();
         assert_eq!(edits.len(), 1);
         let edit = &edits[&position.file_id];
-        let mut after = input.to_string();
+        let mut after = input.to_owned();
         edit.apply(&mut after);
         assert_eq!(after, "fn foo() {} fn bar() {} fn main() { bar(1+2); }");
     }
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
index d78d009681a..2f91271c465 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/parsing.rs
@@ -152,7 +152,7 @@ impl FromStr for SsrRule {
             .next()
             .ok_or_else(|| SsrError("Cannot find delimiter `==>>`".into()))?
             .trim()
-            .to_string();
+            .to_owned();
         if it.next().is_some() {
             return Err(SsrError("More than one delimiter found".into()));
         }
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs
index 7c7d146cb4a..e608b0a7c42 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs
@@ -113,6 +113,7 @@ fn assert_ssr_transforms(rules: &[&str], input: &str, expected: Expect) {
     expected.assert_eq(&actual);
 }
 
+#[allow(clippy::print_stdout)]
 fn print_match_debug_info(match_finder: &MatchFinder<'_>, file_id: FileId, snippet: &str) {
     let debug_info = match_finder.debug_where_text_equal(file_id, snippet);
     println!(
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index f2219857191..dbe6a5507cc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -58,7 +58,7 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
         // and valid URLs so we choose to be too eager to try to resolve what might be
         // a URL.
         if target.contains("://") {
-            (Some(LinkType::Inline), target.to_string(), title.to_string())
+            (Some(LinkType::Inline), target.to_owned(), title.to_owned())
         } else {
             // Two possibilities:
             // * path-based links: `../../module/struct.MyStruct.html`
@@ -66,9 +66,9 @@ pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: Defin
             if let Some((target, title)) = rewrite_intra_doc_link(db, definition, target, title) {
                 (None, target, title)
             } else if let Some(target) = rewrite_url_link(db, definition, target) {
-                (Some(LinkType::Inline), target, title.to_string())
+                (Some(LinkType::Inline), target, title.to_owned())
             } else {
-                (None, target.to_string(), title.to_string())
+                (None, target.to_owned(), title.to_owned())
             }
         }
     });
@@ -186,7 +186,7 @@ pub(crate) fn extract_definitions_from_docs(
             let (link, ns) = parse_intra_doc_link(&target);
             Some((
                 TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?),
-                link.to_string(),
+                link.to_owned(),
                 ns,
             ))
         }
@@ -388,7 +388,7 @@ fn rewrite_intra_doc_link(
     url = url.join(&file).ok()?;
     url.set_fragment(anchor);
 
-    Some((url.into(), strip_prefixes_suffixes(title).to_string()))
+    Some((url.into(), strip_prefixes_suffixes(title).to_owned()))
 }
 
 /// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
@@ -668,7 +668,7 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) ->
     Some(match assoc_item {
         AssocItem::Function(function) => {
             let is_trait_method =
-                function.as_assoc_item(db).and_then(|assoc| assoc.containing_trait(db)).is_some();
+                function.as_assoc_item(db).and_then(|assoc| assoc.container_trait(db)).is_some();
             // This distinction may get more complicated when specialization is available.
             // Rustdoc makes this decision based on whether a method 'has defaultness'.
             // Currently this is only the case for provided trait methods.
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
index 3bb0fc60641..60e8d29a716 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links/tests.rs
@@ -29,9 +29,6 @@ fn check_external_docs(
     let web_url = links.web_url;
     let local_url = links.local_url;
 
-    println!("web_url: {:?}", web_url);
-    println!("local_url: {:?}", local_url);
-
     match (expect_web_url, web_url) {
         (Some(expect), Some(url)) => expect.assert_eq(&url),
         (None, None) => (),
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 b278924721c..0e790e14205 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -193,7 +193,7 @@ fn structure_token(token: SyntaxToken) -> Option<StructureNode> {
         if let Some(region_name) = text.strip_prefix("// region:").map(str::trim) {
             return Some(StructureNode {
                 parent: None,
-                label: region_name.to_string(),
+                label: region_name.to_owned(),
                 navigation_range: comment.syntax().text_range(),
                 node_range: comment.syntax().text_range(),
                 kind: StructureNodeKind::Region,
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
index fae10074354..fab62e95d19 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_declaration.rs
@@ -61,7 +61,7 @@ pub(crate) fn goto_declaration(
                 _ => None,
             }?;
 
-            let trait_ = assoc.containing_trait_impl(db)?;
+            let trait_ = assoc.implemented_trait(db)?;
             let name = Some(assoc.name(db)?);
             let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
             item.try_to_nav(db)
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index 4fed1f9158c..88255d222ed 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -182,11 +182,7 @@ fn try_filter_trait_item_definition(
     match assoc {
         AssocItem::Function(..) => None,
         AssocItem::Const(..) | AssocItem::TypeAlias(..) => {
-            let imp = match assoc.container(db) {
-                hir::AssocItemContainer::Impl(imp) => imp,
-                _ => return None,
-            };
-            let trait_ = imp.trait_(db)?;
+            let trait_ = assoc.implemented_trait(db)?;
             let name = def.name(db)?;
             let discri_value = discriminant(&assoc);
             trait_
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index c1a4a7b1fc7..8a12cbacccc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -60,13 +60,13 @@ pub(crate) fn goto_implementation(
                     Definition::Function(f) => {
                         let assoc = f.as_assoc_item(sema.db)?;
                         let name = assoc.name(sema.db)?;
-                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        let trait_ = assoc.container_or_implemented_trait(sema.db)?;
                         impls_for_trait_item(&sema, trait_, name)
                     }
                     Definition::Const(c) => {
                         let assoc = c.as_assoc_item(sema.db)?;
                         let name = assoc.name(sema.db)?;
-                        let trait_ = assoc.containing_trait_or_trait_impl(sema.db)?;
+                        let trait_ = assoc.container_or_implemented_trait(sema.db)?;
                         impls_for_trait_item(&sema, trait_, name)
                     }
                     _ => return None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 979ca4575d0..dd285e9b327 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -521,7 +521,7 @@ mod tests {
                             ReferenceCategory::Import => "import",
                             ReferenceCategory::Test => "test",
                         }
-                        .to_string()
+                        .to_owned()
                     }),
                 )
             })
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 45386df2b26..eff055c9599 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -621,7 +621,7 @@ fn closure_ty(
         })
         .join("\n");
     if captures_rendered.trim().is_empty() {
-        captures_rendered = "This closure captures nothing".to_string();
+        captures_rendered = "This closure captures nothing".to_owned();
     }
     let mut targets: Vec<hir::ModuleDef> = Vec::new();
     let mut push_new_def = |item: hir::ModuleDef| {
@@ -823,7 +823,7 @@ fn keyword_hints(
                     }
                 }
                 _ => KeywordHint {
-                    description: token.text().to_string(),
+                    description: token.text().to_owned(),
                     keyword_mod,
                     actions: Vec::new(),
                 },
@@ -835,9 +835,9 @@ fn keyword_hints(
                 Some(_) => format!("prim_{}", token.text()),
                 None => format!("{}_keyword", token.text()),
             };
-            KeywordHint::new(token.text().to_string(), module)
+            KeywordHint::new(token.text().to_owned(), module)
         }
-        T![Self] => KeywordHint::new(token.text().to_string(), "self_upper_keyword".into()),
-        _ => KeywordHint::new(token.text().to_string(), format!("{}_keyword", token.text())),
+        T![Self] => KeywordHint::new(token.text().to_owned(), "self_upper_keyword".into()),
+        _ => KeywordHint::new(token.text().to_owned(), format!("{}_keyword", token.text())),
     }
 }
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 9f4427090e9..30bfe6ee9dc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -406,8 +406,8 @@ fn main() {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 631..866,
-                                focus_range: 692..698,
+                                full_range: 632..867,
+                                focus_range: 693..699,
                                 name: "FnOnce",
                                 kind: Trait,
                                 container_name: "function",
@@ -702,7 +702,7 @@ fn hover_shows_struct_field_info() {
     // Hovering over the field when instantiating
     check(
         r#"
-struct Foo { field_a: u32 }
+struct Foo { pub field_a: u32 }
 
 fn main() {
     let foo = Foo { field_a$0: 0, };
@@ -717,7 +717,7 @@ fn main() {
 
             ```rust
              // size = 4, align = 4, offset = 0
-            field_a: u32
+            pub field_a: u32
             ```
         "#]],
     );
@@ -725,7 +725,7 @@ fn main() {
     // Hovering over the field in the definition
     check(
         r#"
-struct Foo { field_a$0: u32 }
+struct Foo { pub field_a$0: u32 }
 
 fn main() {
     let foo = Foo { field_a: 0 };
@@ -740,7 +740,74 @@ fn main() {
 
             ```rust
              // size = 4, align = 4, offset = 0
-            field_a: u32
+            pub field_a: u32
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_shows_tuple_struct_field_info() {
+    check(
+        r#"
+struct Foo(pub u32)
+
+fn main() {
+    let foo = Foo { 0$0: 0, };
+}
+"#,
+        expect![[r#"
+            *0*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+             // size = 4, align = 4, offset = 0
+            pub 0: u32
+            ```
+        "#]],
+    );
+    check(
+        r#"
+struct Foo(pub u32)
+
+fn foo(foo: Foo) {
+    foo.0$0;
+}
+"#,
+        expect![[r#"
+            *0*
+
+            ```rust
+            test::Foo
+            ```
+
+            ```rust
+             // size = 4, align = 4, offset = 0
+            pub 0: u32
+            ```
+        "#]],
+    );
+}
+
+#[test]
+fn hover_tuple_struct() {
+    check(
+        r#"
+struct Foo$0(pub u32)
+"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+             // size = 4, align = 4
+            struct Foo(pub u32);
             ```
         "#]],
     );
@@ -7196,8 +7263,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6156..6364,
-                                focus_range: 6221..6227,
+                                full_range: 6157..6365,
+                                focus_range: 6222..6228,
                                 name: "Future",
                                 kind: Trait,
                                 container_name: "future",
@@ -7210,8 +7277,8 @@ impl Iterator for S {
                                 file_id: FileId(
                                     1,
                                 ),
-                                full_range: 6994..7460,
-                                focus_range: 7038..7046,
+                                full_range: 6995..7461,
+                                focus_range: 7039..7047,
                                 name: "Iterator",
                                 kind: Trait,
                                 container_name: "iterator",
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
index 3104b85768f..8d9ad5bda14 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs
@@ -1,10 +1,8 @@
 //! Implementation of "implicit drop" inlay hints:
-//! ```no_run
-//! fn main() {
-//!     let x = vec![2];
-//!     if some_condition() {
-//!         /* drop(x) */return;
-//!     }
+//! ```ignore
+//! let x = vec![2];
+//! if some_condition() {
+//!     /* drop(x) */return;
 //! }
 //! ```
 use hir::{
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
index 50ab15c504f..c4b0c199fc2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/range_exclusive.rs
@@ -1,5 +1,5 @@
 //! Implementation of "range exclusive" inlay hints:
-//! ```no_run
+//! ```ignore
 //! for i in 0../* < */10 {}
 //! if let ../* < */100 = 50 {}
 //! ```
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
index adbd1918884..df444a3f4d0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret_function.rs
@@ -15,8 +15,8 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
 // |===
 pub(crate) fn interpret_function(db: &RootDatabase, position: FilePosition) -> String {
     let start_time = Instant::now();
-    let mut result = find_and_interpret(db, position)
-        .unwrap_or_else(|| "Not inside a function body".to_string());
+    let mut result =
+        find_and_interpret(db, position).unwrap_or_else(|| "Not inside a function body".to_owned());
     let duration = Instant::now() - start_time;
     writeln!(result).unwrap();
     writeln!(result, "----------------------").unwrap();
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index 1cfde236245..fef0ec35ba0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -115,7 +115,7 @@ fn remove_newline(
 
         let range = TextRange::at(offset, ((n_spaces_after_line_break + 1) as u32).into());
         let replace_with = if no_space { "" } else { " " };
-        edit.replace(range, replace_with.to_string());
+        edit.replace(range, replace_with.to_owned());
         return;
     }
 
@@ -140,7 +140,7 @@ fn remove_newline(
                 };
                 edit.replace(
                     TextRange::new(prev.text_range().start(), token.text_range().end()),
-                    space.to_string(),
+                    space.to_owned(),
                 );
                 return;
             }
@@ -154,7 +154,7 @@ fn remove_newline(
                 Some(_) => cov_mark::hit!(join_two_ifs_with_existing_else),
                 None => {
                     cov_mark::hit!(join_two_ifs);
-                    edit.replace(token.text_range(), " else ".to_string());
+                    edit.replace(token.text_range(), " else ".to_owned());
                     return;
                 }
             }
@@ -203,7 +203,7 @@ fn remove_newline(
     }
 
     // Remove newline but add a computed amount of whitespace characters
-    edit.replace(token.text_range(), compute_ws(prev.kind(), next.kind()).to_string());
+    edit.replace(token.text_range(), compute_ws(prev.kind(), next.kind()).to_owned());
 }
 
 fn join_single_expr_block(edit: &mut TextEditBuilder, token: &SyntaxToken) -> Option<()> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index e9f42d47855..effdbf2c1f0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -238,7 +238,7 @@ impl Analysis {
         let mut host = AnalysisHost::default();
         let file_id = FileId::from_raw(0);
         let mut file_set = FileSet::default();
-        file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_string()));
+        file_set.insert(file_id, VfsPath::new_virtual_path("/main.rs".to_owned()));
         let source_root = SourceRoot::new_local(file_set);
 
         let mut change = Change::new();
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index c49d75b2f81..80d265ae373 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -383,18 +383,18 @@ pub(crate) fn def_to_moniker(
             let (name, repo, version) = match krate.origin(db) {
                 CrateOrigin::Library { repo, name } => (name, repo, krate.version(db)),
                 CrateOrigin::Local { repo, name } => (
-                    name.unwrap_or(krate.display_name(db)?.canonical_name().to_string()),
+                    name.unwrap_or(krate.display_name(db)?.canonical_name().to_owned()),
                     repo,
                     krate.version(db),
                 ),
                 CrateOrigin::Rustc { name } => (
                     name.clone(),
-                    Some("https://github.com/rust-lang/rust/".to_string()),
+                    Some("https://github.com/rust-lang/rust/".to_owned()),
                     Some(format!("https://github.com/rust-lang/rust/compiler/{name}",)),
                 ),
                 CrateOrigin::Lang(lang) => (
-                    krate.display_name(db)?.canonical_name().to_string(),
-                    Some("https://github.com/rust-lang/rust/".to_string()),
+                    krate.display_name(db)?.canonical_name().to_owned(),
+                    Some("https://github.com/rust-lang/rust/".to_owned()),
                     Some(match lang {
                         LangCrateOrigin::Other => {
                             "https://github.com/rust-lang/rust/library/".into()
diff --git a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
index bfd91feeb39..674ce6d52bf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/navigation_target.rs
@@ -860,7 +860,7 @@ fn foo() { enum FooInner { } }
 "#,
         );
 
-        let navs = analysis.symbol_search(Query::new("FooInner".to_string()), !0).unwrap();
+        let navs = analysis.symbol_search(Query::new("FooInner".to_owned()), !0).unwrap();
         expect![[r#"
             [
                 NavigationTarget {
@@ -898,7 +898,7 @@ struct Foo;
 "#,
         );
 
-        let navs = analysis.symbol_search(Query::new("foo".to_string()), !0).unwrap();
+        let navs = analysis.symbol_search(Query::new("foo".to_owned()), !0).unwrap();
         assert_eq!(navs.len(), 2)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs
index a95d1771ce0..5c14f496a0b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/prime_caches.rs
@@ -105,7 +105,7 @@ pub(crate) fn parallel_prime_caches(
             work_sender
                 .send((
                     crate_id,
-                    graph[crate_id].display_name.as_deref().unwrap_or_default().to_string(),
+                    graph[crate_id].display_name.as_deref().unwrap_or_default().to_owned(),
                 ))
                 .ok();
         }
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index bdda25a111f..dcdc6118a34 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -9,8 +9,6 @@
 //! at the index that the match starts at and its tree parent is
 //! resolved to the search element definition, we get a reference.
 
-use std::collections::HashMap;
-
 use hir::{DescendPreference, PathResolution, Semantics};
 use ide_db::{
     base_db::FileId,
@@ -79,7 +77,7 @@ pub(crate) fn find_all_refs(
                             .collect(),
                     )
                 })
-                .collect::<HashMap<_, Vec<_>, _>>();
+                .collect::<IntMap<_, Vec<_>>>();
             let declaration = match def {
                 Definition::Module(module) => {
                     Some(NavigationTarget::from_module_to_decl(sema.db, module))
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 3008722cdbb..ae107a96040 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -72,7 +72,7 @@ impl Runnable {
             RunnableKind::Bench { test_id } => format!("bench {test_id}"),
             RunnableKind::DocTest { test_id, .. } => format!("doctest {test_id}"),
             RunnableKind::Bin => {
-                target.map_or_else(|| "run binary".to_string(), |t| format!("run {t}"))
+                target.map_or_else(|| "run binary".to_owned(), |t| format!("run {t}"))
             }
         }
     }
@@ -442,8 +442,7 @@ fn module_def_doctest(db: &RootDatabase, def: Definition) -> Option<Runnable> {
             .for_each(|name| format_to!(path, "{}::", name.display(db)));
         // This probably belongs to canonical_path?
         if let Some(assoc_item) = def.as_assoc_item(db) {
-            if let hir::AssocItemContainer::Impl(imp) = assoc_item.container(db) {
-                let ty = imp.self_ty(db);
+            if let Some(ty) = assoc_item.implementing_ty(db) {
                 if let Some(adt) = ty.as_adt() {
                     let name = adt.name(db);
                     let mut ty_args = ty.generic_parameters(db).peekable();
diff --git a/src/tools/rust-analyzer/crates/ide/src/ssr.rs b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
index f0d18fdefa7..b49fe391bf2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/ssr.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/ssr.rs
@@ -41,7 +41,7 @@ pub(crate) fn ssr_assists(
     for (label, source_change) in assists.into_iter() {
         let assist = Assist {
             id,
-            label: Label::new(label.to_string()),
+            label: Label::new(label.to_owned()),
             group: Some(GroupLabel("Apply SSR".into())),
             target: comment_range,
             source_change,
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 5b7094e6bcc..dee5afbf8d9 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -1,14 +1,12 @@
 //! This module provides `StaticIndex` which is used for powering
 //! read-only code browsers and emitting LSIF
 
-use std::collections::HashMap;
-
 use hir::{db::HirDatabase, Crate, HirFileIdExt, Module};
-use ide_db::helpers::get_definition;
 use ide_db::{
     base_db::{FileId, FileRange, SourceDatabaseExt},
     defs::Definition,
-    FxHashSet, RootDatabase,
+    helpers::get_definition,
+    FxHashMap, FxHashSet, RootDatabase,
 };
 use syntax::{AstNode, SyntaxKind::*, TextRange, T};
 
@@ -31,7 +29,7 @@ pub struct StaticIndex<'a> {
     pub tokens: TokenStore,
     analysis: &'a Analysis,
     db: &'a RootDatabase,
-    def_map: HashMap<Definition, TokenId>,
+    def_map: FxHashMap<Definition, TokenId>,
 }
 
 #[derive(Debug)]
@@ -232,14 +230,13 @@ impl StaticIndex<'_> {
 #[cfg(test)]
 mod tests {
     use crate::{fixture, StaticIndex};
-    use ide_db::base_db::FileRange;
-    use std::collections::HashSet;
+    use ide_db::{base_db::FileRange, FxHashSet};
     use syntax::TextSize;
 
     fn check_all_ranges(ra_fixture: &str) {
         let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
         let s = StaticIndex::compute(&analysis);
-        let mut range_set: HashSet<_> = ranges.iter().map(|it| it.0).collect();
+        let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect();
         for f in s.files {
             for (range, _) in f.tokens {
                 let it = FileRange { file_id: f.file_id, range };
@@ -258,7 +255,7 @@ mod tests {
     fn check_definitions(ra_fixture: &str) {
         let (analysis, ranges) = fixture::annotations_without_marker(ra_fixture);
         let s = StaticIndex::compute(&analysis);
-        let mut range_set: HashSet<_> = ranges.iter().map(|it| it.0).collect();
+        let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect();
         for (_, t) in s.tokens.iter() {
             if let Some(t) = t.definition {
                 if t.range.start() == TextSize::from(0) {
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index b2b305c1d38..3321a0513b6 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -105,7 +105,7 @@ pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
         }
     }
 
-    buf.trim().to_string()
+    buf.trim().to_owned()
 }
 
 fn collect_query<'q, Q>(table: QueryTable<'q, Q>) -> <Q as QueryCollect>::Collector
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index d686652bb3e..e7c1b4497e2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -559,7 +559,7 @@ fn highlight_method_call(
     }
     if func
         .as_assoc_item(sema.db)
-        .and_then(|it| it.containing_trait_or_trait_impl(sema.db))
+        .and_then(|it| it.container_or_implemented_trait(sema.db))
         .is_some()
     {
         h |= HlMod::Trait;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
index 2108b53861c..1065d5899ab 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_tree.rs
@@ -55,7 +55,7 @@ fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<
 fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
     // Range of the full node
     let node_range = node.text_range();
-    let text = node.text().to_string();
+    let text = node.text().to_owned();
 
     // We start at some point inside the node
     // Either we have selected the whole string
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index b8856882ed7..e87fc89fea2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -149,10 +149,7 @@ fn on_opening_bracket_typed(
 
         let tree: ast::UseTree = find_node_at_offset(file.syntax(), offset)?;
 
-        Some(TextEdit::insert(
-            tree.syntax().text_range().end() + TextSize::of("{"),
-            "}".to_string(),
-        ))
+        Some(TextEdit::insert(tree.syntax().text_range().end() + TextSize::of("{"), "}".to_owned()))
     }
 
     fn bracket_expr(
@@ -235,7 +232,7 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
             return None;
         }
         let offset = expr.syntax().text_range().end();
-        Some(TextEdit::insert(offset, ";".to_string()))
+        Some(TextEdit::insert(offset, ";".to_owned()))
     }
 
     /// `a =$0 b;` removes the semicolon if an expression is valid in this context.
@@ -275,7 +272,7 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
             return None;
         }
         let offset = let_stmt.syntax().text_range().end();
-        Some(TextEdit::insert(offset, ";".to_string()))
+        Some(TextEdit::insert(offset, ";".to_owned()))
     }
 }
 
@@ -353,7 +350,7 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option<ExtendedTe
     if let Some(t) = file.syntax().token_at_offset(offset).left_biased() {
         if T![impl] == t.kind() {
             return Some(ExtendedTextEdit {
-                edit: TextEdit::replace(range, "<$0>".to_string()),
+                edit: TextEdit::replace(range, "<$0>".to_owned()),
                 is_snippet: true,
             });
         }
@@ -363,7 +360,7 @@ fn on_left_angle_typed(file: &SourceFile, offset: TextSize) -> Option<ExtendedTe
         ast::GenericParamList::can_cast(n.kind()) || ast::GenericArgList::can_cast(n.kind())
     }) {
         Some(ExtendedTextEdit {
-            edit: TextEdit::replace(range, "<$0>".to_string()),
+            edit: TextEdit::replace(range, "<$0>".to_owned()),
             is_snippet: true,
         })
     } else {
@@ -383,7 +380,7 @@ fn on_right_angle_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit>
     }
     find_node_at_offset::<ast::RetType>(file.syntax(), offset)?;
 
-    Some(TextEdit::insert(after_arrow, " ".to_string()))
+    Some(TextEdit::insert(after_arrow, " ".to_owned()))
 }
 
 #[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
index 9abe54cd390..51cf45bd22b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
@@ -12,7 +12,7 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode};
 // |===
 // image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
 pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
-    body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
+    body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
 }
 
 fn body_hir(db: &RootDatabase, position: FilePosition) -> Option<String> {
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
index 08d810c1346..5fb47039890 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
@@ -11,7 +11,7 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode};
 // | VS Code | **rust-analyzer: View Mir**
 // |===
 pub(crate) fn view_mir(db: &RootDatabase, position: FilePosition) -> String {
-    body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
+    body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
 }
 
 fn body_mir(db: &RootDatabase, position: FilePosition) -> Option<String> {
diff --git a/src/tools/rust-analyzer/crates/limit/src/lib.rs b/src/tools/rust-analyzer/crates/limit/src/lib.rs
index 7f4b00df0ba..27471db6a34 100644
--- a/src/tools/rust-analyzer/crates/limit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/limit/src/lib.rs
@@ -55,13 +55,12 @@ impl Limit {
                 if other <= old_max || old_max == 0 {
                     break;
                 }
-                if self
-                    .max
-                    .compare_exchange_weak(old_max, other, Ordering::Relaxed, Ordering::Relaxed)
-                    .is_ok()
-                {
-                    eprintln!("new max: {other}");
-                }
+                _ = self.max.compare_exchange_weak(
+                    old_max,
+                    other,
+                    Ordering::Relaxed,
+                    Ordering::Relaxed,
+                );
             }
 
             Ok(())
diff --git a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
index 3878e20a2a6..c6dc071c394 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -279,7 +279,7 @@ pub fn load_proc_macro(
         let dylib = MacroDylib::new(path.to_path_buf());
         let vec = server.load_dylib(dylib).map_err(|e| format!("{e}"))?;
         if vec.is_empty() {
-            return Err("proc macro library returned no proc macros".to_string());
+            return Err("proc macro library returned no proc macros".to_owned());
         }
         Ok(vec
             .into_iter()
@@ -382,7 +382,7 @@ impl ProcMacroExpander for Expander {
         call_site: Span,
         mixed_site: Span,
     ) -> Result<tt::Subtree<Span>, ProcMacroExpansionError> {
-        let env = env.iter().map(|(k, v)| (k.to_string(), v.to_string())).collect();
+        let env = env.iter().map(|(k, v)| (k.to_owned(), v.to_owned())).collect();
         match self.0.expand(subtree, attrs, env, def_site, call_site, mixed_site) {
             Ok(Ok(subtree)) => Ok(subtree),
             Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err.0)),
diff --git a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
index 6c3917b37f1..d946ecc1caf 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/benchmark.rs
@@ -100,17 +100,19 @@ fn invocation_fixtures(
                 // So we just skip any error cases and try again
                 let mut try_cnt = 0;
                 loop {
-                    let mut subtree = tt::Subtree {
+                    let mut token_trees = Vec::new();
+                    for op in rule.lhs.iter() {
+                        collect_from_op(op, &mut token_trees, &mut seed);
+                    }
+
+                    let subtree = tt::Subtree {
                         delimiter: tt::Delimiter {
                             open: DUMMY,
                             close: DUMMY,
                             kind: tt::DelimiterKind::Invisible,
                         },
-                        token_trees: vec![],
+                        token_trees: token_trees.into_boxed_slice(),
                     };
-                    for op in rule.lhs.iter() {
-                        collect_from_op(op, &mut subtree, &mut seed);
-                    }
                     if it.expand(&subtree, |_| (), true, DUMMY).err.is_none() {
                         res.push((name.clone(), subtree));
                         break;
@@ -127,45 +129,45 @@ fn invocation_fixtures(
 
     fn collect_from_op(
         op: &Op<DummyTestSpanData>,
-        parent: &mut tt::Subtree<DummyTestSpanData>,
+        token_trees: &mut Vec<tt::TokenTree<DummyTestSpanData>>,
         seed: &mut usize,
     ) {
         return match op {
             Op::Var { kind, .. } => match kind.as_ref() {
-                Some(MetaVarKind::Ident) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Ty) => parent.token_trees.push(make_ident("Foo")),
-                Some(MetaVarKind::Tt) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Vis) => parent.token_trees.push(make_ident("pub")),
-                Some(MetaVarKind::Pat) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Path) => parent.token_trees.push(make_ident("foo")),
-                Some(MetaVarKind::Literal) => parent.token_trees.push(make_literal("1")),
-                Some(MetaVarKind::Expr) => parent.token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Ident) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Ty) => token_trees.push(make_ident("Foo")),
+                Some(MetaVarKind::Tt) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Vis) => token_trees.push(make_ident("pub")),
+                Some(MetaVarKind::Pat) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Path) => token_trees.push(make_ident("foo")),
+                Some(MetaVarKind::Literal) => token_trees.push(make_literal("1")),
+                Some(MetaVarKind::Expr) => token_trees.push(make_ident("foo")),
                 Some(MetaVarKind::Lifetime) => {
-                    parent.token_trees.push(make_punct('\''));
-                    parent.token_trees.push(make_ident("a"));
+                    token_trees.push(make_punct('\''));
+                    token_trees.push(make_ident("a"));
                 }
                 Some(MetaVarKind::Block) => {
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
+                    token_trees.push(make_subtree(tt::DelimiterKind::Brace, None))
                 }
                 Some(MetaVarKind::Item) => {
-                    parent.token_trees.push(make_ident("fn"));
-                    parent.token_trees.push(make_ident("foo"));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
+                    token_trees.push(make_ident("fn"));
+                    token_trees.push(make_ident("foo"));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Brace, None));
                 }
                 Some(MetaVarKind::Meta) => {
-                    parent.token_trees.push(make_ident("foo"));
-                    parent.token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
+                    token_trees.push(make_ident("foo"));
+                    token_trees.push(make_subtree(tt::DelimiterKind::Parenthesis, None));
                 }
 
                 None => (),
                 Some(kind) => panic!("Unhandled kind {kind:?}"),
             },
-            Op::Literal(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
-            Op::Ident(it) => parent.token_trees.push(tt::Leaf::from(it.clone()).into()),
+            Op::Literal(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
+            Op::Ident(it) => token_trees.push(tt::Leaf::from(it.clone()).into()),
             Op::Punct(puncts) => {
                 for punct in puncts {
-                    parent.token_trees.push(tt::Leaf::from(*punct).into());
+                    token_trees.push(tt::Leaf::from(*punct).into());
                 }
             }
             Op::Repeat { tokens, kind, separator } => {
@@ -177,20 +179,20 @@ fn invocation_fixtures(
                 };
                 for i in 0..cnt {
                     for it in tokens.iter() {
-                        collect_from_op(it, parent, seed);
+                        collect_from_op(it, token_trees, seed);
                     }
                     if i + 1 != cnt {
                         if let Some(sep) = separator {
                             match sep {
                                 Separator::Literal(it) => {
-                                    parent.token_trees.push(tt::Leaf::Literal(it.clone()).into())
+                                    token_trees.push(tt::Leaf::Literal(it.clone()).into())
                                 }
                                 Separator::Ident(it) => {
-                                    parent.token_trees.push(tt::Leaf::Ident(it.clone()).into())
+                                    token_trees.push(tt::Leaf::Ident(it.clone()).into())
                                 }
                                 Separator::Puncts(puncts) => {
                                     for it in puncts {
-                                        parent.token_trees.push(tt::Leaf::Punct(*it).into())
+                                        token_trees.push(tt::Leaf::Punct(*it).into())
                                     }
                                 }
                             };
@@ -199,11 +201,15 @@ fn invocation_fixtures(
                 }
             }
             Op::Subtree { tokens, delimiter } => {
-                let mut subtree = tt::Subtree { delimiter: *delimiter, token_trees: Vec::new() };
+                let mut subtree = Vec::new();
                 tokens.iter().for_each(|it| {
                     collect_from_op(it, &mut subtree, seed);
                 });
-                parent.token_trees.push(subtree.into());
+
+                let subtree =
+                    tt::Subtree { delimiter: *delimiter, token_trees: subtree.into_boxed_slice() };
+
+                token_trees.push(subtree.into());
             }
             Op::Ignore { .. } | Op::Index { .. } | Op::Count { .. } | Op::Length { .. } => {}
         };
@@ -230,7 +236,7 @@ fn invocation_fixtures(
         ) -> tt::TokenTree<DummyTestSpanData> {
             tt::Subtree {
                 delimiter: tt::Delimiter { open: DUMMY, close: DUMMY, kind },
-                token_trees: token_trees.unwrap_or_default(),
+                token_trees: token_trees.map(Vec::into_boxed_slice).unwrap_or_default(),
             }
             .into()
         }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander.rs b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
index 60483809dc1..9366048fd95 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander.rs
@@ -58,7 +58,7 @@ pub(crate) fn expand_rules<S: Span>(
         ExpandResult::new(
             tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(call_site),
-                token_trees: vec![],
+                token_trees: Box::new([]),
             },
             ExpandError::NoMatchingRule,
         )
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
index 40b4c7cdd65..eea92cfba4c 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs
@@ -798,7 +798,7 @@ fn match_meta_var<S: Span>(
                 tt.map(|tt| match tt {
                     tt::TokenTree::Leaf(leaf) => tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(*leaf.span()),
-                        token_trees: vec![leaf.into()],
+                        token_trees: Box::new([leaf.into()]),
                     },
                     tt::TokenTree::Subtree(mut s) => {
                         if s.delimiter.kind == tt::DelimiterKind::Invisible {
@@ -832,7 +832,7 @@ fn match_meta_var<S: Span>(
                                 None => lit.into(),
                                 Some(neg) => tt::TokenTree::Subtree(tt::Subtree {
                                     delimiter: tt::Delimiter::invisible_spanned(*literal.span()),
-                                    token_trees: vec![neg, lit.into()],
+                                    token_trees: Box::new([neg, lit.into()]),
                                 }),
                             }
                         })
@@ -989,10 +989,10 @@ impl<S: Span> TtIter<'_, S> {
                 close: ident.span,
                 kind: tt::DelimiterKind::Invisible,
             },
-            token_trees: vec![
+            token_trees: Box::new([
                 tt::Leaf::Punct(*punct).into(),
                 tt::Leaf::Ident(ident.clone()).into(),
-            ],
+            ]),
         }
         .into())
     }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
index 800bc994ada..9291f799cca 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs
@@ -83,7 +83,7 @@ impl<S: Span> Bindings<S> {
                             close: span,
                             kind: tt::DelimiterKind::Brace,
                         },
-                        token_trees: vec![],
+                        token_trees: Box::new([]),
                     })),
                     // FIXME: Meta and Item should get proper defaults
                     MetaVarKind::Meta | MetaVarKind::Item | MetaVarKind::Tt | MetaVarKind::Vis => {
@@ -349,11 +349,11 @@ fn expand_var<S: Span>(
             // We just treat it a normal tokens
             let tt = tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(id),
-                token_trees: vec![
+                token_trees: Box::new([
                     tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone, span: id })
                         .into(),
                     tt::Leaf::from(tt::Ident { text: v.clone(), span: id }).into(),
-                ],
+                ]),
             }
             .into();
             ExpandResult::ok(Fragment::Tokens(tt))
@@ -406,7 +406,7 @@ fn expand_repeat<S: Span>(
                 value: Fragment::Tokens(
                     tt::Subtree {
                         delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
-                        token_trees: vec![],
+                        token_trees: Box::new([]),
                     }
                     .into(),
                 ),
@@ -455,7 +455,7 @@ fn expand_repeat<S: Span>(
     // e.g {Delimiter:None> ['>'] /Delimiter:None>}
     let tt = tt::Subtree {
         delimiter: tt::Delimiter::invisible_spanned(ctx.call_site),
-        token_trees: buf,
+        token_trees: buf.into_boxed_slice(),
     }
     .into();
 
@@ -486,7 +486,7 @@ fn push_fragment<S: Span>(
 
 fn push_subtree<S>(buf: &mut Vec<tt::TokenTree<S>>, tt: tt::Subtree<S>) {
     match tt.delimiter.kind {
-        tt::DelimiterKind::Invisible => buf.extend(tt.token_trees),
+        tt::DelimiterKind::Invisible => buf.extend(Vec::from(tt.token_trees)),
         _ => buf.push(tt.into()),
     }
 }
@@ -504,7 +504,7 @@ fn fix_up_and_push_path_tt<S: Span>(
     // Note that we only need to fix up the top-level `TokenTree`s because the
     // context of the paths in the descendant `Subtree`s won't be changed by the
     // mbe transcription.
-    for tt in subtree.token_trees {
+    for tt in Vec::from(subtree.token_trees) {
         if prev_was_ident {
             // Pedantically, `(T) -> U` in `FnOnce(T) -> U` is treated as a generic
             // argument list and thus needs `::` between it and `FnOnce`. However in
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index d6c3bd18926..bfc5d197f68 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -130,7 +130,7 @@ where
         tt::Subtree {
             delimiter: tt::Delimiter { kind: tt::DelimiterKind::Invisible, .. },
             token_trees,
-        } => TokenBuffer::from_tokens(token_trees.as_slice()),
+        } => TokenBuffer::from_tokens(token_trees),
         _ => TokenBuffer::from_subtree(tt),
     };
     let parser_input = to_parser_input(&buffer);
@@ -146,7 +146,7 @@ where
             }
             parser::Step::Enter { kind } => tree_sink.start_node(kind),
             parser::Step::Exit => tree_sink.finish_node(),
-            parser::Step::Error { msg } => tree_sink.error(msg.to_string()),
+            parser::Step::Error { msg } => tree_sink.error(msg.to_owned()),
         }
     }
     tree_sink.finish()
@@ -227,14 +227,14 @@ where
     C: TokenConverter<S>,
     S: Span,
 {
-    let entry = tt::Subtree {
+    let entry = tt::SubtreeBuilder {
         delimiter: tt::Delimiter::invisible_spanned(conv.call_site()),
         token_trees: vec![],
     };
     let mut stack = NonEmptyVec::new(entry);
 
     while let Some((token, abs_range)) = conv.bump() {
-        let tt::Subtree { delimiter, token_trees } = stack.last_mut();
+        let tt::SubtreeBuilder { delimiter, token_trees } = stack.last_mut();
 
         let tt = match token.as_leaf() {
             Some(leaf) => tt::TokenTree::Leaf(leaf.clone()),
@@ -260,7 +260,7 @@ where
                     if matches!(expected, Some(expected) if expected == kind) {
                         if let Some(mut subtree) = stack.pop() {
                             subtree.delimiter.close = conv.span_for(abs_range);
-                            stack.last_mut().token_trees.push(subtree.into());
+                            stack.last_mut().token_trees.push(subtree.build().into());
                         }
                         continue;
                     }
@@ -275,7 +275,7 @@ where
                     // Start a new subtree
                     if let Some(kind) = delim {
                         let open = conv.span_for(abs_range);
-                        stack.push(tt::Subtree {
+                        stack.push(tt::SubtreeBuilder {
                             delimiter: tt::Delimiter {
                                 open,
                                 // will be overwritten on subtree close above
@@ -361,7 +361,7 @@ where
         parent.token_trees.extend(entry.token_trees);
     }
 
-    let subtree = stack.into_last();
+    let subtree = stack.into_last().build();
     if let [tt::TokenTree::Subtree(first)] = &*subtree.token_trees {
         first.clone()
     } else {
@@ -454,7 +454,7 @@ fn convert_doc_comment<S: Copy>(
     };
 
     // Make `doc="\" Comments\""
-    let meta_tkns = vec![mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)];
+    let meta_tkns = Box::new([mk_ident("doc"), mk_punct('='), mk_doc_literal(&comment)]);
 
     // Make `#![]`
     let mut token_trees = Vec::with_capacity(3);
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
index e5569138dbf..11d1a728799 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
@@ -1,5 +1,4 @@
-use std::collections::HashMap;
-
+use rustc_hash::FxHashMap;
 use syntax::{ast, AstNode};
 use test_utils::extract_annotations;
 use tt::{
@@ -12,7 +11,7 @@ use crate::{syntax_node_to_token_tree, DummyTestSpanData, DummyTestSpanMap, DUMM
 fn check_punct_spacing(fixture: &str) {
     let source_file = ast::SourceFile::parse(fixture).ok().unwrap();
     let subtree = syntax_node_to_token_tree(source_file.syntax(), DummyTestSpanMap, DUMMY);
-    let mut annotations: HashMap<_, _> = extract_annotations(fixture)
+    let mut annotations: FxHashMap<_, _> = extract_annotations(fixture)
         .into_iter()
         .map(|(range, annotation)| {
             let spacing = match annotation.as_str() {
diff --git a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
index 71513ef4391..f9913cb6f9b 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/tt_iter.rs
@@ -180,7 +180,7 @@ impl<'a, S: Span> TtIter<'a, S> {
             [] | [_] => res.pop(),
             [first, ..] => Some(tt::TokenTree::Subtree(tt::Subtree {
                 delimiter: tt::Delimiter::invisible_spanned(first.first_span()),
-                token_trees: res,
+                token_trees: res.into_boxed_slice(),
             })),
         };
         ExpandResult { value: res, err }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar.rs b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
index 53fda3ae4fd..34715628f18 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar.rs
@@ -393,11 +393,26 @@ fn delimited(
     bra: SyntaxKind,
     ket: SyntaxKind,
     delim: SyntaxKind,
+    unexpected_delim_message: impl Fn() -> String,
     first_set: TokenSet,
     mut parser: impl FnMut(&mut Parser<'_>) -> bool,
 ) {
     p.bump(bra);
     while !p.at(ket) && !p.at(EOF) {
+        if p.at(delim) {
+            // Recover if an argument is missing and only got a delimiter,
+            // e.g. `(a, , b)`.
+
+            // Wrap the erroneous delimiter in an error node so that fixup logic gets rid of it.
+            // FIXME: Ideally this should be handled in fixup in a structured way, but our list
+            // nodes currently have no concept of a missing node between two delimiters.
+            // So doing it this way is easier.
+            let m = p.start();
+            p.error(unexpected_delim_message());
+            p.bump(delim);
+            m.complete(p, ERROR);
+            continue;
+        }
         if !parser(p) {
             break;
         }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index c8626111145..f40c515fa07 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -530,6 +530,15 @@ fn method_call_expr<const FLOAT_RECOVERY: bool>(
     generic_args::opt_generic_arg_list(p, true);
     if p.at(T!['(']) {
         arg_list(p);
+    } else {
+        // emit an error when argument list is missing
+
+        // test_err method_call_missing_argument_list
+        // fn func() {
+        //     foo.bar::<>
+        //     foo.bar::<i32>;
+        // }
+        p.error("expected argument list");
     }
     m.complete(p, METHOD_CALL_EXPR)
 }
@@ -602,6 +611,7 @@ fn cast_expr(p: &mut Parser<'_>, lhs: CompletedMarker) -> CompletedMarker {
 //     foo(bar::);
 //     foo(bar:);
 //     foo(bar+);
+//     foo(a, , b);
 // }
 fn arg_list(p: &mut Parser<'_>) {
     assert!(p.at(T!['(']));
@@ -615,8 +625,9 @@ fn arg_list(p: &mut Parser<'_>) {
         T!['('],
         T![')'],
         T![,],
+        || "expected expression".into(),
         EXPR_FIRST.union(ATTRIBUTE_FIRST),
-        |p: &mut Parser<'_>| expr(p).is_some(),
+        |p| expr(p).is_some(),
     );
     m.complete(p, ARG_LIST);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
index 211af98e6ef..249be2a3335 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_args.rs
@@ -1,5 +1,7 @@
 use super::*;
 
+// test_err generic_arg_list_recover
+// type T = T<0, ,T>;
 pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: bool) {
     let m;
     if p.at(T![::]) && p.nth(2) == T![<] {
@@ -11,7 +13,15 @@ pub(super) fn opt_generic_arg_list(p: &mut Parser<'_>, colon_colon_required: boo
         return;
     }
 
-    delimited(p, T![<], T![>], T![,], GENERIC_ARG_FIRST, generic_arg);
+    delimited(
+        p,
+        T![<],
+        T![>],
+        T![,],
+        || "expected generic argument".into(),
+        GENERIC_ARG_FIRST,
+        generic_arg,
+    );
     m.complete(p, GENERIC_ARG_LIST);
 }
 
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
index 29d9b05d3f3..3c577aa3cb4 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/generic_params.rs
@@ -10,16 +10,27 @@ pub(super) fn opt_generic_param_list(p: &mut Parser<'_>) {
 
 // test generic_param_list
 // fn f<T: Clone>() {}
+
+// test_err generic_param_list_recover
+// fn f<T: Clone,, U:, V>() {}
 fn generic_param_list(p: &mut Parser<'_>) {
     assert!(p.at(T![<]));
     let m = p.start();
-    delimited(p, T![<], T![>], T![,], GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST), |p| {
-        // test generic_param_attribute
-        // fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
-        let m = p.start();
-        attributes::outer_attrs(p);
-        generic_param(p, m)
-    });
+    delimited(
+        p,
+        T![<],
+        T![>],
+        T![,],
+        || "expected generic parameter".into(),
+        GENERIC_PARAM_FIRST.union(ATTRIBUTE_FIRST),
+        |p| {
+            // test generic_param_attribute
+            // fn foo<#[lt_attr] 'a, #[t_attr] T>() {}
+            let m = p.start();
+            attributes::outer_attrs(p);
+            generic_param(p, m)
+        },
+    );
 
     m.complete(p, GENERIC_PARAM_LIST);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
index 17f41b8e13a..21078175c0e 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
@@ -146,28 +146,39 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
 const TUPLE_FIELD_FIRST: TokenSet =
     types::TYPE_FIRST.union(ATTRIBUTE_FIRST).union(VISIBILITY_FIRST);
 
+// test_err tuple_field_list_recovery
+// struct S(struct S;
+// struct S(A,,B);
 fn tuple_field_list(p: &mut Parser<'_>) {
     assert!(p.at(T!['(']));
     let m = p.start();
-    delimited(p, T!['('], T![')'], T![,], TUPLE_FIELD_FIRST, |p| {
-        let m = p.start();
-        // test tuple_field_attrs
-        // struct S (#[attr] f32);
-        attributes::outer_attrs(p);
-        let has_vis = opt_visibility(p, true);
-        if !p.at_ts(types::TYPE_FIRST) {
-            p.error("expected a type");
-            if has_vis {
-                m.complete(p, ERROR);
-            } else {
-                m.abandon(p);
+    delimited(
+        p,
+        T!['('],
+        T![')'],
+        T![,],
+        || "expected tuple field".into(),
+        TUPLE_FIELD_FIRST,
+        |p| {
+            let m = p.start();
+            // test tuple_field_attrs
+            // struct S (#[attr] f32);
+            attributes::outer_attrs(p);
+            let has_vis = opt_visibility(p, true);
+            if !p.at_ts(types::TYPE_FIRST) {
+                p.error("expected a type");
+                if has_vis {
+                    m.complete(p, ERROR);
+                } else {
+                    m.abandon(p);
+                }
+                return false;
             }
-            return false;
-        }
-        types::type_(p);
-        m.complete(p, TUPLE_FIELD);
-        true
-    });
+            types::type_(p);
+            m.complete(p, TUPLE_FIELD);
+            true
+        },
+    );
 
     m.complete(p, TUPLE_FIELD_LIST);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs
index f689c06b31c..675a1fd4650 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/use_item.rs
@@ -93,9 +93,16 @@ pub(crate) fn use_tree_list(p: &mut Parser<'_>) {
     // use b;
     // struct T;
     // fn test() {}
-    delimited(p, T!['{'], T!['}'], T![,], USE_TREE_LIST_FIRST_SET, |p: &mut Parser<'_>| {
-        use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET)
-    });
+    // use {a ,, b};
+    delimited(
+        p,
+        T!['{'],
+        T!['}'],
+        T![,],
+        || "expected use tree".into(),
+        USE_TREE_LIST_FIRST_SET,
+        |p: &mut Parser<'_>| use_tree(p, false) || p.at_ts(USE_TREE_LIST_RECOVERY_SET),
+    );
 
     m.complete(p, USE_TREE_LIST);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
index bf1feb9a7eb..2da9184693d 100644
--- a/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/lexed_str.rs
@@ -149,7 +149,7 @@ impl<'a> Converter<'a> {
 
         if let Some(err) = err {
             let token = self.res.len() as u32;
-            let msg = err.to_string();
+            let msg = err.to_owned();
             self.res.error.push(LexError { msg, token });
         }
     }
diff --git a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs
index bd9e188e4d8..5a71bfd82b1 100644
--- a/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/tests/sourcegen_inline_tests.rs
@@ -1,5 +1,6 @@
 //! This module greps parser's code for specially formatted comments and turns
 //! them into tests.
+#![allow(clippy::disallowed_types, clippy::print_stdout)]
 
 use std::{
     collections::HashMap,
@@ -59,9 +60,9 @@ fn collect_tests(s: &str) -> Vec<Test> {
     for comment_block in sourcegen::CommentBlock::extract_untagged(s) {
         let first_line = &comment_block.contents[0];
         let (name, ok) = if let Some(name) = first_line.strip_prefix("test ") {
-            (name.to_string(), true)
+            (name.to_owned(), true)
         } else if let Some(name) = first_line.strip_prefix("test_err ") {
-            (name.to_string(), false)
+            (name.to_owned(), false)
         } else {
             continue;
         };
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast
index 5d0fe859c29..cd5aa680c65 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rast
@@ -68,6 +68,33 @@ SOURCE_FILE
                 PLUS "+"
               R_PAREN ")"
           SEMICOLON ";"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          CALL_EXPR
+            PATH_EXPR
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "foo"
+            ARG_LIST
+              L_PAREN "("
+              PATH_EXPR
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "a"
+              COMMA ","
+              WHITESPACE " "
+              ERROR
+                COMMA ","
+              WHITESPACE " "
+              PATH_EXPR
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "b"
+              R_PAREN ")"
+          SEMICOLON ";"
         WHITESPACE "\n"
         R_CURLY "}"
   WHITESPACE "\n"
@@ -75,3 +102,4 @@ error 25: expected identifier
 error 39: expected COMMA
 error 39: expected expression
 error 55: expected expression
+error 69: expected expression
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs
index 0e7ac9cc307..175a31f8b58 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0015_arg_list_recovery.rs
@@ -2,4 +2,5 @@ fn main() {
     foo(bar::);
     foo(bar:);
     foo(bar+);
+    foo(a, , b);
 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast
index cb90b093ba0..b576d872e13 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rast
@@ -43,4 +43,29 @@ SOURCE_FILE
         L_CURLY "{"
         R_CURLY "}"
   WHITESPACE "\n"
+  USE
+    USE_KW "use"
+    WHITESPACE " "
+    USE_TREE
+      USE_TREE_LIST
+        L_CURLY "{"
+        USE_TREE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "a"
+        WHITESPACE " "
+        COMMA ","
+        ERROR
+          COMMA ","
+        WHITESPACE " "
+        USE_TREE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "b"
+        R_CURLY "}"
+    SEMICOLON ";"
+  WHITESPACE "\n"
 error 6: expected R_CURLY
+error 46: expected use tree
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs
index f16959c25f2..9885e6ab273 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0026_use_tree_list_err_recovery.rs
@@ -2,3 +2,4 @@ use {a;
 use b;
 struct T;
 fn test() {}
+use {a ,, b};
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rast
new file mode 100644
index 00000000000..02544b5e532
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rast
@@ -0,0 +1,56 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "func"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          METHOD_CALL_EXPR
+            PATH_EXPR
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "foo"
+            DOT "."
+            NAME_REF
+              IDENT "bar"
+            GENERIC_ARG_LIST
+              COLON2 "::"
+              L_ANGLE "<"
+              R_ANGLE ">"
+        WHITESPACE "\n    "
+        EXPR_STMT
+          METHOD_CALL_EXPR
+            PATH_EXPR
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "foo"
+            DOT "."
+            NAME_REF
+              IDENT "bar"
+            GENERIC_ARG_LIST
+              COLON2 "::"
+              L_ANGLE "<"
+              TYPE_ARG
+                PATH_TYPE
+                  PATH
+                    PATH_SEGMENT
+                      NAME_REF
+                        IDENT "i32"
+              R_ANGLE ">"
+          SEMICOLON ";"
+        WHITESPACE "\n"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 27: expected argument list
+error 27: expected SEMICOLON
+error 46: expected argument list
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rs
new file mode 100644
index 00000000000..7c8baecaa9c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0028_method_call_missing_argument_list.rs
@@ -0,0 +1,4 @@
+fn func() {
+    foo.bar::<>
+    foo.bar::<i32>;
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rast
new file mode 100644
index 00000000000..6b0bfa007e3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rast
@@ -0,0 +1,44 @@
+SOURCE_FILE
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "S"
+    TUPLE_FIELD_LIST
+      L_PAREN "("
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "S"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+  STRUCT
+    STRUCT_KW "struct"
+    WHITESPACE " "
+    NAME
+      IDENT "S"
+    TUPLE_FIELD_LIST
+      L_PAREN "("
+      TUPLE_FIELD
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "A"
+      COMMA ","
+      ERROR
+        COMMA ","
+      TUPLE_FIELD
+        PATH_TYPE
+          PATH
+            PATH_SEGMENT
+              NAME_REF
+                IDENT "B"
+      R_PAREN ")"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 9: expected a type
+error 9: expected R_PAREN
+error 9: expected SEMICOLON
+error 30: expected tuple field
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rs
new file mode 100644
index 00000000000..ecb4d8bda14
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0029_tuple_field_list_recovery.rs
@@ -0,0 +1,2 @@
+struct S(struct S;
+struct S(A,,B);
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rast
new file mode 100644
index 00000000000..4cf5a3386b9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+  TYPE_ALIAS
+    TYPE_KW "type"
+    WHITESPACE " "
+    NAME
+      IDENT "T"
+    WHITESPACE " "
+    EQ "="
+    WHITESPACE " "
+    PATH_TYPE
+      PATH
+        PATH_SEGMENT
+          NAME_REF
+            IDENT "T"
+          GENERIC_ARG_LIST
+            L_ANGLE "<"
+            CONST_ARG
+              LITERAL
+                INT_NUMBER "0"
+            COMMA ","
+            WHITESPACE " "
+            ERROR
+              COMMA ","
+            TYPE_ARG
+              PATH_TYPE
+                PATH
+                  PATH_SEGMENT
+                    NAME_REF
+                      IDENT "T"
+            R_ANGLE ">"
+    SEMICOLON ";"
+  WHITESPACE "\n"
+error 14: expected generic argument
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rs
new file mode 100644
index 00000000000..7d849aa1bee
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0030_generic_arg_list_recover.rs
@@ -0,0 +1 @@
+type T = T<0, ,T>;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rast
new file mode 100644
index 00000000000..0a1ed01fbe6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rast
@@ -0,0 +1,45 @@
+SOURCE_FILE
+  FN
+    FN_KW "fn"
+    WHITESPACE " "
+    NAME
+      IDENT "f"
+    GENERIC_PARAM_LIST
+      L_ANGLE "<"
+      TYPE_PARAM
+        NAME
+          IDENT "T"
+        COLON ":"
+        WHITESPACE " "
+        TYPE_BOUND_LIST
+          TYPE_BOUND
+            PATH_TYPE
+              PATH
+                PATH_SEGMENT
+                  NAME_REF
+                    IDENT "Clone"
+      COMMA ","
+      ERROR
+        COMMA ","
+      WHITESPACE " "
+      TYPE_PARAM
+        NAME
+          IDENT "U"
+        COLON ":"
+        TYPE_BOUND_LIST
+      COMMA ","
+      WHITESPACE " "
+      TYPE_PARAM
+        NAME
+          IDENT "V"
+      R_ANGLE ">"
+    PARAM_LIST
+      L_PAREN "("
+      R_PAREN ")"
+    WHITESPACE " "
+    BLOCK_EXPR
+      STMT_LIST
+        L_CURLY "{"
+        R_CURLY "}"
+  WHITESPACE "\n"
+error 14: expected generic parameter
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rs
new file mode 100644
index 00000000000..2b5149bb0dc
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/0031_generic_param_list_recover.rs
@@ -0,0 +1 @@
+fn f<T: Clone,, U:, V>() {}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index 49a0979f4f5..cf01b94c0a2 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -23,6 +23,7 @@ serde.workspace = true
 serde_json = { workspace = true, features = ["unbounded_depth"] }
 tracing.workspace = true
 triomphe.workspace = true
+rustc-hash.workspace = true
 memmap2 = "0.5.4"
 snap = "1.1.0"
 indexmap = "2.1.0"
@@ -40,4 +41,4 @@ base-db.workspace = true
 la-arena.workspace = true
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
index 379d184dd68..1dadfc40ac4 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs
@@ -197,7 +197,7 @@ impl ProcMacro {
                     &deserialize_span_data_index_map(&resp.span_data_table),
                 )
             })),
-            _ => Err(ServerError { message: "unexpected response".to_string(), io: None }),
+            _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
         }
     }
 }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
index e28fe387b84..aa5aff455fd 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg.rs
@@ -187,79 +187,82 @@ mod tests {
             file_id: FileId::from_raw(0),
             ast_id: ErasedFileAstId::from_raw(RawIdx::from(0)),
         };
-        let mut subtree = Subtree {
-            delimiter: Delimiter {
-                open: Span {
-                    range: TextRange::empty(TextSize::new(0)),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-                close: Span {
-                    range: TextRange::empty(TextSize::new(13)),
-                    anchor,
-                    ctx: SyntaxContextId::ROOT,
-                },
-                kind: DelimiterKind::Invisible,
-            },
-            token_trees: Vec::new(),
-        };
-        subtree.token_trees.push(TokenTree::Leaf(
-            Ident {
-                text: "struct".into(),
+
+        let token_trees = Box::new([
+            TokenTree::Leaf(
+                Ident {
+                    text: "struct".into(),
+                    span: Span {
+                        range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                }
+                .into(),
+            ),
+            TokenTree::Leaf(
+                Ident {
+                    text: "Foo".into(),
+                    span: Span {
+                        range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                }
+                .into(),
+            ),
+            TokenTree::Leaf(Leaf::Literal(Literal {
+                text: "Foo".into(),
+
                 span: Span {
-                    range: TextRange::at(TextSize::new(0), TextSize::of("struct")),
+                    range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
                     anchor,
                     ctx: SyntaxContextId::ROOT,
                 },
-            }
-            .into(),
-        ));
-        subtree.token_trees.push(TokenTree::Leaf(
-            Ident {
-                text: "Foo".into(),
+            })),
+            TokenTree::Leaf(Leaf::Punct(Punct {
+                char: '@',
                 span: Span {
-                    range: TextRange::at(TextSize::new(5), TextSize::of("Foo")),
+                    range: TextRange::at(TextSize::new(11), TextSize::of('@')),
                     anchor,
                     ctx: SyntaxContextId::ROOT,
                 },
-            }
-            .into(),
-        ));
-        subtree.token_trees.push(TokenTree::Leaf(Leaf::Literal(Literal {
-            text: "Foo".into(),
-
-            span: Span {
-                range: TextRange::at(TextSize::new(8), TextSize::of("Foo")),
-                anchor,
-                ctx: SyntaxContextId::ROOT,
-            },
-        })));
-        subtree.token_trees.push(TokenTree::Leaf(Leaf::Punct(Punct {
-            char: '@',
-            span: Span {
-                range: TextRange::at(TextSize::new(11), TextSize::of('@')),
-                anchor,
-                ctx: SyntaxContextId::ROOT,
-            },
-            spacing: Spacing::Joint,
-        })));
-        subtree.token_trees.push(TokenTree::Subtree(Subtree {
+                spacing: Spacing::Joint,
+            })),
+            TokenTree::Subtree(Subtree {
+                delimiter: Delimiter {
+                    open: Span {
+                        range: TextRange::at(TextSize::new(12), TextSize::of('{')),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                    close: Span {
+                        range: TextRange::at(TextSize::new(13), TextSize::of('}')),
+                        anchor,
+                        ctx: SyntaxContextId::ROOT,
+                    },
+                    kind: DelimiterKind::Brace,
+                },
+                token_trees: Box::new([]),
+            }),
+        ]);
+
+        Subtree {
             delimiter: Delimiter {
                 open: Span {
-                    range: TextRange::at(TextSize::new(12), TextSize::of('{')),
+                    range: TextRange::empty(TextSize::new(0)),
                     anchor,
                     ctx: SyntaxContextId::ROOT,
                 },
                 close: Span {
-                    range: TextRange::at(TextSize::new(13), TextSize::of('}')),
+                    range: TextRange::empty(TextSize::new(13)),
                     anchor,
                     ctx: SyntaxContextId::ROOT,
                 },
-                kind: DelimiterKind::Brace,
+                kind: DelimiterKind::Invisible,
             },
-            token_trees: vec![],
-        }));
-        subtree
+            token_trees,
+        }
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
index 8dfaba52625..caf9e237fdd 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/msg/flat.rs
@@ -35,10 +35,11 @@
 //! as we don't have bincode in Cargo.toml yet, lets stick with serde_json for
 //! the time being.
 
-use std::collections::{HashMap, VecDeque};
+use std::collections::VecDeque;
 
 use indexmap::IndexSet;
 use la_arena::RawIdx;
+use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 use span::{ErasedFileAstId, FileId, Span, SpanAnchor, SyntaxContextId};
 use text_size::TextRange;
@@ -129,7 +130,7 @@ impl FlatTree {
         span_data_table: &mut SpanDataIndexMap,
     ) -> FlatTree {
         let mut w = Writer {
-            string_table: HashMap::new(),
+            string_table: FxHashMap::default(),
             work: VecDeque::new(),
             span_data_table,
 
@@ -158,7 +159,7 @@ impl FlatTree {
 
     pub fn new_raw(subtree: &tt::Subtree<TokenId>, version: u32) -> FlatTree {
         let mut w = Writer {
-            string_table: HashMap::new(),
+            string_table: FxHashMap::default(),
             work: VecDeque::new(),
             span_data_table: &mut (),
 
@@ -340,7 +341,7 @@ impl InternableSpan for Span {
 
 struct Writer<'a, 'span, S: InternableSpan> {
     work: VecDeque<(usize, &'a tt::Subtree<S>)>,
-    string_table: HashMap<&'a str, u32>,
+    string_table: FxHashMap<&'a str, u32>,
     span_data_table: &'span mut S::Table,
 
     subtree: Vec<SubtreeRepr>,
@@ -370,7 +371,7 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
 
         self.subtree[idx].tt = [first_tt as u32, (first_tt + n_tt) as u32];
 
-        for child in &subtree.token_trees {
+        for child in subtree.token_trees.iter() {
             let idx_tag = match child {
                 tt::TokenTree::Subtree(it) => {
                     let idx = self.enqueue(it);
@@ -418,7 +419,7 @@ impl<'a, 'span, S: InternableSpan> Writer<'a, 'span, S> {
         let table = &mut self.text;
         *self.string_table.entry(text).or_insert_with(|| {
             let idx = table.len();
-            table.push(text.to_string());
+            table.push(text.to_owned());
             idx as u32
         })
     }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
index 5ce601bce69..96f97bf5e20 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs
@@ -78,7 +78,7 @@ impl ProcMacroProcessSrv {
 
         match response {
             Response::ApiVersionCheck(version) => Ok(version),
-            _ => Err(ServerError { message: "unexpected response".to_string(), io: None }),
+            _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
         }
     }
 
@@ -90,7 +90,7 @@ impl ProcMacroProcessSrv {
 
         match response {
             Response::SetConfig(crate::msg::ServerConfig { span_mode }) => Ok(span_mode),
-            _ => Err(ServerError { message: "unexpected response".to_string(), io: None }),
+            _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
         }
     }
 
@@ -104,7 +104,7 @@ impl ProcMacroProcessSrv {
 
         match response {
             Response::ListMacros(it) => Ok(it),
-            _ => Err(ServerError { message: "unexpected response".to_string(), io: None }),
+            _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
index 5f81c0a96d9..f768de3e31d 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/src/version.rs
@@ -38,7 +38,7 @@ pub fn read_dylib_info(dylib_path: &AbsPath) -> io::Result<RustCInfo> {
     let version_part = items.next().ok_or_else(|| err!("no version string"))?;
     let mut version_parts = version_part.split('-');
     let version = version_parts.next().ok_or_else(|| err!("no version"))?;
-    let channel = version_parts.next().unwrap_or_default().to_string();
+    let channel = version_parts.next().unwrap_or_default().to_owned();
 
     let commit = match items.next() {
         Some(commit) => {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
index a36200cdb4c..df0ae3171f5 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs
@@ -1,6 +1,8 @@
 //! A standalone binary for `proc-macro-srv`.
 //! Driver for proc macro server
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+#![allow(clippy::print_stderr)]
+
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_driver as _;
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
index d9018b1b87d..5f8530d08c4 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/proc-macro-test/imp/src/lib.rs
@@ -2,6 +2,7 @@
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
 #![feature(proc_macro_span, proc_macro_def_site)]
+#![allow(clippy::all)]
 
 use proc_macro::{Group, Ident, Literal, Punct, Span, TokenStream, TokenTree};
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
index b864a5e4fd6..c7c7bea9941 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/rust_analyzer_span.rs
@@ -104,7 +104,7 @@ impl server::TokenStream for RaSpanServer {
                     delimiter: delim_to_internal(group.delimiter, group.span),
                     token_trees: match group.stream {
                         Some(stream) => stream.into_iter().collect(),
-                        None => Vec::new(),
+                        None => Box::new([]),
                     },
                 };
                 let tree = tt::TokenTree::from(group);
@@ -221,7 +221,7 @@ impl server::TokenStream for RaSpanServer {
                     stream: if subtree.token_trees.is_empty() {
                         None
                     } else {
-                        Some(subtree.token_trees.into_iter().collect())
+                        Some(subtree.token_trees.into_vec().into_iter().collect())
                     },
                     span: bridge::DelimSpan::from_single(subtree.delimiter.open),
                 }),
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
index c83e09af0d6..edbdc67b482 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_id.rs
@@ -94,7 +94,7 @@ impl server::TokenStream for TokenIdServer {
                     delimiter: delim_to_internal(group.delimiter, group.span),
                     token_trees: match group.stream {
                         Some(stream) => stream.into_iter().collect(),
-                        None => Vec::new(),
+                        None => Box::new([]),
                     },
                 };
                 let tree = TokenTree::from(group);
@@ -206,7 +206,7 @@ impl server::TokenStream for TokenIdServer {
                     stream: if subtree.token_trees.is_empty() {
                         None
                     } else {
-                        Some(TokenStream { token_trees: subtree.token_trees })
+                        Some(TokenStream { token_trees: subtree.token_trees.into_vec() })
                     },
                     span: bridge::DelimSpan::from_single(subtree.delimiter.open),
                 }),
@@ -338,7 +338,7 @@ mod tests {
                         close: tt::TokenId(0),
                         kind: tt::DelimiterKind::Brace,
                     },
-                    token_trees: vec![],
+                    token_trees: Box::new([]),
                 }),
             ],
         };
@@ -354,10 +354,10 @@ mod tests {
                 close: tt::TokenId(0),
                 kind: tt::DelimiterKind::Parenthesis,
             },
-            token_trees: vec![tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
+            token_trees: Box::new([tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
                 text: "a".into(),
                 span: tt::TokenId(0),
-            }))],
+            }))]),
         });
 
         let t1 = TokenStream::from_str("(a)", tt::TokenId(0)).unwrap();
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
index 8f669a30494..5edaa720fc7 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server/token_stream.rs
@@ -15,14 +15,14 @@ impl<S> Default for TokenStream<S> {
 
 impl<S> TokenStream<S> {
     pub(crate) fn new() -> Self {
-        TokenStream { token_trees: vec![] }
+        TokenStream::default()
     }
 
     pub(crate) fn with_subtree(subtree: tt::Subtree<S>) -> Self {
         if subtree.delimiter.kind != tt::DelimiterKind::Invisible {
             TokenStream { token_trees: vec![TokenTree::Subtree(subtree)] }
         } else {
-            TokenStream { token_trees: subtree.token_trees }
+            TokenStream { token_trees: subtree.token_trees.into_vec() }
         }
     }
 
@@ -36,7 +36,7 @@ impl<S> TokenStream<S> {
                 close: call_site,
                 kind: tt::DelimiterKind::Invisible,
             },
-            token_trees: self.token_trees,
+            token_trees: self.token_trees.into_boxed_slice(),
         }
     }
 
@@ -83,7 +83,7 @@ impl<S> Extend<TokenStream<S>> for TokenStream<S> {
                     tt::TokenTree::Subtree(subtree)
                         if subtree.delimiter.kind == tt::DelimiterKind::Invisible =>
                     {
-                        self.token_trees.extend(subtree.token_trees);
+                        self.token_trees.extend(subtree.token_trees.into_vec().into_iter());
                     }
                     _ => {
                         self.token_trees.push(tkn);
diff --git a/src/tools/rust-analyzer/crates/profile/src/lib.rs b/src/tools/rust-analyzer/crates/profile/src/lib.rs
index 38c5b3fc9c7..36399815606 100644
--- a/src/tools/rust-analyzer/crates/profile/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/lib.rs
@@ -21,7 +21,7 @@ pub use countme;
 /// almost zero.
 pub use countme::Count;
 
-thread_local!(static IN_SCOPE: RefCell<bool> = RefCell::new(false));
+thread_local!(static IN_SCOPE: RefCell<bool> = const { RefCell::new(false) });
 
 /// Allows to check if the current code is within some dynamic scope, can be
 /// useful during debugging to figure out why a function is called.
@@ -88,6 +88,7 @@ pub fn cpu_span() -> CpuSpan {
     }
 
     #[cfg(not(feature = "cpu_profiler"))]
+    #[allow(clippy::print_stderr)]
     {
         eprintln!(
             r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."#
diff --git a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
index 814a0257402..990b59cad42 100644
--- a/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
+++ b/src/tools/rust-analyzer/crates/profile/src/stop_watch.rs
@@ -1,4 +1,7 @@
 //! Like `std::time::Instant`, but also measures memory & CPU cycles.
+
+#![allow(clippy::print_stderr)]
+
 use std::{
     fmt,
     time::{Duration, Instant},
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index c1670c20049..a2c9856a3f7 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -322,7 +322,7 @@ impl WorkspaceBuildScripts {
                 let mut deserializer = serde_json::Deserializer::from_str(line);
                 deserializer.disable_recursion_limit();
                 let message = Message::deserialize(&mut deserializer)
-                    .unwrap_or_else(|_| Message::TextLine(line.to_string()));
+                    .unwrap_or_else(|_| Message::TextLine(line.to_owned()));
 
                 match message {
                     Message::BuildScriptExecuted(mut message) => {
@@ -356,7 +356,7 @@ impl WorkspaceBuildScripts {
                                 if let Some(out_dir) =
                                     out_dir.as_os_str().to_str().map(|s| s.to_owned())
                                 {
-                                    data.envs.push(("OUT_DIR".to_string(), out_dir));
+                                    data.envs.push(("OUT_DIR".to_owned(), out_dir));
                                 }
                                 data.out_dir = Some(out_dir);
                                 data.cfgs = cfgs;
@@ -396,7 +396,7 @@ impl WorkspaceBuildScripts {
 
         let errors = if !output.status.success() {
             let errors = errors.into_inner();
-            Some(if errors.is_empty() { "cargo check failed".to_string() } else { errors })
+            Some(if errors.is_empty() { "cargo check failed".to_owned() } else { errors })
         } else {
             None
         };
@@ -490,7 +490,7 @@ impl WorkspaceBuildScripts {
 
 // FIXME: Find a better way to know if it is a dylib.
 fn is_dylib(path: &Utf8Path) -> bool {
-    match path.extension().map(|e| e.to_string().to_lowercase()) {
+    match path.extension().map(|e| e.to_owned().to_lowercase()) {
         None => false,
         Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
     }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index 361f8721a4e..a99ee6e664c 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -285,7 +285,7 @@ impl CargoWorkspace {
         // FIXME: Fetching metadata is a slow process, as it might require
         // calling crates.io. We should be reporting progress here, but it's
         // unclear whether cargo itself supports it.
-        progress("metadata".to_string());
+        progress("metadata".to_owned());
 
         (|| -> Result<cargo_metadata::Metadata, cargo_metadata::Error> {
             let mut command = meta.cargo_command();
@@ -399,7 +399,7 @@ impl CargoWorkspace {
         CargoWorkspace { packages, targets, workspace_root, target_directory }
     }
 
-    pub fn packages(&self) -> impl Iterator<Item = Package> + ExactSizeIterator + '_ {
+    pub fn packages(&self) -> impl ExactSizeIterator<Item = Package> + '_ {
         self.packages.iter().map(|(id, _pkg)| id)
     }
 
@@ -502,7 +502,7 @@ fn rustc_discover_host_triple(
             let field = "host: ";
             let target = stdout.lines().find_map(|l| l.strip_prefix(field));
             if let Some(target) = target {
-                Some(target.to_string())
+                Some(target.to_owned())
             } else {
                 // If we fail to resolve the host platform, it's not the end of the world.
                 tracing::info!("rustc -vV did not report host platform, got:\n{}", stdout);
@@ -536,7 +536,7 @@ fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
     let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
 
     if !trimmed.starts_with('[') {
-        return [trimmed.to_string()].to_vec();
+        return [trimmed.to_owned()].to_vec();
     }
 
     let res = serde_json::from_str(trimmed);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs b/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs
index e366d441c1b..af682904b19 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cfg_flag.rs
@@ -19,7 +19,7 @@ impl FromStr for CfgFlag {
                 if !(value.starts_with('"') && value.ends_with('"')) {
                     return Err(format!("Invalid cfg ({s:?}), value should be in quotes"));
                 }
-                let key = key.to_string();
+                let key = key.to_owned();
                 let value = value[1..value.len() - 1].to_string();
                 CfgFlag::KeyValue { key, value }
             }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/lib.rs b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
index 5114c9c016d..5b91f5d8058 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/lib.rs
@@ -167,7 +167,7 @@ fn utf8_stdout(mut cmd: Command) -> anyhow::Result<String> {
         }
     }
     let stdout = String::from_utf8(output.stdout)?;
-    Ok(stdout.trim().to_string())
+    Ok(stdout.trim().to_owned())
 }
 
 #[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
diff --git a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
index cf12d5b71df..0aee002fbb3 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/rustc_cfg.rs
@@ -33,7 +33,7 @@ pub(crate) fn get(
     res.push(CfgFlag::Atom("target_thread_local".into()));
     for ty in ["8", "16", "32", "64", "cas", "ptr"] {
         for key in ["target_has_atomic", "target_has_atomic_load_store"] {
-            res.push(CfgFlag::KeyValue { key: key.to_string(), value: ty.into() });
+            res.push(CfgFlag::KeyValue { key: key.to_owned(), value: ty.into() });
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index c24c0196dd9..9e19a525838 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -57,7 +57,7 @@ impl Stitched {
         self.by_name("proc_macro")
     }
 
-    pub(crate) fn crates(&self) -> impl Iterator<Item = SysrootCrate> + ExactSizeIterator + '_ {
+    pub(crate) fn crates(&self) -> impl ExactSizeIterator<Item = SysrootCrate> + '_ {
         self.crates.iter().map(|(id, _data)| id)
     }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index 7c078f72f52..74042e925ed 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -129,7 +129,7 @@ fn get_fake_sysroot() -> Sysroot {
 }
 
 fn rooted_project_json(data: ProjectJsonData) -> ProjectJson {
-    let mut root = "$ROOT$".to_string();
+    let mut root = "$ROOT$".to_owned();
     replace_root(&mut root, true);
     let path = Path::new(&root);
     let base = AbsPath::assert(path);
diff --git a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
index 8c5ea0619ac..cda5ad2f110 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -241,7 +241,7 @@ impl ProjectWorkspace {
                         .map_err(|p| Some(format!("rustc source path is not absolute: {p}"))),
                     Some(RustLibSource::Discover) => {
                         sysroot.as_ref().ok().and_then(Sysroot::discover_rustc_src).ok_or_else(
-                            || Some("Failed to discover rustc source for sysroot.".to_string()),
+                            || Some("Failed to discover rustc source for sysroot.".to_owned()),
                         )
                     }
                     None => Err(None),
@@ -840,7 +840,7 @@ fn project_json_to_crate_graph(
                     if let Some(name) = display_name.clone() {
                         CrateOrigin::Local {
                             repo: repository.clone(),
-                            name: Some(name.canonical_name().to_string()),
+                            name: Some(name.canonical_name().to_owned()),
                         }
                     } else {
                         CrateOrigin::Local { repo: None, name: None }
@@ -1117,7 +1117,7 @@ fn detached_files_to_crate_graph(
         let display_name = detached_file
             .file_stem()
             .and_then(|os_str| os_str.to_str())
-            .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_string()));
+            .map(|file_stem| CrateDisplayName::from_canonical_name(file_stem.to_owned()));
         let detached_file_crate = crate_graph.add_crate_root(
             file_id,
             Edition::CURRENT,
@@ -1129,7 +1129,7 @@ fn detached_files_to_crate_graph(
             false,
             CrateOrigin::Local {
                 repo: None,
-                name: display_name.map(|n| n.canonical_name().to_string()),
+                name: display_name.map(|n| n.canonical_name().to_owned()),
             },
             target_layout.clone(),
             None,
@@ -1323,7 +1323,7 @@ fn add_target_crate_root(
         }
     }
 
-    let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_string());
+    let display_name = CrateDisplayName::from_canonical_name(cargo_name.to_owned());
     let crate_id = crate_graph.add_crate_root(
         file_id,
         edition,
@@ -1455,7 +1455,7 @@ fn sysroot_to_crate_graph(
             (SysrootPublicDeps { deps: pub_deps }, libproc_macro)
         }
         SysrootMode::Stitched(stitched) => {
-            let cfg_options = create_cfg_options(rustc_cfg.clone());
+            let cfg_options = create_cfg_options(rustc_cfg);
             let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = stitched
                 .crates()
                 .filter_map(|krate| {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
index 66b680571a9..269dd3cfffe 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/bin/main.rs
@@ -3,7 +3,9 @@
 //! Based on cli flags, either spawns an LSP server, or runs a batch analysis
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(clippy::print_stdout, clippy::print_stderr)]
 #![cfg_attr(feature = "in-rust-tree", feature(rustc_private))]
+
 #[cfg(feature = "in-rust-tree")]
 extern crate rustc_driver as _;
 
@@ -132,7 +134,7 @@ fn setup_logging(log_file_flag: Option<PathBuf>) -> anyhow::Result<()> {
         writer,
         // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually
         // useful information in there for debugging.
-        filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_string()),
+        filter: env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()),
         chalk_filter: env::var("CHALK_DEBUG").ok(),
         profile_filter: env::var("RA_PROFILE").ok(),
     }
@@ -222,7 +224,7 @@ fn run_server() -> anyhow::Result<()> {
                 MessageType, ShowMessageParams,
             };
             let not = lsp_server::Notification::new(
-                ShowMessage::METHOD.to_string(),
+                ShowMessage::METHOD.to_owned(),
                 ShowMessageParams { typ: MessageType::WARNING, message: e.to_string() },
             );
             connection.sender.send(lsp_server::Message::Notification(not)).unwrap();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
index 94eab97e8fc..a1469c22abf 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/caps.rs
@@ -44,17 +44,17 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
         completion_provider: Some(CompletionOptions {
             resolve_provider: completions_resolve_provider(config.caps()),
             trigger_characters: Some(vec![
-                ":".to_string(),
-                ".".to_string(),
-                "'".to_string(),
-                "(".to_string(),
+                ":".to_owned(),
+                ".".to_owned(),
+                "'".to_owned(),
+                "(".to_owned(),
             ]),
             all_commit_characters: None,
             completion_item: completion_item(config),
             work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
         signature_help_provider: Some(SignatureHelpOptions {
-            trigger_characters: Some(vec!["(".to_string(), ",".to_string(), "<".to_string()]),
+            trigger_characters: Some(vec!["(".to_owned(), ",".to_owned(), "<".to_owned()]),
             retrigger_characters: None,
             work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
@@ -74,7 +74,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             _ => Some(OneOf::Left(false)),
         },
         document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
-            first_trigger_character: "=".to_string(),
+            first_trigger_character: "=".to_owned(),
             more_trigger_character: Some(more_trigger_character(config)),
         }),
         selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
@@ -222,9 +222,9 @@ fn code_action_capabilities(client_caps: &ClientCapabilities) -> CodeActionProvi
 }
 
 fn more_trigger_character(config: &Config) -> Vec<String> {
-    let mut res = vec![".".to_string(), ">".to_string(), "{".to_string(), "(".to_string()];
+    let mut res = vec![".".to_owned(), ">".to_owned(), "{".to_owned(), "(".to_owned()];
     if config.snippet_cap() {
-        res.push("<".to_string());
+        res.push("<".to_owned());
     }
     res
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
index 00670f2cb4c..0bd6677b662 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli.rs
@@ -1,5 +1,7 @@
 //! Various batch processing tasks, intended primarily for debugging.
 
+#![allow(clippy::print_stdout, clippy::print_stderr)]
+
 mod analysis_stats;
 mod diagnostics;
 pub mod flags;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 31bdd2a0e82..2741b452225 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -397,7 +397,7 @@ impl flags::AnalysisStats {
                 module
                     .krate()
                     .display_name(db)
-                    .map(|it| it.canonical_name().to_string())
+                    .map(|it| it.canonical_name().to_owned())
                     .into_iter()
                     .chain(
                         module
@@ -688,7 +688,7 @@ impl flags::AnalysisStats {
                 module
                     .krate()
                     .display_name(db)
-                    .map(|it| it.canonical_name().to_string())
+                    .map(|it| it.canonical_name().to_owned())
                     .into_iter()
                     .chain(
                         module
@@ -833,7 +833,7 @@ impl flags::AnalysisStats {
 fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id: ExprId) -> String {
     let src = match sm.expr_syntax(expr_id) {
         Ok(s) => s,
-        Err(SyntheticSyntax) => return "synthetic,,".to_string(),
+        Err(SyntheticSyntax) => return "synthetic,,".to_owned(),
     };
     let root = db.parse_or_expand(src.file_id);
     let node = src.map(|e| e.to_node(&root).syntax().clone());
@@ -849,7 +849,7 @@ fn location_csv_expr(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, expr_id:
 fn location_csv_pat(db: &RootDatabase, vfs: &Vfs, sm: &BodySourceMap, pat_id: PatId) -> String {
     let src = match sm.pat_syntax(pat_id) {
         Ok(s) => s,
-        Err(SyntheticSyntax) => return "synthetic,,".to_string(),
+        Err(SyntheticSyntax) => return "synthetic,,".to_owned(),
     };
     let root = db.parse_or_expand(src.file_id);
     let node = src.map(|e| e.to_node(&root).syntax().clone());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 6d2e97be20e..605670f6a82 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -45,7 +45,7 @@ impl flags::Diagnostics {
             let file_id = module.definition_source_file_id(db).original_file(db);
             if !visited_files.contains(&file_id) {
                 let crate_name =
-                    module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string();
+                    module.krate().display_name(db).as_deref().unwrap_or("unknown").to_owned();
                 println!("processing crate: {crate_name}, module: {}", _vfs.file_path(file_id));
                 for diagnostic in analysis
                     .diagnostics(
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
index 64f965e22ac..1424a775777 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/lsif.rs
@@ -1,6 +1,5 @@
 //! LSIF (language server index format) generator
 
-use std::collections::HashMap;
 use std::env;
 use std::time::Instant;
 
@@ -16,6 +15,7 @@ use ide_db::{
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
 use lsp_types::{self, lsif};
 use project_model::{CargoConfig, ProjectManifest, ProjectWorkspace, RustLibSource};
+use rustc_hash::FxHashMap;
 use vfs::{AbsPathBuf, Vfs};
 
 use crate::{
@@ -35,10 +35,10 @@ impl<DB: ParallelDatabase> Clone for Snap<salsa::Snapshot<DB>> {
 
 struct LsifManager<'a> {
     count: i32,
-    token_map: HashMap<TokenId, Id>,
-    range_map: HashMap<FileRange, Id>,
-    file_map: HashMap<FileId, Id>,
-    package_map: HashMap<PackageInformation, Id>,
+    token_map: FxHashMap<TokenId, Id>,
+    range_map: FxHashMap<FileRange, Id>,
+    file_map: FxHashMap<FileId, Id>,
+    package_map: FxHashMap<PackageInformation, Id>,
     analysis: &'a Analysis,
     db: &'a RootDatabase,
     vfs: &'a Vfs,
@@ -57,10 +57,10 @@ impl LsifManager<'_> {
     fn new<'a>(analysis: &'a Analysis, db: &'a RootDatabase, vfs: &'a Vfs) -> LsifManager<'a> {
         LsifManager {
             count: 0,
-            token_map: HashMap::default(),
-            range_map: HashMap::default(),
-            file_map: HashMap::default(),
-            package_map: HashMap::default(),
+            token_map: FxHashMap::default(),
+            range_map: FxHashMap::default(),
+            file_map: FxHashMap::default(),
+            package_map: FxHashMap::default(),
             analysis,
             db,
             vfs,
@@ -104,12 +104,12 @@ impl LsifManager<'_> {
         let result_set_id =
             self.add_vertex(lsif::Vertex::PackageInformation(lsif::PackageInformation {
                 name: pi.name,
-                manager: "cargo".to_string(),
+                manager: "cargo".to_owned(),
                 uri: None,
                 content: None,
                 repository: pi.repo.map(|url| lsif::Repository {
                     url,
-                    r#type: "git".to_string(),
+                    r#type: "git".to_owned(),
                     commit_id: None,
                 }),
                 version: pi.version,
@@ -148,7 +148,7 @@ impl LsifManager<'_> {
         let path = self.vfs.file_path(id);
         let path = path.as_path().unwrap();
         let doc_id = self.add_vertex(lsif::Vertex::Document(lsif::Document {
-            language_id: "rust".to_string(),
+            language_id: "rust".to_owned(),
             uri: lsp_types::Url::from_file_path(path).unwrap(),
         }));
         self.file_map.insert(id, doc_id);
@@ -175,7 +175,7 @@ impl LsifManager<'_> {
         if let Some(moniker) = token.moniker {
             let package_id = self.get_package_id(moniker.package_information);
             let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
-                scheme: "rust-analyzer".to_string(),
+                scheme: "rust-analyzer".to_owned(),
                 identifier: moniker.identifier.to_string(),
                 unique: lsp_types::UniquenessLevel::Scheme,
                 kind: Some(match moniker.kind {
@@ -215,7 +215,7 @@ impl LsifManager<'_> {
                 out_v: result_set_id.into(),
             }));
             let mut edges = token.references.iter().fold(
-                HashMap::<_, Vec<lsp_types::NumberOrString>>::new(),
+                FxHashMap::<_, Vec<lsp_types::NumberOrString>>::default(),
                 |mut edges, it| {
                     let entry = edges.entry((it.range.file_id, it.is_definition)).or_default();
                     entry.push((*self.range_map.get(&it.range).unwrap()).into());
@@ -313,7 +313,7 @@ impl flags::Lsif {
             project_root: lsp_types::Url::from_file_path(path).unwrap(),
             position_encoding: lsif::Encoding::Utf16,
             tool_info: Some(lsp_types::lsif::ToolInfo {
-                name: "rust-analyzer".to_string(),
+                name: "rust-analyzer".to_owned(),
                 args: vec![],
                 version: Some(version().to_string()),
             }),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
index 8166aa23b44..b2337300997 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/progress_report.rs
@@ -92,7 +92,7 @@ impl<'a> ProgressReport<'a> {
 
         let _ = io::stdout().write(output.as_bytes());
         let _ = io::stdout().flush();
-        self.text = text.to_string();
+        self.text = text.to_owned();
     }
 
     fn set_value(&mut self, value: f32) {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
index d07dcdec251..6b43e095429 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/run_tests.rs
@@ -34,7 +34,7 @@ impl flags::RunTests {
             .filter(|x| x.is_test(db));
         let span_formatter = |file_id, text_range: TextRange| {
             let line_col = match db.line_index(file_id).try_line_col(text_range.start()) {
-                None => " (unknown line col)".to_string(),
+                None => " (unknown line col)".to_owned(),
                 Some(x) => format!("#{}:{}", x.line + 1, x.col),
             };
             let path = &db
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
index be7e434acac..64ea246a458 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -1,8 +1,6 @@
 //! Run all tests in a project, similar to `cargo test`, but using the mir interpreter.
 
-use std::{
-    cell::RefCell, collections::HashMap, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf,
-};
+use std::{cell::RefCell, fs::read_to_string, panic::AssertUnwindSafe, path::PathBuf};
 
 use hir::{Change, Crate};
 use ide::{AnalysisHost, DiagnosticCode, DiagnosticsConfig};
@@ -10,6 +8,7 @@ use profile::StopWatch;
 use project_model::{CargoConfig, ProjectWorkspace, RustLibSource, Sysroot};
 
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
+use rustc_hash::FxHashMap;
 use triomphe::Arc;
 use vfs::{AbsPathBuf, FileId};
 use walkdir::WalkDir;
@@ -27,7 +26,7 @@ struct Tester {
 
 fn string_to_diagnostic_code_leaky(code: &str) -> DiagnosticCode {
     thread_local! {
-        static LEAK_STORE: RefCell<HashMap<String, DiagnosticCode>> = RefCell::new(HashMap::new());
+        static LEAK_STORE: RefCell<FxHashMap<String, DiagnosticCode>> = RefCell::new(FxHashMap::default());
     }
     LEAK_STORE.with_borrow_mut(|s| match s.get(code) {
         Some(c) => *c,
@@ -39,9 +38,9 @@ fn string_to_diagnostic_code_leaky(code: &str) -> DiagnosticCode {
     })
 }
 
-fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> HashMap<DiagnosticCode, usize> {
+fn detect_errors_from_rustc_stderr_file(p: PathBuf) -> FxHashMap<DiagnosticCode, usize> {
     let text = read_to_string(p).unwrap();
-    let mut result = HashMap::new();
+    let mut result = FxHashMap::default();
     {
         let mut text = &*text;
         while let Some(p) = text.find("error[E") {
@@ -106,7 +105,7 @@ impl Tester {
         let expected = if stderr_path.exists() {
             detect_errors_from_rustc_stderr_file(stderr_path)
         } else {
-            HashMap::new()
+            FxHashMap::default()
         };
         let text = read_to_string(&p).unwrap();
         let mut change = Change::new();
@@ -125,7 +124,7 @@ impl Tester {
         self.host.apply_change(change);
         let diagnostic_config = DiagnosticsConfig::test_sample();
 
-        let mut actual = HashMap::new();
+        let mut actual = FxHashMap::default();
         let panicked = match std::panic::catch_unwind(|| {
             self.host
                 .analysis()
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index 81622a4617a..f4aec288348 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -1,10 +1,6 @@
 //! SCIP generator
 
-use std::{
-    collections::{HashMap, HashSet},
-    path::PathBuf,
-    time::Instant,
-};
+use std::{path::PathBuf, time::Instant};
 
 use ide::{
     LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile,
@@ -12,6 +8,7 @@ use ide::{
 };
 use ide_db::LineIndexDatabase;
 use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
+use rustc_hash::{FxHashMap, FxHashSet};
 use scip::types as scip_types;
 
 use crate::{
@@ -76,9 +73,10 @@ impl flags::Scip {
         };
         let mut documents = Vec::new();
 
-        let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
-        let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
-        let mut tokens_to_enclosing_symbol: HashMap<TokenId, Option<String>> = HashMap::new();
+        let mut symbols_emitted: FxHashSet<TokenId> = FxHashSet::default();
+        let mut tokens_to_symbol: FxHashMap<TokenId, String> = FxHashMap::default();
+        let mut tokens_to_enclosing_symbol: FxHashMap<TokenId, Option<String>> =
+            FxHashMap::default();
 
         for StaticIndexedFile { file_id, tokens, .. } in si.files {
             let mut local_count = 0;
@@ -148,7 +146,7 @@ impl flags::Scip {
                         let signature_documentation =
                             token.signature.clone().map(|text| scip_types::Document {
                                 relative_path: relative_path.clone(),
-                                language: "rust".to_string(),
+                                language: "rust".to_owned(),
                                 text,
                                 position_encoding,
                                 ..Default::default()
@@ -188,7 +186,7 @@ impl flags::Scip {
                 scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into();
             documents.push(scip_types::Document {
                 relative_path,
-                language: "rust".to_string(),
+                language: "rust".to_owned(),
                 occurrences,
                 symbols,
                 text: String::new(),
@@ -218,7 +216,7 @@ fn get_relative_filepath(
     rootpath: &vfs::AbsPathBuf,
     file_id: ide::FileId,
 ) -> Option<String> {
-    Some(vfs.file_path(file_id).as_path()?.strip_prefix(rootpath)?.as_ref().to_str()?.to_string())
+    Some(vfs.file_path(file_id).as_path()?.strip_prefix(rootpath)?.as_ref().to_str()?.to_owned())
 }
 
 // SCIP Ranges have a (very large) optimization that ranges if they are on the same line
@@ -241,8 +239,8 @@ fn new_descriptor_str(
     suffix: scip_types::descriptor::Suffix,
 ) -> scip_types::Descriptor {
     scip_types::Descriptor {
-        name: name.to_string(),
-        disambiguator: "".to_string(),
+        name: name.to_owned(),
+        disambiguator: "".to_owned(),
         suffix: suffix.into(),
         special_fields: Default::default(),
     }
@@ -313,9 +311,9 @@ fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
     scip_types::Symbol {
         scheme: "rust-analyzer".into(),
         package: Some(scip_types::Package {
-            manager: "cargo".to_string(),
+            manager: "cargo".to_owned(),
             name: package_name,
-            version: version.unwrap_or_else(|| ".".to_string()),
+            version: version.unwrap_or_else(|| ".".to_owned()),
             special_fields: Default::default(),
         })
         .into(),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 815f6ea12e8..7bdd9ec866a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -223,6 +223,9 @@ config_data! {
         ///
         /// Aliased as `"checkOnSave.targets"`.
         check_targets | checkOnSave_targets | checkOnSave_target: Option<CheckOnSaveTargets> = "null",
+        /// Whether `--workspace` should be passed to `cargo check`.
+        /// If false, `-p <package>` will be passed instead.
+        check_workspace: bool = "true",
 
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
@@ -478,6 +481,9 @@ config_data! {
         /// Whether to show `can't find Cargo.toml` error message.
         notifications_cargoTomlNotFound: bool      = "true",
 
+        /// Whether to send an UnindexedProject notification to the client.
+        notifications_unindexedProject: bool      = "false",
+
         /// How many worker threads in the main loop. The default `null` means to pick automatically.
         numThreads: Option<usize> = "null",
 
@@ -745,6 +751,7 @@ pub enum FilesWatcher {
 #[derive(Debug, Clone)]
 pub struct NotificationsConfig {
     pub cargo_toml_not_found: bool,
+    pub unindexed_project: bool,
 }
 
 #[derive(Debug, Clone)]
@@ -897,7 +904,7 @@ impl Config {
         use serde::de::Error;
         if self.data.check_command.is_empty() {
             error_sink.push((
-                "/check/command".to_string(),
+                "/check/command".to_owned(),
                 serde_json::Error::custom("expected a non-empty string"),
             ));
         }
@@ -1220,7 +1227,10 @@ impl Config {
     }
 
     pub fn notifications(&self) -> NotificationsConfig {
-        NotificationsConfig { cargo_toml_not_found: self.data.notifications_cargoTomlNotFound }
+        NotificationsConfig {
+            cargo_toml_not_found: self.data.notifications_cargoTomlNotFound,
+            unindexed_project: self.data.notifications_unindexedProject,
+        }
     }
 
     pub fn cargo_autoreload(&self) -> bool {
@@ -1323,6 +1333,10 @@ impl Config {
         }
     }
 
+    pub fn flycheck_workspace(&self) -> bool {
+        self.data.check_workspace
+    }
+
     pub fn flycheck(&self) -> FlycheckConfig {
         match &self.data.check_overrideCommand {
             Some(args) if !args.is_empty() => {
@@ -2612,7 +2626,7 @@ mod tests {
             .replace('\n', "\n            ")
             .trim_start_matches('\n')
             .trim_end()
-            .to_string();
+            .to_owned();
         schema.push_str(",\n");
 
         // Transform the asciidoc form link to markdown style.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs
index 73d2ed32984..92c0c0d048a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config/patch_old_style.rs
@@ -19,7 +19,7 @@ pub(super) fn patch_json_for_outdated_configs(json: &mut Value) {
                 Some(it) => {
                     let mut last = it;
                     for segment in [$(stringify!($dst)),+].into_iter().rev() {
-                        last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_string(), last))));
+                        last = Value::Object(serde_json::Map::from_iter(std::iter::once((segment.to_owned(), last))));
                     }
 
                     merge(json, last);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
index c91b22999de..a0a53f545c9 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics.rs
@@ -135,11 +135,11 @@ pub(crate) fn fetch_native_diagnostics(
         |line_index: &crate::line_index::LineIndex, d: ide::Diagnostic| lsp_types::Diagnostic {
             range: lsp::to_proto::range(line_index, d.range.range),
             severity: Some(lsp::to_proto::diagnostic_severity(d.severity)),
-            code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_string())),
+            code: Some(lsp_types::NumberOrString::String(d.code.as_str().to_owned())),
             code_description: Some(lsp_types::CodeDescription {
                 href: lsp_types::Url::parse(&d.code.url()).unwrap(),
             }),
-            source: Some("rust-analyzer".to_string()),
+            source: Some("rust-analyzer".to_owned()),
             message: d.message,
             related_information: None,
             tags: d.unused.then(|| vec![lsp_types::DiagnosticTag::UNNECESSARY]),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index f8bc66ff8e7..e900f2601d8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -1,9 +1,9 @@
 //! This module provides the functionality needed to convert diagnostics from
 //! `cargo check` json format to the LSP diagnostic format.
-use std::collections::HashMap;
 
 use flycheck::{Applicability, DiagnosticLevel, DiagnosticSpan};
 use itertools::Itertools;
+use rustc_hash::FxHashMap;
 use stdx::format_to;
 use vfs::{AbsPath, AbsPathBuf};
 
@@ -186,7 +186,7 @@ fn map_rust_child_diagnostic(
         return MappedRustChildDiagnostic::MessageLine(rd.message.clone());
     }
 
-    let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new();
+    let mut edit_map: FxHashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = FxHashMap::default();
     let mut suggested_replacements = Vec::new();
     let mut is_preferred = true;
     for &span in &spans {
@@ -403,16 +403,16 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
                 related_info_macro_calls.push(lsp_types::DiagnosticRelatedInformation {
                     location: secondary_location.clone(),
                     message: if is_in_macro_call {
-                        "Error originated from macro call here".to_string()
+                        "Error originated from macro call here".to_owned()
                     } else {
-                        "Actual error occurred here".to_string()
+                        "Actual error occurred here".to_owned()
                     },
                 });
                 // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
                 let information_for_additional_diagnostic =
                     vec![lsp_types::DiagnosticRelatedInformation {
                         location: primary_location.clone(),
-                        message: "Exact error occurred here".to_string(),
+                        message: "Exact error occurred here".to_owned(),
                     }];
 
                 let diagnostic = lsp_types::Diagnostic {
@@ -467,7 +467,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
             // `related_information`, which just produces hard-to-read links, at least in VS Code.
             let back_ref = lsp_types::DiagnosticRelatedInformation {
                 location: primary_location,
-                message: "original diagnostic".to_string(),
+                message: "original diagnostic".to_owned(),
             };
             for sub in &subdiagnostics {
                 diagnostics.push(MappedRustDiagnostic {
@@ -685,7 +685,7 @@ mod tests {
     fn rustc_unused_variable_as_info() {
         check_with_config(
             DiagnosticsMapConfig {
-                warnings_as_info: vec!["unused_variables".to_string()],
+                warnings_as_info: vec!["unused_variables".to_owned()],
                 ..DiagnosticsMapConfig::default()
             },
             r##"{
@@ -769,7 +769,7 @@ mod tests {
     fn rustc_unused_variable_as_hint() {
         check_with_config(
             DiagnosticsMapConfig {
-                warnings_as_hint: vec!["unused_variables".to_string()],
+                warnings_as_hint: vec!["unused_variables".to_owned()],
                 ..DiagnosticsMapConfig::default()
             },
             r##"{
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
index fa856a796a8..7adaef4ff6e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/dispatch.rs
@@ -123,7 +123,7 @@ impl RequestDispatcher<'_> {
                     Err(_) => Task::Response(lsp_server::Response::new_err(
                         req.id,
                         lsp_server::ErrorCode::ContentModified as i32,
-                        "content modified".to_string(),
+                        "content modified".to_owned(),
                     )),
                 }
             }
@@ -179,7 +179,7 @@ impl RequestDispatcher<'_> {
             let response = lsp_server::Response::new_err(
                 req.id,
                 lsp_server::ErrorCode::MethodNotFound as i32,
-                "unknown request".to_string(),
+                "unknown request".to_owned(),
             );
             self.global_state.respond(response);
         }
@@ -269,7 +269,7 @@ where
                 .map(String::as_str)
                 .or_else(|| panic.downcast_ref::<&str>().copied());
 
-            let mut message = "request handler panicked".to_string();
+            let mut message = "request handler panicked".to_owned();
             if let Some(panic_message) = panic_message {
                 message.push_str(": ");
                 message.push_str(panic_message)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 2f226d01155..da4422a60a8 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -33,7 +33,7 @@ use crate::{
     mem_docs::MemDocs,
     op_queue::OpQueue,
     reload,
-    task_pool::TaskPool,
+    task_pool::{TaskPool, TaskQueue},
 };
 
 // Enforces drop order
@@ -126,6 +126,17 @@ pub(crate) struct GlobalState {
         OpQueue<(), (Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
     pub(crate) fetch_proc_macros_queue: OpQueue<Vec<ProcMacroPaths>, bool>,
     pub(crate) prime_caches_queue: OpQueue,
+
+    /// A deferred task queue.
+    ///
+    /// This queue is used for doing database-dependent work inside of sync
+    /// handlers, as accessing the database may block latency-sensitive
+    /// interactions and should be moved away from the main thread.
+    ///
+    /// For certain features, such as [`lsp_ext::UnindexedProjectParams`],
+    /// this queue should run only *after* [`GlobalState::process_changes`] has
+    /// been called.
+    pub(crate) deferred_task_queue: TaskQueue,
 }
 
 /// An immutable snapshot of the world's state at a point in time.
@@ -165,6 +176,11 @@ impl GlobalState {
             Handle { handle, receiver }
         };
 
+        let task_queue = {
+            let (sender, receiver) = unbounded();
+            TaskQueue { sender, receiver }
+        };
+
         let mut analysis_host = AnalysisHost::new(config.lru_parse_query_capacity());
         if let Some(capacities) = config.lru_query_capacities() {
             analysis_host.update_lru_capacities(capacities);
@@ -208,6 +224,8 @@ impl GlobalState {
             fetch_proc_macros_queue: OpQueue::default(),
 
             prime_caches_queue: OpQueue::default(),
+
+            deferred_task_queue: task_queue,
         };
         // Apply any required database inputs from the config.
         this.update_configuration(config);
@@ -370,7 +388,7 @@ impl GlobalState {
         params: R::Params,
         handler: ReqHandler,
     ) {
-        let request = self.req_queue.outgoing.register(R::METHOD.to_string(), params, handler);
+        let request = self.req_queue.outgoing.register(R::METHOD.to_owned(), params, handler);
         self.send(request.into());
     }
 
@@ -387,7 +405,7 @@ impl GlobalState {
         &self,
         params: N::Params,
     ) {
-        let not = lsp_server::Notification::new(N::METHOD.to_string(), params);
+        let not = lsp_server::Notification::new(N::METHOD.to_owned(), params);
         self.send(not.into());
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 1f24e950105..d3c2073f09d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -70,7 +70,15 @@ pub(crate) fn handle_did_open_text_document(
         if already_exists {
             tracing::error!("duplicate DidOpenTextDocument: {}", path);
         }
+
         state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes()));
+        if state.config.notifications().unindexed_project {
+            tracing::debug!("queuing task");
+            let _ = state
+                .deferred_task_queue
+                .sender
+                .send(crate::main_loop::QueuedTask::CheckIfIndexed(params.text_document.uri));
+        }
     }
     Ok(())
 }
@@ -160,7 +168,7 @@ pub(crate) fn handle_did_save_text_document(
     } else if state.config.check_on_save() {
         // No specific flycheck was triggered, so let's trigger all of them.
         for flycheck in state.flycheck.iter() {
-            flycheck.restart();
+            flycheck.restart_workspace();
         }
     }
     Ok(())
@@ -176,7 +184,7 @@ pub(crate) fn handle_did_change_configuration(
         lsp_types::ConfigurationParams {
             items: vec![lsp_types::ConfigurationItem {
                 scope_uri: None,
-                section: Some("rust-analyzer".to_string()),
+                section: Some("rust-analyzer".to_owned()),
             }],
         },
         |this, resp| {
@@ -228,7 +236,7 @@ pub(crate) fn handle_did_change_workspace_folders(
 
     if !config.has_linked_projects() && config.detached_files().is_empty() {
         config.rediscover_workspaces();
-        state.fetch_workspaces_queue.request_op("client workspaces changed".to_string(), false)
+        state.fetch_workspaces_queue.request_op("client workspaces changed".to_owned(), false)
     }
 
     Ok(())
@@ -281,27 +289,40 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
             let crate_root_paths: Vec<_> = crate_root_paths.iter().map(Deref::deref).collect();
 
             // Find all workspaces that have at least one target containing the saved file
-            let workspace_ids = world.workspaces.iter().enumerate().filter(|(_, ws)| match ws {
-                project_model::ProjectWorkspace::Cargo { cargo, .. } => {
-                    cargo.packages().any(|pkg| {
-                        cargo[pkg]
-                            .targets
-                            .iter()
-                            .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()))
-                    })
-                }
-                project_model::ProjectWorkspace::Json { project, .. } => {
-                    project.crates().any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c))
-                }
-                project_model::ProjectWorkspace::DetachedFiles { .. } => false,
+            let workspace_ids = world.workspaces.iter().enumerate().filter_map(|(idx, ws)| {
+                let package = match ws {
+                    project_model::ProjectWorkspace::Cargo { cargo, .. } => {
+                        cargo.packages().find_map(|pkg| {
+                            let has_target_with_root = cargo[pkg]
+                                .targets
+                                .iter()
+                                .any(|&it| crate_root_paths.contains(&cargo[it].root.as_path()));
+                            has_target_with_root.then(|| cargo[pkg].name.clone())
+                        })
+                    }
+                    project_model::ProjectWorkspace::Json { project, .. } => {
+                        if !project
+                            .crates()
+                            .any(|(c, _)| crate_ids.iter().any(|&crate_id| crate_id == c))
+                        {
+                            return None;
+                        }
+                        None
+                    }
+                    project_model::ProjectWorkspace::DetachedFiles { .. } => return None,
+                };
+                Some((idx, package))
             });
 
             // Find and trigger corresponding flychecks
             for flycheck in world.flycheck.iter() {
-                for (id, _) in workspace_ids.clone() {
+                for (id, package) in workspace_ids.clone() {
                     if id == flycheck.id() {
                         updated = true;
-                        flycheck.restart();
+                        match package.filter(|_| !world.config.flycheck_workspace()) {
+                            Some(package) => flycheck.restart_for_package(package),
+                            None => flycheck.restart_workspace(),
+                        }
                         continue;
                     }
                 }
@@ -309,7 +330,7 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
             // No specific flycheck was triggered, so let's trigger all of them.
             if !updated {
                 for flycheck in world.flycheck.iter() {
-                    flycheck.restart();
+                    flycheck.restart_workspace();
                 }
             }
             Ok(())
@@ -351,7 +372,7 @@ pub(crate) fn handle_run_flycheck(
     }
     // No specific flycheck was triggered, so let's trigger all of them.
     for flycheck in state.flycheck.iter() {
-        flycheck.restart();
+        flycheck.restart_workspace();
     }
     Ok(())
 }
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 2be2ba5c446..2a3633a48e9 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
@@ -54,7 +54,7 @@ pub(crate) fn handle_workspace_reload(state: &mut GlobalState, _: ()) -> anyhow:
     state.proc_macro_clients = Arc::from_iter([]);
     state.proc_macro_changed = false;
 
-    state.fetch_workspaces_queue.request_op("reload workspace request".to_string(), false);
+    state.fetch_workspaces_queue.request_op("reload workspace request".to_owned(), false);
     Ok(())
 }
 
@@ -62,7 +62,7 @@ pub(crate) fn handle_proc_macros_rebuild(state: &mut GlobalState, _: ()) -> anyh
     state.proc_macro_clients = Arc::from_iter([]);
     state.proc_macro_changed = false;
 
-    state.fetch_build_data_queue.request_op("rebuild proc macros request".to_string(), ());
+    state.fetch_build_data_queue.request_op("rebuild proc macros request".to_owned(), ());
     Ok(())
 }
 
@@ -562,7 +562,7 @@ pub(crate) fn handle_will_rename_files(
                 (Some(p1), Some(p2)) if p1 == p2 => {
                     if from_path.is_dir() {
                         // add '/' to end of url -- from `file://path/to/folder` to `file://path/to/folder/`
-                        let mut old_folder_name = from_path.file_stem()?.to_str()?.to_string();
+                        let mut old_folder_name = from_path.file_stem()?.to_str()?.to_owned();
                         old_folder_name.push('/');
                         let from_with_trailing_slash = from.join(&old_folder_name).ok()?;
 
@@ -570,7 +570,7 @@ pub(crate) fn handle_will_rename_files(
                         let new_file_name = to_path.file_name()?.to_str()?;
                         Some((
                             snap.url_to_file_id(&imitate_from_url).ok()?,
-                            new_file_name.to_string(),
+                            new_file_name.to_owned(),
                         ))
                     } else {
                         let old_name = from_path.file_stem()?.to_str()?;
@@ -578,7 +578,7 @@ pub(crate) fn handle_will_rename_files(
                         match (old_name, new_name) {
                             ("mod", _) => None,
                             (_, "mod") => None,
-                            _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_string())),
+                            _ => Some((snap.url_to_file_id(&from).ok()?, new_name.to_owned())),
                         }
                     }
                 }
@@ -799,13 +799,13 @@ pub(crate) fn handle_runnables(
         None => {
             if !snap.config.linked_or_discovered_projects().is_empty() {
                 res.push(lsp_ext::Runnable {
-                    label: "cargo check --workspace".to_string(),
+                    label: "cargo check --workspace".to_owned(),
                     location: None,
                     kind: lsp_ext::RunnableKind::Cargo,
                     args: lsp_ext::CargoRunnable {
                         workspace_root: None,
                         override_cargo: config.override_cargo,
-                        cargo_args: vec!["check".to_string(), "--workspace".to_string()],
+                        cargo_args: vec!["check".to_owned(), "--workspace".to_owned()],
                         cargo_extra_args: config.cargo_extra_args,
                         executable_args: Vec::new(),
                         expect_test: None,
@@ -879,7 +879,7 @@ pub(crate) fn handle_completion_resolve(
 
     if !all_edits_are_disjoint(&original_completion, &[]) {
         return Err(invalid_params_error(
-            "Received a completion with overlapping edits, this is not LSP-compliant".to_string(),
+            "Received a completion with overlapping edits, this is not LSP-compliant".to_owned(),
         )
         .into());
     }
@@ -1191,7 +1191,7 @@ pub(crate) fn handle_code_action_resolve(
     let _p = tracing::span!(tracing::Level::INFO, "handle_code_action_resolve").entered();
     let params = match code_action.data.take() {
         Some(it) => it,
-        None => return Err(invalid_params_error("code action without data".to_string()).into()),
+        None => return Err(invalid_params_error("code action without data".to_owned()).into()),
     };
 
     let file_id = from_proto::file_id(&snap, &params.code_action_params.text_document.uri)?;
@@ -1270,7 +1270,7 @@ fn parse_action_id(action_id: &str) -> anyhow::Result<(usize, SingleResolve), St
             };
             Ok((index, SingleResolve { assist_id: assist_id_string.to_string(), assist_kind }))
         }
-        _ => Err("Action id contains incorrect number of segments".to_string()),
+        _ => Err("Action id contains incorrect number of segments".to_owned()),
     }
 }
 
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 35c8fad3741..aa40728ce6c 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
@@ -1,6 +1,8 @@
 //! rust-analyzer extensions to the LSP.
 
-use std::{collections::HashMap, path::PathBuf};
+#![allow(clippy::disallowed_types)]
+
+use std::path::PathBuf;
 
 use ide_db::line_index::WideEncoding;
 use lsp_types::request::Request;
@@ -9,6 +11,7 @@ use lsp_types::{
     PartialResultParams, Position, Range, TextDocumentIdentifier, WorkDoneProgressParams,
 };
 use lsp_types::{PositionEncodingKind, Url};
+use rustc_hash::FxHashMap;
 use serde::{Deserialize, Serialize};
 
 use crate::line_index::PositionEncoding;
@@ -448,12 +451,16 @@ pub struct CodeActionData {
 #[serde(rename_all = "camelCase")]
 pub struct SnippetWorkspaceEdit {
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
+    pub changes: Option<FxHashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
     #[serde(skip_serializing_if = "Option::is_none")]
-    pub change_annotations:
-        Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
+    pub change_annotations: Option<
+        std::collections::HashMap<
+            lsp_types::ChangeAnnotationIdentifier,
+            lsp_types::ChangeAnnotation,
+        >,
+    >,
 }
 
 #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
@@ -696,3 +703,16 @@ pub struct CompletionImport {
 pub struct ClientCommandOptions {
     pub commands: Vec<String>,
 }
+
+pub enum UnindexedProject {}
+
+impl Notification for UnindexedProject {
+    type Params = UnindexedProjectParams;
+    const METHOD: &'static str = "rust-analyzer/unindexedProject";
+}
+
+#[derive(Deserialize, Serialize, Debug)]
+#[serde(rename_all = "camelCase")]
+pub struct UnindexedProjectParams {
+    pub text_documents: Vec<TextDocumentIdentifier>,
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
index 9923be382b7..f42985a9161 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/from_proto.rs
@@ -108,7 +108,7 @@ pub(crate) fn annotation(
     code_lens: lsp_types::CodeLens,
 ) -> anyhow::Result<Option<Annotation>> {
     let data =
-        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_string()))?;
+        code_lens.data.ok_or_else(|| invalid_params_error("code lens without data".to_owned()))?;
     let resolve = from_json::<lsp_ext::CodeLensResolveData>("CodeLensResolveData", &data)?;
 
     match resolve.kind {
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 d363ac69fdc..64f19f0b32d 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
@@ -245,7 +245,7 @@ fn completion_item(
 ) {
     let insert_replace_support = config.insert_replace_support().then_some(tdpp.position);
     let ref_match = item.ref_match();
-    let lookup = item.lookup().to_string();
+    let lookup = item.lookup().to_owned();
 
     let mut additional_text_edits = Vec::new();
 
@@ -367,7 +367,7 @@ pub(crate) fn signature_help(
             let params = call_info
                 .parameter_labels()
                 .map(|label| lsp_types::ParameterInformation {
-                    label: lsp_types::ParameterLabel::Simple(label.to_string()),
+                    label: lsp_types::ParameterLabel::Simple(label.to_owned()),
                     documentation: None,
                 })
                 .collect::<Vec<_>>();
@@ -1498,7 +1498,7 @@ pub(crate) mod command {
 
     pub(crate) fn run_single(runnable: &lsp_ext::Runnable, title: &str) -> lsp_types::Command {
         lsp_types::Command {
-            title: title.to_string(),
+            title: title.to_owned(),
             command: "rust-analyzer.runSingle".into(),
             arguments: Some(vec![to_value(runnable).unwrap()]),
         }
@@ -1608,7 +1608,7 @@ fn main() {
     }
 }"#;
 
-        let (analysis, file_id) = Analysis::from_single_file(text.to_string());
+        let (analysis, file_id) = Analysis::from_single_file(text.to_owned());
         let folds = analysis.folding_ranges(file_id).unwrap();
         assert_eq!(folds.len(), 4);
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
index fa5ea5b57db..10335cb1453 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/utils.rs
@@ -333,21 +333,20 @@ mod tests {
 
     #[test]
     fn empty_completion_disjoint_tests() {
-        let empty_completion =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
+        let empty_completion = CompletionItem::new_simple("label".to_owned(), "detail".to_owned());
 
         let disjoint_edit_1 = lsp_types::TextEdit::new(
             Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
         let disjoint_edit_2 = lsp_types::TextEdit::new(
             Range::new(Position::new(3, 3), Position::new(4, 4)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
 
         let joint_edit = lsp_types::TextEdit::new(
             Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
 
         assert!(
@@ -375,19 +374,19 @@ mod tests {
     fn completion_with_joint_edits_disjoint_tests() {
         let disjoint_edit = lsp_types::TextEdit::new(
             Range::new(Position::new(1, 1), Position::new(2, 2)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
         let disjoint_edit_2 = lsp_types::TextEdit::new(
             Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
         let joint_edit = lsp_types::TextEdit::new(
             Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
 
         let mut completion_with_joint_edits =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
+            CompletionItem::new_simple("label".to_owned(), "detail".to_owned());
         completion_with_joint_edits.additional_text_edits =
             Some(vec![disjoint_edit.clone(), joint_edit.clone()]);
         assert!(
@@ -405,7 +404,7 @@ mod tests {
 
         completion_with_joint_edits.text_edit =
             Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
-                new_text: "new_text".to_string(),
+                new_text: "new_text".to_owned(),
                 insert: disjoint_edit.range,
                 replace: disjoint_edit_2.range,
             }));
@@ -420,19 +419,19 @@ mod tests {
     fn completion_with_disjoint_edits_disjoint_tests() {
         let disjoint_edit = lsp_types::TextEdit::new(
             Range::new(Position::new(1, 1), Position::new(2, 2)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
         let disjoint_edit_2 = lsp_types::TextEdit::new(
             Range::new(Position::new(2, 2), Position::new(3, 3)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
         let joint_edit = lsp_types::TextEdit::new(
             Range::new(Position::new(1, 1), Position::new(5, 5)),
-            "new_text".to_string(),
+            "new_text".to_owned(),
         );
 
         let mut completion_with_disjoint_edits =
-            CompletionItem::new_simple("label".to_string(), "detail".to_string());
+            CompletionItem::new_simple("label".to_owned(), "detail".to_owned());
         completion_with_disjoint_edits.text_edit = Some(CompletionTextEdit::Edit(disjoint_edit));
         let completion_with_disjoint_edits = completion_with_disjoint_edits;
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index f3ead6d04f7..88660db7e93 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -1,5 +1,6 @@
 //! The main loop of `rust-analyzer` responsible for dispatching LSP
 //! requests/replies and notifications back to the client.
+use crate::lsp::ext;
 use std::{
     fmt,
     time::{Duration, Instant},
@@ -56,6 +57,7 @@ pub fn main_loop(config: Config, connection: Connection) -> anyhow::Result<()> {
 enum Event {
     Lsp(lsp_server::Message),
     Task(Task),
+    QueuedTask(QueuedTask),
     Vfs(vfs::loader::Message),
     Flycheck(flycheck::Message),
 }
@@ -67,13 +69,20 @@ impl fmt::Display for Event {
             Event::Task(_) => write!(f, "Event::Task"),
             Event::Vfs(_) => write!(f, "Event::Vfs"),
             Event::Flycheck(_) => write!(f, "Event::Flycheck"),
+            Event::QueuedTask(_) => write!(f, "Event::QueuedTask"),
         }
     }
 }
 
 #[derive(Debug)]
+pub(crate) enum QueuedTask {
+    CheckIfIndexed(lsp_types::Url),
+}
+
+#[derive(Debug)]
 pub(crate) enum Task {
     Response(lsp_server::Response),
+    ClientNotification(ext::UnindexedProjectParams),
     Retry(lsp_server::Request),
     Diagnostics(Vec<(FileId, Vec<lsp_types::Diagnostic>)>),
     PrimeCaches(PrimeCachesProgress),
@@ -115,6 +124,7 @@ impl fmt::Debug for Event {
         match self {
             Event::Lsp(it) => fmt::Debug::fmt(it, f),
             Event::Task(it) => fmt::Debug::fmt(it, f),
+            Event::QueuedTask(it) => fmt::Debug::fmt(it, f),
             Event::Vfs(it) => fmt::Debug::fmt(it, f),
             Event::Flycheck(it) => fmt::Debug::fmt(it, f),
         }
@@ -129,7 +139,7 @@ impl GlobalState {
             self.register_did_save_capability();
         }
 
-        self.fetch_workspaces_queue.request_op("startup".to_string(), false);
+        self.fetch_workspaces_queue.request_op("startup".to_owned(), false);
         if let Some((cause, force_crate_graph_reload)) =
             self.fetch_workspaces_queue.should_start_op()
         {
@@ -175,8 +185,8 @@ impl GlobalState {
         };
 
         let registration = lsp_types::Registration {
-            id: "textDocument/didSave".to_string(),
-            method: "textDocument/didSave".to_string(),
+            id: "textDocument/didSave".to_owned(),
+            method: "textDocument/didSave".to_owned(),
             register_options: Some(serde_json::to_value(save_registration_options).unwrap()),
         };
         self.send_request::<lsp_types::request::RegisterCapability>(
@@ -193,6 +203,9 @@ impl GlobalState {
             recv(self.task_pool.receiver) -> task =>
                 Some(Event::Task(task.unwrap())),
 
+            recv(self.deferred_task_queue.receiver) -> task =>
+                Some(Event::QueuedTask(task.unwrap())),
+
             recv(self.fmt_pool.receiver) -> task =>
                 Some(Event::Task(task.unwrap())),
 
@@ -211,7 +224,7 @@ impl GlobalState {
             .entered();
 
         let event_dbg_msg = format!("{event:?}");
-        tracing::debug!("{:?} handle_event({})", loop_start, event_dbg_msg);
+        tracing::debug!(?loop_start, ?event, "handle_event");
         if tracing::enabled!(tracing::Level::INFO) {
             let task_queue_len = self.task_pool.handle.len();
             if task_queue_len > 0 {
@@ -226,6 +239,16 @@ impl GlobalState {
                 lsp_server::Message::Notification(not) => self.on_notification(not)?,
                 lsp_server::Message::Response(resp) => self.complete_request(resp),
             },
+            Event::QueuedTask(task) => {
+                let _p =
+                    tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/queued_task")
+                        .entered();
+                self.handle_queued_task(task);
+                // Coalesce multiple task events into one loop turn
+                while let Ok(task) = self.deferred_task_queue.receiver.try_recv() {
+                    self.handle_queued_task(task);
+                }
+            }
             Event::Task(task) => {
                 let _p = tracing::span!(tracing::Level::INFO, "GlobalState::handle_event/task")
                     .entered();
@@ -273,7 +296,7 @@ impl GlobalState {
                             self.prime_caches_queue.op_completed(());
                             if cancelled {
                                 self.prime_caches_queue
-                                    .request_op("restart after cancellation".to_string(), ());
+                                    .request_op("restart after cancellation".to_owned(), ());
                             }
                         }
                     };
@@ -314,10 +337,10 @@ impl GlobalState {
             if became_quiescent {
                 if self.config.check_on_save() {
                     // Project has loaded properly, kick off initial flycheck
-                    self.flycheck.iter().for_each(FlycheckHandle::restart);
+                    self.flycheck.iter().for_each(FlycheckHandle::restart_workspace);
                 }
                 if self.config.prefill_caches() {
-                    self.prime_caches_queue.request_op("became quiescent".to_string(), ());
+                    self.prime_caches_queue.request_op("became quiescent".to_owned(), ());
                 }
             }
 
@@ -367,7 +390,7 @@ impl GlobalState {
                 // See https://github.com/rust-lang/rust-analyzer/issues/13130
                 let patch_empty = |message: &mut String| {
                     if message.is_empty() {
-                        *message = " ".to_string();
+                        *message = " ".to_owned();
                     }
                 };
 
@@ -498,6 +521,9 @@ impl GlobalState {
     fn handle_task(&mut self, prime_caches_progress: &mut Vec<PrimeCachesProgress>, task: Task) {
         match task {
             Task::Response(response) => self.respond(response),
+            Task::ClientNotification(params) => {
+                self.send_notification::<lsp_ext::UnindexedProject>(params)
+            }
             // Only retry requests that haven't been cancelled. Otherwise we do unnecessary work.
             Task::Retry(req) if !self.is_completed(&req) => self.on_request(req),
             Task::Retry(_) => (),
@@ -531,12 +557,12 @@ impl GlobalState {
                         }
 
                         let old = Arc::clone(&self.workspaces);
-                        self.switch_workspaces("fetched workspace".to_string());
+                        self.switch_workspaces("fetched workspace".to_owned());
                         let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
 
                         if self.config.run_build_scripts() && workspaces_updated {
                             self.fetch_build_data_queue
-                                .request_op("workspace updated".to_string(), ());
+                                .request_op("workspace updated".to_owned(), ());
                         }
 
                         (Progress::End, None)
@@ -555,7 +581,7 @@ impl GlobalState {
                             tracing::error!("FetchBuildDataError:\n{e}");
                         }
 
-                        self.switch_workspaces("fetched build data".to_string());
+                        self.switch_workspaces("fetched build data".to_owned());
                         self.send_hint_refresh_query = true;
 
                         (Some(Progress::End), None)
@@ -638,6 +664,31 @@ impl GlobalState {
         }
     }
 
+    fn handle_queued_task(&mut self, task: QueuedTask) {
+        match task {
+            QueuedTask::CheckIfIndexed(uri) => {
+                let snap = self.snapshot();
+
+                self.task_pool.handle.spawn_with_sender(ThreadIntent::Worker, move |sender| {
+                    let _p = tracing::span!(tracing::Level::INFO, "GlobalState::check_if_indexed")
+                        .entered();
+                    tracing::debug!(?uri, "handling uri");
+                    let id = from_proto::file_id(&snap, &uri).expect("unable to get FileId");
+                    if let Ok(crates) = &snap.analysis.crates_for(id) {
+                        if crates.is_empty() {
+                            let params = ext::UnindexedProjectParams {
+                                text_documents: vec![lsp_types::TextDocumentIdentifier { uri }],
+                            };
+                            sender.send(Task::ClientNotification(params)).unwrap();
+                        } else {
+                            tracing::debug!(?uri, "is indexed");
+                        }
+                    }
+                });
+            }
+        }
+    }
+
     fn handle_flycheck_msg(&mut self, message: flycheck::Message) {
         match message {
             flycheck::Message::AddDiagnostic { id, workspace_root, diagnostic } => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 65c00cc08d1..7bd2877b00c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -83,7 +83,7 @@ impl GlobalState {
         }
         if self.config.linked_or_discovered_projects() != old_config.linked_or_discovered_projects()
         {
-            self.fetch_workspaces_queue.request_op("linked projects changed".to_string(), false)
+            self.fetch_workspaces_queue.request_op("linked projects changed".to_owned(), false)
         } else if self.config.flycheck() != old_config.flycheck() {
             self.reload_flycheck();
         }
@@ -440,8 +440,8 @@ impl GlobalState {
                     .collect(),
             };
             let registration = lsp_types::Registration {
-                id: "workspace/didChangeWatchedFiles".to_string(),
-                method: "workspace/didChangeWatchedFiles".to_string(),
+                id: "workspace/didChangeWatchedFiles".to_owned(),
+                method: "workspace/didChangeWatchedFiles".to_owned(),
                 register_options: Some(serde_json::to_value(registration_options).unwrap()),
             };
             self.send_request::<lsp_types::request::RegisterCapability>(
@@ -503,7 +503,7 @@ impl GlobalState {
             let mut crate_graph_file_dependencies = FxHashSet::default();
 
             let mut load = |path: &AbsPath| {
-                let _p = tracing::span!(tracing::Level::INFO, "switch_workspaces::load").entered();
+                let _p = tracing::span!(tracing::Level::DEBUG, "switch_workspaces::load").entered();
                 let vfs_path = vfs::VfsPath::from(path.to_path_buf());
                 crate_graph_file_dependencies.insert(vfs_path.clone());
                 match vfs.file_id(&vfs_path) {
@@ -528,10 +528,16 @@ impl GlobalState {
             (crate_graph, proc_macros, crate_graph_file_dependencies)
         };
 
+        let mut change = Change::new();
         if self.config.expand_proc_macros() {
+            change.set_proc_macros(
+                crate_graph
+                    .iter()
+                    .map(|id| (id, Err("Proc-macros have not been built yet".to_owned())))
+                    .collect(),
+            );
             self.fetch_proc_macros_queue.request_op(cause, proc_macro_paths);
         }
-        let mut change = Change::new();
         change.set_crate_graph(crate_graph);
         self.analysis_host.apply_change(change);
         self.crate_graph_file_dependencies = crate_graph_file_dependencies;
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
index a5a10e86914..f7de5fb2ff1 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
@@ -4,6 +4,8 @@
 use crossbeam_channel::Sender;
 use stdx::thread::{Pool, ThreadIntent};
 
+use crate::main_loop::QueuedTask;
+
 pub(crate) struct TaskPool<T> {
     sender: Sender<T>,
     pool: Pool,
@@ -40,3 +42,12 @@ impl<T> TaskPool<T> {
         self.pool.len()
     }
 }
+
+/// `TaskQueue`, like its name suggests, queues tasks.
+///
+/// This should only be used used if a task must run after [`GlobalState::process_changes`]
+/// has been called.
+pub(crate) struct TaskQueue {
+    pub(crate) sender: crossbeam_channel::Sender<QueuedTask>,
+    pub(crate) receiver: crossbeam_channel::Receiver<QueuedTask>,
+}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
index c99b551df85..90649873297 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/tracing/hprof.rs
@@ -179,6 +179,7 @@ impl Node {
         self.go(0, filter)
     }
 
+    #[allow(clippy::print_stderr)]
     fn go(&self, level: usize, filter: &WriteFilter) {
         if self.duration > filter.longer_than && level < filter.depth {
             let duration = ms(self.duration);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
index 19890110d53..79ae0c30cfc 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/main.rs
@@ -9,6 +9,7 @@
 //! be sure without a real client anyway.
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(clippy::disallowed_types)]
 
 #[cfg(not(feature = "in-rust-tree"))]
 mod sourcegen;
@@ -29,7 +30,7 @@ use lsp_types::{
     PartialResultParams, Position, Range, RenameFilesParams, TextDocumentItem,
     TextDocumentPositionParams, WorkDoneProgressParams,
 };
-use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams};
+use rust_analyzer::lsp::ext::{OnEnter, Runnables, RunnablesParams, UnindexedProject};
 use serde_json::json;
 use stdx::format_to_acc;
 use test_utils::skip_slow_tests;
@@ -587,6 +588,66 @@ fn main() {{}}
 }
 
 #[test]
+fn test_opening_a_file_outside_of_indexed_workspace() {
+    if skip_slow_tests() {
+        return;
+    }
+
+    let tmp_dir = TestDir::new();
+    let path = tmp_dir.path();
+
+    let project = json!({
+        "roots": [path],
+        "crates": [ {
+            "root_module": path.join("src/crate_one/lib.rs"),
+            "deps": [],
+            "edition": "2015",
+            "cfg": [ "cfg_atom_1", "feature=\"cfg_1\""],
+        } ]
+    });
+
+    let code = format!(
+        r#"
+//- /rust-project.json
+{project}
+
+//- /src/crate_one/lib.rs
+mod bar;
+
+fn main() {{}}
+"#,
+    );
+
+    let server = Project::with_fixture(&code)
+        .tmp_dir(tmp_dir)
+        .with_config(serde_json::json!({
+            "notifications": {
+                "unindexedProject": true
+            },
+        }))
+        .server()
+        .wait_until_workspace_is_loaded();
+
+    let uri = server.doc_id("src/crate_two/lib.rs").uri;
+    server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
+        text_document: TextDocumentItem {
+            uri: uri.clone(),
+            language_id: "rust".to_owned(),
+            version: 0,
+            text: "/// Docs\nfn foo() {}".to_owned(),
+        },
+    });
+    let expected = json!({
+        "textDocuments": [
+            {
+                "uri": uri
+            }
+        ]
+    });
+    server.expect_notification::<UnindexedProject>(expected);
+}
+
+#[test]
 fn diagnostics_dont_block_typing() {
     if skip_slow_tests() {
         return;
@@ -621,9 +682,9 @@ fn main() {{}}
         server.notification::<DidOpenTextDocument>(DidOpenTextDocumentParams {
             text_document: TextDocumentItem {
                 uri: server.doc_id(&format!("src/m{i}.rs")).uri,
-                language_id: "rust".to_string(),
+                language_id: "rust".to_owned(),
                 version: 0,
-                text: "/// Docs\nfn foo() {}".to_string(),
+                text: "/// Docs\nfn foo() {}".to_owned(),
             },
         });
     }
@@ -1017,15 +1078,15 @@ use crate::old_folder::nested::foo as bar;
     server.request::<WillRenameFiles>(
         RenameFilesParams {
             files: vec![FileRename {
-                old_uri: base_path.join("src/old_file.rs").to_str().unwrap().to_string(),
-                new_uri: base_path.join("src/new_file.rs").to_str().unwrap().to_string(),
+                old_uri: base_path.join("src/old_file.rs").to_str().unwrap().to_owned(),
+                new_uri: base_path.join("src/new_file.rs").to_str().unwrap().to_owned(),
             }],
         },
         json!({
           "documentChanges": [
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
@@ -1052,8 +1113,8 @@ use crate::old_folder::nested::foo as bar;
     server.request::<WillRenameFiles>(
         RenameFilesParams {
             files: vec![FileRename {
-                old_uri: base_path.join("src/from_mod/mod.rs").to_str().unwrap().to_string(),
-                new_uri: base_path.join("src/from_mod/foo.rs").to_str().unwrap().to_string(),
+                old_uri: base_path.join("src/from_mod/mod.rs").to_str().unwrap().to_owned(),
+                new_uri: base_path.join("src/from_mod/foo.rs").to_str().unwrap().to_owned(),
             }],
         },
         json!(null),
@@ -1063,8 +1124,8 @@ use crate::old_folder::nested::foo as bar;
     server.request::<WillRenameFiles>(
         RenameFilesParams {
             files: vec![FileRename {
-                old_uri: base_path.join("src/to_mod/foo.rs").to_str().unwrap().to_string(),
-                new_uri: base_path.join("src/to_mod/mod.rs").to_str().unwrap().to_string(),
+                old_uri: base_path.join("src/to_mod/foo.rs").to_str().unwrap().to_owned(),
+                new_uri: base_path.join("src/to_mod/mod.rs").to_str().unwrap().to_owned(),
             }],
         },
         json!(null),
@@ -1074,15 +1135,15 @@ use crate::old_folder::nested::foo as bar;
     server.request::<WillRenameFiles>(
         RenameFilesParams {
             files: vec![FileRename {
-                old_uri: base_path.join("src/old_folder").to_str().unwrap().to_string(),
-                new_uri: base_path.join("src/new_folder").to_str().unwrap().to_string(),
+                old_uri: base_path.join("src/old_folder").to_str().unwrap().to_owned(),
+                new_uri: base_path.join("src/new_folder").to_str().unwrap().to_owned(),
             }],
         },
         json!({
           "documentChanges": [
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("lib.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
@@ -1103,7 +1164,7 @@ use crate::old_folder::nested::foo as bar;
             },
             {
               "textDocument": {
-                "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_string().replace("C:\\", "/c:/").replace('\\', "/")),
+                "uri": format!("file://{}", tmp_dir_path.join("src").join("old_folder").join("nested.rs").to_str().unwrap().to_owned().replace("C:\\", "/c:/").replace('\\', "/")),
                 "version": null
               },
               "edits": [
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
index d699374f9cd..d02cb45b8e3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/support.rs
@@ -9,7 +9,7 @@ use std::{
 use crossbeam_channel::{after, select, Receiver};
 use lsp_server::{Connection, Message, Notification, Request};
 use lsp_types::{notification::Exit, request::Shutdown, TextDocumentIdentifier, Url};
-use rust_analyzer::{config::Config, lsp, main_loop, tracing};
+use rust_analyzer::{config::Config, lsp, main_loop};
 use serde::Serialize;
 use serde_json::{json, to_string_pretty, Value};
 use test_utils::FixtureWithProjectMeta;
@@ -91,11 +91,11 @@ impl Project<'_> {
 
         static INIT: Once = Once::new();
         INIT.call_once(|| {
-            let _ = tracing::Config {
+            let _ = rust_analyzer::tracing::Config {
                 writer: TestWriter::default(),
                 // Deliberately enable all `error` logs if the user has not set RA_LOG, as there is usually
                 // useful information in there for debugging.
-                filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_string()),
+                filter: std::env::var("RA_LOG").ok().unwrap_or_else(|| "error".to_owned()),
                 chalk_filter: std::env::var("CHALK_DEBUG").ok(),
                 profile_filter: std::env::var("RA_PROFILE").ok(),
             };
@@ -193,7 +193,7 @@ impl Server {
         let (connection, client) = Connection::memory();
 
         let _thread = stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
-            .name("test server".to_string())
+            .name("test server".to_owned())
             .spawn(move || main_loop(config, connection).unwrap())
             .expect("failed to spawn a thread");
 
@@ -210,10 +210,44 @@ impl Server {
         N: lsp_types::notification::Notification,
         N::Params: Serialize,
     {
-        let r = Notification::new(N::METHOD.to_string(), params);
+        let r = Notification::new(N::METHOD.to_owned(), params);
         self.send_notification(r)
     }
 
+    pub(crate) fn expect_notification<N>(&self, expected: Value)
+    where
+        N: lsp_types::notification::Notification,
+        N::Params: Serialize,
+    {
+        while let Some(Message::Notification(actual)) =
+            recv_timeout(&self.client.receiver).unwrap_or_else(|_| panic!("timed out"))
+        {
+            if actual.method == N::METHOD {
+                let actual = actual
+                    .clone()
+                    .extract::<Value>(N::METHOD)
+                    .expect("was not able to extract notification");
+
+                tracing::debug!(?actual, "got notification");
+                if let Some((expected_part, actual_part)) = find_mismatch(&expected, &actual) {
+                    panic!(
+                            "JSON mismatch\nExpected:\n{}\nWas:\n{}\nExpected part:\n{}\nActual part:\n{}\n",
+                            to_string_pretty(&expected).unwrap(),
+                            to_string_pretty(&actual).unwrap(),
+                            to_string_pretty(expected_part).unwrap(),
+                            to_string_pretty(actual_part).unwrap(),
+                        );
+                } else {
+                    tracing::debug!("sucessfully matched notification");
+                    return;
+                }
+            } else {
+                continue;
+            }
+        }
+        panic!("never got expected notification");
+    }
+
     #[track_caller]
     pub(crate) fn request<R>(&self, params: R::Params, expected_resp: Value)
     where
@@ -240,7 +274,7 @@ impl Server {
         let id = self.req_id.get();
         self.req_id.set(id.wrapping_add(1));
 
-        let r = Request::new(id.into(), R::METHOD.to_string(), params);
+        let r = Request::new(id.into(), R::METHOD.to_owned(), params);
         self.send_request_(r)
     }
     fn send_request_(&self, r: Request) -> Value {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
index d3146ab7671..3e38fc3ebcd 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -1,3 +1,4 @@
+#![allow(clippy::disallowed_types, clippy::print_stderr)]
 use std::{
     collections::HashSet,
     path::{Path, PathBuf},
@@ -78,8 +79,6 @@ fn files_are_tidy() {
         match extension {
             "rs" => {
                 let text = sh.read_file(&path).unwrap();
-                check_todo(&path, &text);
-                check_dbg(&path, &text);
                 check_test_attrs(&path, &text);
                 check_trailing_ws(&path, &text);
                 tidy_docs.visit(&path, &text);
@@ -205,74 +204,6 @@ Zlib OR Apache-2.0 OR MIT
     assert_eq!(licenses, expected);
 }
 
-fn check_todo(path: &Path, text: &str) {
-    let need_todo = &[
-        // This file itself obviously needs to use todo (<- like this!).
-        "tests/tidy.rs",
-        // Some of our assists generate `todo!()`.
-        "handlers/add_turbo_fish.rs",
-        "handlers/generate_function.rs",
-        "handlers/add_missing_match_arms.rs",
-        "handlers/replace_derive_with_manual_impl.rs",
-        // To support generating `todo!()` in assists, we have `expr_todo()` in
-        // `ast::make`.
-        "ast/make.rs",
-        // The documentation in string literals may contain anything for its own purposes
-        "ide-db/src/generated/lints.rs",
-        "ide-assists/src/utils/gen_trait_fn_body.rs",
-        "ide-assists/src/tests/generated.rs",
-        // The tests for missing fields
-        "ide-diagnostics/src/handlers/missing_fields.rs",
-    ];
-    if need_todo.iter().any(|p| path.ends_with(p)) {
-        return;
-    }
-    if text.contains("TODO") || text.contains("TOOD") || text.contains("todo!") {
-        // Generated by an assist
-        if text.contains("${0:todo!()}") {
-            return;
-        }
-
-        panic!(
-            "\nTODO markers or todo! macros should not be committed to the master branch,\n\
-             use FIXME instead\n\
-             {}\n",
-            path.display(),
-        )
-    }
-}
-
-fn check_dbg(path: &Path, text: &str) {
-    let need_dbg = &[
-        // This file itself obviously needs to use dbg.
-        "slow-tests/tidy.rs",
-        // Assists to remove `dbg!()`
-        "handlers/remove_dbg.rs",
-        // We have .dbg postfix
-        "ide-completion/src/completions/postfix.rs",
-        "ide-completion/src/completions/keyword.rs",
-        "ide-completion/src/tests/expression.rs",
-        "ide-completion/src/tests/proc_macros.rs",
-        // The documentation in string literals may contain anything for its own purposes
-        "ide-completion/src/lib.rs",
-        "ide-db/src/generated/lints.rs",
-        // test for doc test for remove_dbg
-        "src/tests/generated.rs",
-        // `expect!` string can contain `dbg!` (due to .dbg postfix)
-        "ide-completion/src/tests/special.rs",
-    ];
-    if need_dbg.iter().any(|p| path.ends_with(p)) {
-        return;
-    }
-    if text.contains("dbg!") {
-        panic!(
-            "\ndbg! macros should not be committed to the master branch,\n\
-             {}\n",
-            path.display(),
-        )
-    }
-}
-
 fn check_test_attrs(path: &Path, text: &str) {
     let ignore_rule =
         "https://github.com/rust-lang/rust-analyzer/blob/master/docs/dev/style.md#ignore";
@@ -442,7 +373,7 @@ fn find_marks(set: &mut HashSet<String>, text: &str, mark: &str) {
                 text = stripped_text.trim_start();
                 if let Some(idx2) = text.find(|c: char| !(c.is_alphanumeric() || c == '_')) {
                     let mark_text = &text[..idx2];
-                    set.insert(mark_text.to_string());
+                    set.insert(mark_text.to_owned());
                     text = &text[idx2..];
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/salsa/Cargo.toml b/src/tools/rust-analyzer/crates/salsa/Cargo.toml
new file mode 100644
index 00000000000..4ccbc3de846
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/Cargo.toml
@@ -0,0 +1,35 @@
+[package]
+name = "salsa"
+version = "0.0.0"
+authors = ["Salsa developers"]
+edition = "2021"
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/salsa-rs/salsa"
+description = "A generic framework for on-demand, incrementalized computation (experimental)"
+
+rust-version.workspace = true
+
+[lib]
+name = "salsa"
+
+[dependencies]
+indexmap = "2.1.0"
+lock_api = "0.4"
+tracing = "0.1"
+parking_lot = "0.12.1"
+rustc-hash = "1.0"
+smallvec = "1.0.0"
+oorandom = "11"
+triomphe = "0.1.11"
+
+salsa-macros = { version = "0.0.0", path = "salsa-macros" }
+
+[dev-dependencies]
+linked-hash-map = "0.5.6"
+rand = "0.8.5"
+test-log = "0.2.14"
+expect-test = "1.4.0"
+dissimilar = "1.0.7"
+
+[lints]
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/salsa/FAQ.md b/src/tools/rust-analyzer/crates/salsa/FAQ.md
new file mode 100644
index 00000000000..9c9f6f92da9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/FAQ.md
@@ -0,0 +1,34 @@
+# Frequently asked questions
+
+## Why is it called salsa?
+
+I like salsa! Don't you?! Well, ok, there's a bit more to it. The
+underlying algorithm for figuring out which bits of code need to be
+re-executed after any given change is based on the algorithm used in
+rustc. Michael Woerister and I first described the rustc algorithm in
+terms of two colors, red and green, and hence we called it the
+"red-green algorithm". This made me think of the New Mexico State
+Question --- ["Red or green?"][nm] --- which refers to chile
+(salsa). Although this version no longer uses colors (we borrowed
+revision counters from Glimmer, instead), I still like the name.
+
+[nm]: https://www.sos.state.nm.us/about-new-mexico/state-question/
+
+## What is the relationship between salsa and an Entity-Component System (ECS)?
+
+You may have noticed that Salsa "feels" a lot like an ECS in some
+ways. That's true -- Salsa's queries are a bit like *components* (and
+the keys to the queries are a bit like *entities*). But there is one
+big difference: **ECS is -- at its heart -- a mutable system**. You
+can get or set a component of some entity whenever you like. In
+contrast, salsa's queries **define "derived values" via pure
+computations**.
+
+Partly as a consequence, ECS doesn't handle incremental updates for
+you. When you update some component of some entity, you have to ensure
+that other entities' components are updated appropriately.
+
+Finally, ECS offers interesting metadata and "aspect-like" facilities,
+such as iterating over all entities that share certain components.
+Salsa has no analogue to that.
+
diff --git a/src/tools/rust-analyzer/crates/salsa/LICENSE-APACHE b/src/tools/rust-analyzer/crates/salsa/LICENSE-APACHE
new file mode 100644
index 00000000000..16fe87b06e8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/LICENSE-APACHE
@@ -0,0 +1,201 @@
+                              Apache License
+                        Version 2.0, January 2004
+                     http://www.apache.org/licenses/
+
+TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+1. Definitions.
+
+   "License" shall mean the terms and conditions for use, reproduction,
+   and distribution as defined by Sections 1 through 9 of this document.
+
+   "Licensor" shall mean the copyright owner or entity authorized by
+   the copyright owner that is granting the License.
+
+   "Legal Entity" shall mean the union of the acting entity and all
+   other entities that control, are controlled by, or are under common
+   control with that entity. For the purposes of this definition,
+   "control" means (i) the power, direct or indirect, to cause the
+   direction or management of such entity, whether by contract or
+   otherwise, or (ii) ownership of fifty percent (50%) or more of the
+   outstanding shares, or (iii) beneficial ownership of such entity.
+
+   "You" (or "Your") shall mean an individual or Legal Entity
+   exercising permissions granted by this License.
+
+   "Source" form shall mean the preferred form for making modifications,
+   including but not limited to software source code, documentation
+   source, and configuration files.
+
+   "Object" form shall mean any form resulting from mechanical
+   transformation or translation of a Source form, including but
+   not limited to compiled object code, generated documentation,
+   and conversions to other media types.
+
+   "Work" shall mean the work of authorship, whether in Source or
+   Object form, made available under the License, as indicated by a
+   copyright notice that is included in or attached to the work
+   (an example is provided in the Appendix below).
+
+   "Derivative Works" shall mean any work, whether in Source or Object
+   form, that is based on (or derived from) the Work and for which the
+   editorial revisions, annotations, elaborations, or other modifications
+   represent, as a whole, an original work of authorship. For the purposes
+   of this License, Derivative Works shall not include works that remain
+   separable from, or merely link (or bind by name) to the interfaces of,
+   the Work and Derivative Works thereof.
+
+   "Contribution" shall mean any work of authorship, including
+   the original version of the Work and any modifications or additions
+   to that Work or Derivative Works thereof, that is intentionally
+   submitted to Licensor for inclusion in the Work by the copyright owner
+   or by an individual or Legal Entity authorized to submit on behalf of
+   the copyright owner. For the purposes of this definition, "submitted"
+   means any form of electronic, verbal, or written communication sent
+   to the Licensor or its representatives, including but not limited to
+   communication on electronic mailing lists, source code control systems,
+   and issue tracking systems that are managed by, or on behalf of, the
+   Licensor for the purpose of discussing and improving the Work, but
+   excluding communication that is conspicuously marked or otherwise
+   designated in writing by the copyright owner as "Not a Contribution."
+
+   "Contributor" shall mean Licensor and any individual or Legal Entity
+   on behalf of whom a Contribution has been received by Licensor and
+   subsequently incorporated within the Work.
+
+2. Grant of Copyright License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   copyright license to reproduce, prepare Derivative Works of,
+   publicly display, publicly perform, sublicense, and distribute the
+   Work and such Derivative Works in Source or Object form.
+
+3. Grant of Patent License. Subject to the terms and conditions of
+   this License, each Contributor hereby grants to You a perpetual,
+   worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+   (except as stated in this section) patent license to make, have made,
+   use, offer to sell, sell, import, and otherwise transfer the Work,
+   where such license applies only to those patent claims licensable
+   by such Contributor that are necessarily infringed by their
+   Contribution(s) alone or by combination of their Contribution(s)
+   with the Work to which such Contribution(s) was submitted. If You
+   institute patent litigation against any entity (including a
+   cross-claim or counterclaim in a lawsuit) alleging that the Work
+   or a Contribution incorporated within the Work constitutes direct
+   or contributory patent infringement, then any patent licenses
+   granted to You under this License for that Work shall terminate
+   as of the date such litigation is filed.
+
+4. Redistribution. You may reproduce and distribute copies of the
+   Work or Derivative Works thereof in any medium, with or without
+   modifications, and in Source or Object form, provided that You
+   meet the following conditions:
+
+   (a) You must give any other recipients of the Work or
+       Derivative Works a copy of this License; and
+
+   (b) You must cause any modified files to carry prominent notices
+       stating that You changed the files; and
+
+   (c) You must retain, in the Source form of any Derivative Works
+       that You distribute, all copyright, patent, trademark, and
+       attribution notices from the Source form of the Work,
+       excluding those notices that do not pertain to any part of
+       the Derivative Works; and
+
+   (d) If the Work includes a "NOTICE" text file as part of its
+       distribution, then any Derivative Works that You distribute must
+       include a readable copy of the attribution notices contained
+       within such NOTICE file, excluding those notices that do not
+       pertain to any part of the Derivative Works, in at least one
+       of the following places: within a NOTICE text file distributed
+       as part of the Derivative Works; within the Source form or
+       documentation, if provided along with the Derivative Works; or,
+       within a display generated by the Derivative Works, if and
+       wherever such third-party notices normally appear. The contents
+       of the NOTICE file are for informational purposes only and
+       do not modify the License. You may add Your own attribution
+       notices within Derivative Works that You distribute, alongside
+       or as an addendum to the NOTICE text from the Work, provided
+       that such additional attribution notices cannot be construed
+       as modifying the License.
+
+   You may add Your own copyright statement to Your modifications and
+   may provide additional or different license terms and conditions
+   for use, reproduction, or distribution of Your modifications, or
+   for any such Derivative Works as a whole, provided Your use,
+   reproduction, and distribution of the Work otherwise complies with
+   the conditions stated in this License.
+
+5. Submission of Contributions. Unless You explicitly state otherwise,
+   any Contribution intentionally submitted for inclusion in the Work
+   by You to the Licensor shall be under the terms and conditions of
+   this License, without any additional terms or conditions.
+   Notwithstanding the above, nothing herein shall supersede or modify
+   the terms of any separate license agreement you may have executed
+   with Licensor regarding such Contributions.
+
+6. Trademarks. This License does not grant permission to use the trade
+   names, trademarks, service marks, or product names of the Licensor,
+   except as required for reasonable and customary use in describing the
+   origin of the Work and reproducing the content of the NOTICE file.
+
+7. Disclaimer of Warranty. Unless required by applicable law or
+   agreed to in writing, Licensor provides the Work (and each
+   Contributor provides its Contributions) on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+   implied, including, without limitation, any warranties or conditions
+   of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+   PARTICULAR PURPOSE. You are solely responsible for determining the
+   appropriateness of using or redistributing the Work and assume any
+   risks associated with Your exercise of permissions under this License.
+
+8. Limitation of Liability. In no event and under no legal theory,
+   whether in tort (including negligence), contract, or otherwise,
+   unless required by applicable law (such as deliberate and grossly
+   negligent acts) or agreed to in writing, shall any Contributor be
+   liable to You for damages, including any direct, indirect, special,
+   incidental, or consequential damages of any character arising as a
+   result of this License or out of the use or inability to use the
+   Work (including but not limited to damages for loss of goodwill,
+   work stoppage, computer failure or malfunction, or any and all
+   other commercial damages or losses), even if such Contributor
+   has been advised of the possibility of such damages.
+
+9. Accepting Warranty or Additional Liability. While redistributing
+   the Work or Derivative Works thereof, You may choose to offer,
+   and charge a fee for, acceptance of support, warranty, indemnity,
+   or other liability obligations and/or rights consistent with this
+   License. However, in accepting such obligations, You may act only
+   on Your own behalf and on Your sole responsibility, not on behalf
+   of any other Contributor, and only if You agree to indemnify,
+   defend, and hold each Contributor harmless for any liability
+   incurred by, or claims asserted against, such Contributor by reason
+   of your accepting any such warranty or additional liability.
+
+END OF TERMS AND CONDITIONS
+
+APPENDIX: How to apply the Apache License to your work.
+
+   To apply the Apache License to your work, attach the following
+   boilerplate notice, with the fields enclosed by brackets "[]"
+   replaced with your own identifying information. (Don't include
+   the brackets!)  The text should be enclosed in the appropriate
+   comment syntax for the file format. We also recommend that a
+   file or class name and description of purpose be included on the
+   same "printed page" as the copyright notice for easier
+   identification within third-party archives.
+
+Copyright [yyyy] [name of copyright owner]
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
diff --git a/src/tools/rust-analyzer/crates/salsa/LICENSE-MIT b/src/tools/rust-analyzer/crates/salsa/LICENSE-MIT
new file mode 100644
index 00000000000..31aa79387f2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/LICENSE-MIT
@@ -0,0 +1,23 @@
+Permission is hereby granted, free of charge, to any
+person obtaining a copy of this software and associated
+documentation files (the "Software"), to deal in the
+Software without restriction, including without
+limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice
+shall be included in all copies or substantial portions
+of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
+ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
+TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
+PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
+SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
diff --git a/src/tools/rust-analyzer/crates/salsa/README.md b/src/tools/rust-analyzer/crates/salsa/README.md
new file mode 100644
index 00000000000..4a8d9f8c731
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/README.md
@@ -0,0 +1,42 @@
+# salsa
+
+*A generic framework for on-demand, incrementalized computation.*
+
+## Obligatory warning
+
+This is a fork of https://github.com/salsa-rs/salsa/ adjusted to rust-analyzer's needs.
+
+## Credits
+
+This system is heavily inspired by [adapton](http://adapton.org/), [glimmer](https://github.com/glimmerjs/glimmer-vm), and rustc's query
+system. So credit goes to Eduard-Mihai Burtescu, Matthew Hammer,
+Yehuda Katz, and Michael Woerister.
+
+## Key idea
+
+The key idea of `salsa` is that you define your program as a set of
+**queries**. Every query is used like function `K -> V` that maps from
+some key of type `K` to a value of type `V`. Queries come in two basic
+varieties:
+
+- **Inputs**: the base inputs to your system. You can change these
+  whenever you like.
+- **Functions**: pure functions (no side effects) that transform your
+  inputs into other values. The results of queries is memoized to
+  avoid recomputing them a lot. When you make changes to the inputs,
+  we'll figure out (fairly intelligently) when we can re-use these
+  memoized values and when we have to recompute them.
+
+## Want to learn more?
+
+To learn more about Salsa, try one of the following:
+
+- read the [heavily commented `hello_world` example](https://github.com/salsa-rs/salsa/blob/master/examples/hello_world/main.rs);
+- check out the [Salsa book](https://salsa-rs.github.io/salsa);
+- watch one of our [videos](https://salsa-rs.github.io/salsa/videos.html).
+
+## Getting in touch
+
+The bulk of the discussion happens in the [issues](https://github.com/salsa-rs/salsa/issues)
+and [pull requests](https://github.com/salsa-rs/salsa/pulls),
+but we have a [zulip chat](https://salsa.zulipchat.com/) as well.
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/Cargo.toml b/src/tools/rust-analyzer/crates/salsa/salsa-macros/Cargo.toml
new file mode 100644
index 00000000000..791d2f6e9f5
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/Cargo.toml
@@ -0,0 +1,23 @@
+[package]
+name = "salsa-macros"
+version = "0.0.0"
+authors = ["Salsa developers"]
+edition = "2021"
+license = "Apache-2.0 OR MIT"
+repository = "https://github.com/salsa-rs/salsa"
+description = "Procedural macros for the salsa crate"
+
+rust-version.workspace = true
+
+[lib]
+proc-macro = true
+name = "salsa_macros"
+
+[dependencies]
+heck = "0.4"
+proc-macro2 = "1.0"
+quote = "1.0"
+syn = { version = "2.0", features = ["full", "extra-traits"] }
+
+[lints]
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-APACHE b/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-APACHE
new file mode 100644
index 00000000000..0bf2cad6488
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-APACHE
@@ -0,0 +1 @@
+../LICENSE-APACHE
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-MIT b/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-MIT
new file mode 100644
index 00000000000..d99cce5f720
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/LICENSE-MIT
@@ -0,0 +1 @@
+../LICENSE-MIT
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/README.md b/src/tools/rust-analyzer/crates/salsa/salsa-macros/README.md
new file mode 100644
index 00000000000..94389aee61a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/README.md
@@ -0,0 +1 @@
+../README.md
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
new file mode 100644
index 00000000000..0ec75bb043d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/database_storage.rs
@@ -0,0 +1,250 @@
+//!
+use heck::ToSnakeCase;
+use proc_macro::TokenStream;
+use syn::parse::{Parse, ParseStream};
+use syn::punctuated::Punctuated;
+use syn::{Ident, ItemStruct, Path, Token};
+
+type PunctuatedQueryGroups = Punctuated<QueryGroup, Token![,]>;
+
+pub(crate) fn database(args: TokenStream, input: TokenStream) -> TokenStream {
+    let args = syn::parse_macro_input!(args as QueryGroupList);
+    let input = syn::parse_macro_input!(input as ItemStruct);
+
+    let query_groups = &args.query_groups;
+    let database_name = &input.ident;
+    let visibility = &input.vis;
+    let db_storage_field = quote! { storage };
+
+    let mut output = proc_macro2::TokenStream::new();
+    output.extend(quote! { #input });
+
+    let query_group_names_snake: Vec<_> = query_groups
+        .iter()
+        .map(|query_group| {
+            let group_name = query_group.name();
+            Ident::new(&group_name.to_string().to_snake_case(), group_name.span())
+        })
+        .collect();
+
+    let query_group_storage_names: Vec<_> = query_groups
+        .iter()
+        .map(|QueryGroup { group_path }| {
+            quote! {
+                <#group_path as salsa::plumbing::QueryGroup>::GroupStorage
+            }
+        })
+        .collect();
+
+    // For each query group `foo::MyGroup` create a link to its
+    // `foo::MyGroupGroupStorage`
+    let mut storage_fields = proc_macro2::TokenStream::new();
+    let mut storage_initializers = proc_macro2::TokenStream::new();
+    let mut has_group_impls = proc_macro2::TokenStream::new();
+    for (((query_group, group_name_snake), group_storage), group_index) in query_groups
+        .iter()
+        .zip(&query_group_names_snake)
+        .zip(&query_group_storage_names)
+        .zip(0_u16..)
+    {
+        let group_path = &query_group.group_path;
+
+        // rewrite the last identifier (`MyGroup`, above) to
+        // (e.g.) `MyGroupGroupStorage`.
+        storage_fields.extend(quote! {
+            #group_name_snake: #group_storage,
+        });
+
+        // rewrite the last identifier (`MyGroup`, above) to
+        // (e.g.) `MyGroupGroupStorage`.
+        storage_initializers.extend(quote! {
+            #group_name_snake: #group_storage::new(#group_index),
+        });
+
+        // ANCHOR:HasQueryGroup
+        has_group_impls.extend(quote! {
+            impl salsa::plumbing::HasQueryGroup<#group_path> for #database_name {
+                fn group_storage(&self) -> &#group_storage {
+                    &self.#db_storage_field.query_store().#group_name_snake
+                }
+
+                fn group_storage_mut(&mut self) -> (&#group_storage, &mut salsa::Runtime) {
+                    let (query_store_mut, runtime) = self.#db_storage_field.query_store_mut();
+                    (&query_store_mut.#group_name_snake, runtime)
+                }
+            }
+        });
+        // ANCHOR_END:HasQueryGroup
+    }
+
+    // create group storage wrapper struct
+    output.extend(quote! {
+        #[doc(hidden)]
+        #visibility struct __SalsaDatabaseStorage {
+            #storage_fields
+        }
+
+        impl Default for __SalsaDatabaseStorage {
+            fn default() -> Self {
+                Self {
+                    #storage_initializers
+                }
+            }
+        }
+    });
+
+    // Create a tuple (D1, D2, ...) where Di is the data for a given query group.
+    let mut database_data = vec![];
+    for QueryGroup { group_path } in query_groups {
+        database_data.push(quote! {
+            <#group_path as salsa::plumbing::QueryGroup>::GroupData
+        });
+    }
+
+    // ANCHOR:DatabaseStorageTypes
+    output.extend(quote! {
+        impl salsa::plumbing::DatabaseStorageTypes for #database_name {
+            type DatabaseStorage = __SalsaDatabaseStorage;
+        }
+    });
+    // ANCHOR_END:DatabaseStorageTypes
+
+    // ANCHOR:DatabaseOps
+    let mut fmt_ops = proc_macro2::TokenStream::new();
+    let mut maybe_changed_ops = proc_macro2::TokenStream::new();
+    let mut cycle_recovery_strategy_ops = proc_macro2::TokenStream::new();
+    let mut for_each_ops = proc_macro2::TokenStream::new();
+    for ((QueryGroup { group_path }, group_storage), group_index) in
+        query_groups.iter().zip(&query_group_storage_names).zip(0_u16..)
+    {
+        fmt_ops.extend(quote! {
+            #group_index => {
+                let storage: &#group_storage =
+                    <Self as salsa::plumbing::HasQueryGroup<#group_path>>::group_storage(self);
+                storage.fmt_index(self, input, fmt)
+            }
+        });
+        maybe_changed_ops.extend(quote! {
+            #group_index => {
+                let storage: &#group_storage =
+                    <Self as salsa::plumbing::HasQueryGroup<#group_path>>::group_storage(self);
+                storage.maybe_changed_after(self, input, revision)
+            }
+        });
+        cycle_recovery_strategy_ops.extend(quote! {
+            #group_index => {
+                let storage: &#group_storage =
+                    <Self as salsa::plumbing::HasQueryGroup<#group_path>>::group_storage(self);
+                storage.cycle_recovery_strategy(self, input)
+            }
+        });
+        for_each_ops.extend(quote! {
+            let storage: &#group_storage =
+                <Self as salsa::plumbing::HasQueryGroup<#group_path>>::group_storage(self);
+            storage.for_each_query(runtime, &mut op);
+        });
+    }
+    output.extend(quote! {
+        impl salsa::plumbing::DatabaseOps for #database_name {
+            fn ops_database(&self) -> &dyn salsa::Database {
+                self
+            }
+
+            fn ops_salsa_runtime(&self) -> &salsa::Runtime {
+                self.#db_storage_field.salsa_runtime()
+            }
+
+            fn ops_salsa_runtime_mut(&mut self) -> &mut salsa::Runtime {
+                self.#db_storage_field.salsa_runtime_mut()
+            }
+
+            fn fmt_index(
+                &self,
+                input: salsa::DatabaseKeyIndex,
+                fmt: &mut std::fmt::Formatter<'_>,
+            ) -> std::fmt::Result {
+                match input.group_index() {
+                    #fmt_ops
+                    i => panic!("salsa: invalid group index {}", i)
+                }
+            }
+
+            fn maybe_changed_after(
+                &self,
+                input: salsa::DatabaseKeyIndex,
+                revision: salsa::Revision
+            ) -> bool {
+                match input.group_index() {
+                    #maybe_changed_ops
+                    i => panic!("salsa: invalid group index {}", i)
+                }
+            }
+
+            fn cycle_recovery_strategy(
+                &self,
+                input: salsa::DatabaseKeyIndex,
+            ) -> salsa::plumbing::CycleRecoveryStrategy {
+                match input.group_index() {
+                    #cycle_recovery_strategy_ops
+                    i => panic!("salsa: invalid group index {}", i)
+                }
+            }
+
+            fn for_each_query(
+                &self,
+                mut op: &mut dyn FnMut(&dyn salsa::plumbing::QueryStorageMassOps),
+            ) {
+                let runtime = salsa::Database::salsa_runtime(self);
+                #for_each_ops
+            }
+        }
+    });
+    // ANCHOR_END:DatabaseOps
+
+    output.extend(has_group_impls);
+
+    output.into()
+}
+
+#[derive(Clone, Debug)]
+struct QueryGroupList {
+    query_groups: PunctuatedQueryGroups,
+}
+
+impl Parse for QueryGroupList {
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let query_groups: PunctuatedQueryGroups =
+            input.parse_terminated(QueryGroup::parse, Token![,])?;
+        Ok(QueryGroupList { query_groups })
+    }
+}
+
+#[derive(Clone, Debug)]
+struct QueryGroup {
+    group_path: Path,
+}
+
+impl QueryGroup {
+    /// The name of the query group trait.
+    fn name(&self) -> Ident {
+        self.group_path.segments.last().unwrap().ident.clone()
+    }
+}
+
+impl Parse for QueryGroup {
+    /// ```ignore
+    ///         impl HelloWorldDatabase;
+    /// ```
+    fn parse(input: ParseStream<'_>) -> syn::Result<Self> {
+        let group_path: Path = input.parse()?;
+        Ok(QueryGroup { group_path })
+    }
+}
+
+struct Nothing;
+
+impl Parse for Nothing {
+    fn parse(_input: ParseStream<'_>) -> syn::Result<Self> {
+        Ok(Nothing)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/lib.rs
new file mode 100644
index 00000000000..8af48b1e3f8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/lib.rs
@@ -0,0 +1,146 @@
+//! This crate provides salsa's macros and attributes.
+
+#![recursion_limit = "256"]
+
+#[macro_use]
+extern crate quote;
+
+use proc_macro::TokenStream;
+
+mod database_storage;
+mod parenthesized;
+mod query_group;
+
+/// The decorator that defines a salsa "query group" trait. This is a
+/// trait that defines everything that a block of queries need to
+/// execute, as well as defining the queries themselves that are
+/// exported for others to use.
+///
+/// This macro declares the "prototype" for a group of queries. It will
+/// expand into a trait and a set of structs, one per query.
+///
+/// For each query, you give the name of the accessor method to invoke
+/// the query (e.g., `my_query`, below), as well as its parameter
+/// types and the output type. You also give the name for a query type
+/// (e.g., `MyQuery`, below) that represents the query, and optionally
+/// other details, such as its storage.
+///
+/// # Examples
+///
+/// The simplest example is something like this:
+///
+/// ```ignore
+/// #[salsa::query_group]
+/// trait TypeckDatabase {
+///     #[salsa::input] // see below for other legal attributes
+///     fn my_query(&self, input: u32) -> u64;
+///
+///     /// Queries can have any number of inputs (including zero); if there
+///     /// is not exactly one input, then the key type will be
+///     /// a tuple of the input types, so in this case `(u32, f32)`.
+///     fn other_query(&self, input1: u32, input2: f32) -> u64;
+/// }
+/// ```
+///
+/// Here is a list of legal `salsa::XXX` attributes:
+///
+/// - Storage attributes: control how the query data is stored and set. These
+///   are described in detail in the section below.
+///   - `#[salsa::input]`
+///   - `#[salsa::memoized]`
+///   - `#[salsa::dependencies]`
+/// - Query execution:
+///   - `#[salsa::invoke(path::to::my_fn)]` -- for a non-input, this
+///     indicates the function to call when a query must be
+///     recomputed. The default is to call a function in the same
+///     module with the same name as the query.
+///   - `#[query_type(MyQueryTypeName)]` specifies the name of the
+///     dummy struct created for the query. Default is the name of the
+///     query, in camel case, plus the word "Query" (e.g.,
+///     `MyQueryQuery` and `OtherQueryQuery` in the examples above).
+///
+/// # Storage attributes
+///
+/// Here are the possible storage values for each query.  The default
+/// is `storage memoized`.
+///
+/// ## Input queries
+///
+/// Specifying `storage input` will give you an **input
+/// query**. Unlike derived queries, whose value is given by a
+/// function, input queries are explicitly set by doing
+/// `db.query(QueryType).set(key, value)` (where `QueryType` is the
+/// `type` specified for the query). Accessing a value that has not
+/// yet been set will panic. Each time you invoke `set`, we assume the
+/// value has changed, and so we will potentially re-execute derived
+/// queries that read (transitively) from this input.
+///
+/// ## Derived queries
+///
+/// Derived queries are specified by a function.
+///
+/// - `#[salsa::memoized]` (the default) -- The result is memoized
+///   between calls.  If the inputs have changed, we will recompute
+///   the value, but then compare against the old memoized value,
+///   which can significantly reduce the amount of recomputation
+///   required in new revisions. This does require that the value
+///   implements `Eq`.
+/// - `#[salsa::dependencies]` -- does not cache the value, so it will
+///   be recomputed every time it is needed. We do track the inputs, however,
+///   so if they have not changed, then things that rely on this query
+///   may be known not to have changed.
+///
+/// ## Attribute combinations
+///
+/// Some attributes are mutually exclusive. For example, it is an error to add
+/// multiple storage specifiers:
+///
+/// ```compile_fail
+/// # use salsa_macros as salsa;
+/// #[salsa::query_group]
+/// trait CodegenDatabase {
+///     #[salsa::input]
+///     #[salsa::memoized]
+///     fn my_query(&self, input: u32) -> u64;
+/// }
+/// ```
+///
+/// It is also an error to annotate a function to `invoke` on an `input` query:
+///
+/// ```compile_fail
+/// # use salsa_macros as salsa;
+/// #[salsa::query_group]
+/// trait CodegenDatabase {
+///     #[salsa::input]
+///     #[salsa::invoke(typeck::my_query)]
+///     fn my_query(&self, input: u32) -> u64;
+/// }
+/// ```
+#[proc_macro_attribute]
+pub fn query_group(args: TokenStream, input: TokenStream) -> TokenStream {
+    query_group::query_group(args, input)
+}
+
+/// This attribute is placed on your database struct. It takes a list of the
+/// query groups that your database supports. The format looks like so:
+///
+/// ```rust,ignore
+/// #[salsa::database(MyQueryGroup1, MyQueryGroup2)]
+/// struct MyDatabase {
+///     runtime: salsa::Runtime<MyDatabase>, // <-- your database will need this field, too
+/// }
+/// ```
+///
+/// Here, the struct `MyDatabase` would support the two query groups
+/// `MyQueryGroup1` and `MyQueryGroup2`. In addition to the `database`
+/// attribute, the struct needs to have a `runtime` field (of type
+/// [`salsa::Runtime`]) and to implement the `salsa::Database` trait.
+///
+/// See [the `hello_world` example][hw] for more details.
+///
+/// [`salsa::Runtime`]: struct.Runtime.html
+/// [hw]: https://github.com/salsa-rs/salsa/tree/master/examples/hello_world
+#[proc_macro_attribute]
+pub fn database(args: TokenStream, input: TokenStream) -> TokenStream {
+    database_storage::database(args, input)
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/parenthesized.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/parenthesized.rs
new file mode 100644
index 00000000000..9df41e03c16
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/parenthesized.rs
@@ -0,0 +1,13 @@
+//!
+pub(crate) struct Parenthesized<T>(pub(crate) T);
+
+impl<T> syn::parse::Parse for Parenthesized<T>
+where
+    T: syn::parse::Parse,
+{
+    fn parse(input: syn::parse::ParseStream<'_>) -> syn::Result<Self> {
+        let content;
+        syn::parenthesized!(content in input);
+        content.parse::<T>().map(Parenthesized)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
new file mode 100644
index 00000000000..e535d7ed043
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/salsa-macros/src/query_group.rs
@@ -0,0 +1,737 @@
+//!
+use std::{convert::TryFrom, iter::FromIterator};
+
+use crate::parenthesized::Parenthesized;
+use heck::ToUpperCamelCase;
+use proc_macro::TokenStream;
+use proc_macro2::Span;
+use quote::ToTokens;
+use syn::{
+    parse_macro_input, parse_quote, spanned::Spanned, Attribute, Error, FnArg, Ident, ItemTrait,
+    ReturnType, TraitItem, Type,
+};
+
+/// Implementation for `[salsa::query_group]` decorator.
+pub(crate) fn query_group(args: TokenStream, input: TokenStream) -> TokenStream {
+    let group_struct = parse_macro_input!(args as Ident);
+    let input: ItemTrait = parse_macro_input!(input as ItemTrait);
+    // println!("args: {:#?}", args);
+    // println!("input: {:#?}", input);
+
+    let input_span = input.span();
+    let (trait_attrs, salsa_attrs) = filter_attrs(input.attrs);
+    if !salsa_attrs.is_empty() {
+        return Error::new(input_span, format!("unsupported attributes: {:?}", salsa_attrs))
+            .to_compile_error()
+            .into();
+    }
+
+    let trait_vis = input.vis;
+    let trait_name = input.ident;
+    let _generics = input.generics.clone();
+    let dyn_db = quote! { dyn #trait_name };
+
+    // Decompose the trait into the corresponding queries.
+    let mut queries = vec![];
+    for item in input.items {
+        if let TraitItem::Fn(method) = item {
+            let query_name = method.sig.ident.to_string();
+
+            let mut storage = QueryStorage::Memoized;
+            let mut cycle = None;
+            let mut invoke = None;
+
+            let mut query_type =
+                format_ident!("{}Query", query_name.to_string().to_upper_camel_case());
+            let mut num_storages = 0;
+
+            // Extract attributes.
+            let (attrs, salsa_attrs) = filter_attrs(method.attrs);
+            for SalsaAttr { name, tts, span } in salsa_attrs {
+                match name.as_str() {
+                    "memoized" => {
+                        storage = QueryStorage::Memoized;
+                        num_storages += 1;
+                    }
+                    "dependencies" => {
+                        storage = QueryStorage::Dependencies;
+                        num_storages += 1;
+                    }
+                    "input" => {
+                        storage = QueryStorage::Input;
+                        num_storages += 1;
+                    }
+                    "interned" => {
+                        storage = QueryStorage::Interned;
+                        num_storages += 1;
+                    }
+                    "cycle" => {
+                        cycle = Some(parse_macro_input!(tts as Parenthesized<syn::Path>).0);
+                    }
+                    "invoke" => {
+                        invoke = Some(parse_macro_input!(tts as Parenthesized<syn::Path>).0);
+                    }
+                    "query_type" => {
+                        query_type = parse_macro_input!(tts as Parenthesized<Ident>).0;
+                    }
+                    "transparent" => {
+                        storage = QueryStorage::Transparent;
+                        num_storages += 1;
+                    }
+                    _ => {
+                        return Error::new(span, format!("unknown salsa attribute `{}`", name))
+                            .to_compile_error()
+                            .into();
+                    }
+                }
+            }
+
+            let sig_span = method.sig.span();
+            // Check attribute combinations.
+            if num_storages > 1 {
+                return Error::new(sig_span, "multiple storage attributes specified")
+                    .to_compile_error()
+                    .into();
+            }
+            match &invoke {
+                Some(invoke) if storage == QueryStorage::Input => {
+                    return Error::new(
+                        invoke.span(),
+                        "#[salsa::invoke] cannot be set on #[salsa::input] queries",
+                    )
+                    .to_compile_error()
+                    .into();
+                }
+                _ => {}
+            }
+
+            // Extract keys.
+            let mut iter = method.sig.inputs.iter();
+            let self_receiver = match iter.next() {
+                Some(FnArg::Receiver(sr)) if sr.mutability.is_none() => sr,
+                _ => {
+                    return Error::new(
+                        sig_span,
+                        format!("first argument of query `{}` must be `&self`", query_name),
+                    )
+                    .to_compile_error()
+                    .into();
+                }
+            };
+            let mut keys: Vec<(Ident, Type)> = vec![];
+            for (idx, arg) in iter.enumerate() {
+                match arg {
+                    FnArg::Typed(syn::PatType { pat, ty, .. }) => keys.push((
+                        match pat.as_ref() {
+                            syn::Pat::Ident(ident_pat) => ident_pat.ident.clone(),
+                            _ => format_ident!("key{}", idx),
+                        },
+                        Type::clone(ty),
+                    )),
+                    arg => {
+                        return Error::new(
+                            arg.span(),
+                            format!("unsupported argument `{:?}` of `{}`", arg, query_name,),
+                        )
+                        .to_compile_error()
+                        .into();
+                    }
+                }
+            }
+
+            // Extract value.
+            let value = match method.sig.output {
+                ReturnType::Type(_, ref ty) => ty.as_ref().clone(),
+                ref ret => {
+                    return Error::new(
+                        ret.span(),
+                        format!("unsupported return type `{:?}` of `{}`", ret, query_name),
+                    )
+                    .to_compile_error()
+                    .into();
+                }
+            };
+
+            // For `#[salsa::interned]` keys, we create a "lookup key" automatically.
+            //
+            // For a query like:
+            //
+            //     fn foo(&self, x: Key1, y: Key2) -> u32
+            //
+            // we would create
+            //
+            //     fn lookup_foo(&self, x: u32) -> (Key1, Key2)
+            let lookup_query = if let QueryStorage::Interned = storage {
+                let lookup_query_type =
+                    format_ident!("{}LookupQuery", query_name.to_string().to_upper_camel_case());
+                let lookup_fn_name = format_ident!("lookup_{}", query_name);
+                let keys = keys.iter().map(|(_, ty)| ty);
+                let lookup_value: Type = parse_quote!((#(#keys),*));
+                let lookup_keys = vec![(parse_quote! { key }, value.clone())];
+                Some(Query {
+                    query_type: lookup_query_type,
+                    query_name: format!("{}", lookup_fn_name),
+                    fn_name: lookup_fn_name,
+                    receiver: self_receiver.clone(),
+                    attrs: vec![], // FIXME -- some automatically generated docs on this method?
+                    storage: QueryStorage::InternedLookup { intern_query_type: query_type.clone() },
+                    keys: lookup_keys,
+                    value: lookup_value,
+                    invoke: None,
+                    cycle: cycle.clone(),
+                })
+            } else {
+                None
+            };
+
+            queries.push(Query {
+                query_type,
+                query_name,
+                fn_name: method.sig.ident,
+                receiver: self_receiver.clone(),
+                attrs,
+                storage,
+                keys,
+                value,
+                invoke,
+                cycle,
+            });
+
+            queries.extend(lookup_query);
+        }
+    }
+
+    let group_storage = format_ident!("{}GroupStorage__", trait_name, span = Span::call_site());
+
+    let mut query_fn_declarations = proc_macro2::TokenStream::new();
+    let mut query_fn_definitions = proc_macro2::TokenStream::new();
+    let mut storage_fields = proc_macro2::TokenStream::new();
+    let mut queries_with_storage = vec![];
+    for query in &queries {
+        #[allow(clippy::map_identity)]
+        // clippy is incorrect here, this is not the identity function due to match ergonomics
+        let (key_names, keys): (Vec<_>, Vec<_>) = query.keys.iter().map(|(a, b)| (a, b)).unzip();
+        let value = &query.value;
+        let fn_name = &query.fn_name;
+        let qt = &query.query_type;
+        let attrs = &query.attrs;
+        let self_receiver = &query.receiver;
+
+        query_fn_declarations.extend(quote! {
+            #(#attrs)*
+            fn #fn_name(#self_receiver, #(#key_names: #keys),*) -> #value;
+        });
+
+        // Special case: transparent queries don't create actual storage,
+        // just inline the definition
+        if let QueryStorage::Transparent = query.storage {
+            let invoke = query.invoke_tt();
+            query_fn_definitions.extend(quote! {
+                fn #fn_name(&self, #(#key_names: #keys),*) -> #value {
+                    #invoke(self, #(#key_names),*)
+                }
+            });
+            continue;
+        }
+
+        queries_with_storage.push(fn_name);
+
+        query_fn_definitions.extend(quote! {
+            fn #fn_name(&self, #(#key_names: #keys),*) -> #value {
+                // Create a shim to force the code to be monomorphized in the
+                // query crate. Our experiments revealed that this makes a big
+                // difference in total compilation time in rust-analyzer, though
+                // it's not totally obvious why that should be.
+                fn __shim(db: &(dyn #trait_name + '_),  #(#key_names: #keys),*) -> #value {
+                    salsa::plumbing::get_query_table::<#qt>(db).get((#(#key_names),*))
+                }
+                __shim(self, #(#key_names),*)
+
+            }
+        });
+
+        // For input queries, we need `set_foo` etc
+        if let QueryStorage::Input = query.storage {
+            let set_fn_name = format_ident!("set_{}", fn_name);
+            let set_with_durability_fn_name = format_ident!("set_{}_with_durability", fn_name);
+
+            let set_fn_docs = format!(
+                "
+                Set the value of the `{fn_name}` input.
+
+                See `{fn_name}` for details.
+
+                *Note:* Setting values will trigger cancellation
+                of any ongoing queries; this method blocks until
+                those queries have been cancelled.
+            ",
+                fn_name = fn_name
+            );
+
+            let set_constant_fn_docs = format!(
+                "
+                Set the value of the `{fn_name}` input with a
+                specific durability instead of the default of
+                `Durability::LOW`. You can use `Durability::MAX`
+                to promise that its value will never change again.
+
+                See `{fn_name}` for details.
+
+                *Note:* Setting values will trigger cancellation
+                of any ongoing queries; this method blocks until
+                those queries have been cancelled.
+            ",
+                fn_name = fn_name
+            );
+
+            query_fn_declarations.extend(quote! {
+                # [doc = #set_fn_docs]
+                fn #set_fn_name(&mut self, #(#key_names: #keys,)* value__: #value);
+
+
+                # [doc = #set_constant_fn_docs]
+                fn #set_with_durability_fn_name(&mut self, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability);
+            });
+
+            query_fn_definitions.extend(quote! {
+                fn #set_fn_name(&mut self, #(#key_names: #keys,)* value__: #value) {
+                    fn __shim(db: &mut dyn #trait_name, #(#key_names: #keys,)* value__: #value) {
+                        salsa::plumbing::get_query_table_mut::<#qt>(db).set((#(#key_names),*), value__)
+                    }
+                    __shim(self, #(#key_names,)* value__)
+                }
+
+                fn #set_with_durability_fn_name(&mut self, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability) {
+                    fn __shim(db: &mut dyn #trait_name, #(#key_names: #keys,)* value__: #value, durability__: salsa::Durability) {
+                        salsa::plumbing::get_query_table_mut::<#qt>(db).set_with_durability((#(#key_names),*), value__, durability__)
+                    }
+                    __shim(self, #(#key_names,)* value__ ,durability__)
+                }
+            });
+        }
+
+        // A field for the storage struct
+        storage_fields.extend(quote! {
+            #fn_name: std::sync::Arc<<#qt as salsa::Query>::Storage>,
+        });
+    }
+
+    // Emit the trait itself.
+    let mut output = {
+        let bounds = &input.supertraits;
+        quote! {
+            #(#trait_attrs)*
+            #trait_vis trait #trait_name :
+            salsa::Database +
+            salsa::plumbing::HasQueryGroup<#group_struct> +
+            #bounds
+            {
+                #query_fn_declarations
+            }
+        }
+    };
+
+    // Emit the query group struct and impl of `QueryGroup`.
+    output.extend(quote! {
+        /// Representative struct for the query group.
+        #trait_vis struct #group_struct { }
+
+        impl salsa::plumbing::QueryGroup for #group_struct
+        {
+            type DynDb = #dyn_db;
+            type GroupStorage = #group_storage;
+        }
+    });
+
+    // Emit an impl of the trait
+    output.extend({
+        let bounds = input.supertraits;
+        quote! {
+            impl<DB> #trait_name for DB
+            where
+                DB: #bounds,
+                DB: salsa::Database,
+                DB: salsa::plumbing::HasQueryGroup<#group_struct>,
+            {
+                #query_fn_definitions
+            }
+        }
+    });
+
+    let non_transparent_queries =
+        || queries.iter().filter(|q| !matches!(q.storage, QueryStorage::Transparent));
+
+    // Emit the query types.
+    for (query, query_index) in non_transparent_queries().zip(0_u16..) {
+        let fn_name = &query.fn_name;
+        let qt = &query.query_type;
+
+        let storage = match &query.storage {
+            QueryStorage::Memoized => quote!(salsa::plumbing::MemoizedStorage<Self>),
+            QueryStorage::Dependencies => {
+                quote!(salsa::plumbing::DependencyStorage<Self>)
+            }
+            QueryStorage::Input if query.keys.is_empty() => {
+                quote!(salsa::plumbing::UnitInputStorage<Self>)
+            }
+            QueryStorage::Input => quote!(salsa::plumbing::InputStorage<Self>),
+            QueryStorage::Interned => quote!(salsa::plumbing::InternedStorage<Self>),
+            QueryStorage::InternedLookup { intern_query_type } => {
+                quote!(salsa::plumbing::LookupInternedStorage<Self, #intern_query_type>)
+            }
+            QueryStorage::Transparent => panic!("should have been filtered"),
+        };
+        let keys = query.keys.iter().map(|(_, ty)| ty);
+        let value = &query.value;
+        let query_name = &query.query_name;
+
+        // Emit the query struct and implement the Query trait on it.
+        output.extend(quote! {
+            #[derive(Default, Debug)]
+            #trait_vis struct #qt;
+        });
+
+        output.extend(quote! {
+            impl #qt {
+                /// Get access to extra methods pertaining to this query.
+                /// You can also use it to invoke this query.
+                #trait_vis fn in_db(self, db: &#dyn_db) -> salsa::QueryTable<'_, Self>
+                {
+                    salsa::plumbing::get_query_table::<#qt>(db)
+                }
+            }
+        });
+
+        output.extend(quote! {
+            impl #qt {
+                /// Like `in_db`, but gives access to methods for setting the
+                /// value of an input. Not applicable to derived queries.
+                ///
+                /// # Threads, cancellation, and blocking
+                ///
+                /// Mutating the value of a query cannot be done while there are
+                /// still other queries executing. If you are using your database
+                /// within a single thread, this is not a problem: you only have
+                /// `&self` access to the database, but this method requires `&mut
+                /// self`.
+                ///
+                /// However, if you have used `snapshot` to create other threads,
+                /// then attempts to `set` will **block the current thread** until
+                /// those snapshots are dropped (usually when those threads
+                /// complete). This also implies that if you create a snapshot but
+                /// do not send it to another thread, then invoking `set` will
+                /// deadlock.
+                ///
+                /// Before blocking, the thread that is attempting to `set` will
+                /// also set a cancellation flag. This will cause any query
+                /// invocations in other threads to unwind with a `Cancelled`
+                /// sentinel value and eventually let the `set` succeed once all
+                /// threads have unwound past the salsa invocation.
+                ///
+                /// If your query implementations are performing expensive
+                /// operations without invoking another query, you can also use
+                /// the `Runtime::unwind_if_cancelled` method to check for an
+                /// ongoing cancellation and bring those operations to a close,
+                /// thus allowing the `set` to succeed. Otherwise, long-running
+                /// computations may lead to "starvation", meaning that the
+                /// thread attempting to `set` has to wait a long, long time. =)
+                #trait_vis fn in_db_mut(self, db: &mut #dyn_db) -> salsa::QueryTableMut<'_, Self>
+                {
+                    salsa::plumbing::get_query_table_mut::<#qt>(db)
+                }
+            }
+
+            impl<'d> salsa::QueryDb<'d> for #qt
+            {
+                type DynDb = #dyn_db + 'd;
+                type Group = #group_struct;
+                type GroupStorage = #group_storage;
+            }
+
+            // ANCHOR:Query_impl
+            impl salsa::Query for #qt
+            {
+                type Key = (#(#keys),*);
+                type Value = #value;
+                type Storage = #storage;
+
+                const QUERY_INDEX: u16 = #query_index;
+
+                const QUERY_NAME: &'static str = #query_name;
+
+                fn query_storage<'a>(
+                    group_storage: &'a <Self as salsa::QueryDb<'_>>::GroupStorage,
+                ) -> &'a std::sync::Arc<Self::Storage> {
+                    &group_storage.#fn_name
+                }
+
+                fn query_storage_mut<'a>(
+                    group_storage: &'a <Self as salsa::QueryDb<'_>>::GroupStorage,
+                ) -> &'a std::sync::Arc<Self::Storage> {
+                    &group_storage.#fn_name
+                }
+            }
+            // ANCHOR_END:Query_impl
+        });
+
+        // Implement the QueryFunction trait for queries which need it.
+        if query.storage.needs_query_function() {
+            let span = query.fn_name.span();
+
+            let key_names: Vec<_> = query.keys.iter().map(|(pat, _)| pat).collect();
+            let key_pattern = if query.keys.len() == 1 {
+                quote! { #(#key_names),* }
+            } else {
+                quote! { (#(#key_names),*) }
+            };
+            let invoke = query.invoke_tt();
+
+            let recover = if let Some(cycle_recovery_fn) = &query.cycle {
+                quote! {
+                    const CYCLE_STRATEGY: salsa::plumbing::CycleRecoveryStrategy =
+                        salsa::plumbing::CycleRecoveryStrategy::Fallback;
+                    fn cycle_fallback(db: &<Self as salsa::QueryDb<'_>>::DynDb, cycle: &salsa::Cycle, #key_pattern: &<Self as salsa::Query>::Key)
+                        -> <Self as salsa::Query>::Value {
+                        #cycle_recovery_fn(
+                                db,
+                                cycle,
+                                #(#key_names),*
+                        )
+                    }
+                }
+            } else {
+                quote! {
+                    const CYCLE_STRATEGY: salsa::plumbing::CycleRecoveryStrategy =
+                        salsa::plumbing::CycleRecoveryStrategy::Panic;
+                }
+            };
+
+            output.extend(quote_spanned! {span=>
+                // ANCHOR:QueryFunction_impl
+                impl salsa::plumbing::QueryFunction for #qt
+                {
+                    fn execute(db: &<Self as salsa::QueryDb<'_>>::DynDb, #key_pattern: <Self as salsa::Query>::Key)
+                        -> <Self as salsa::Query>::Value {
+                        #invoke(db, #(#key_names),*)
+                    }
+
+                    #recover
+                }
+                // ANCHOR_END:QueryFunction_impl
+            });
+        }
+    }
+
+    let mut fmt_ops = proc_macro2::TokenStream::new();
+    for (Query { fn_name, .. }, query_index) in non_transparent_queries().zip(0_u16..) {
+        fmt_ops.extend(quote! {
+            #query_index => {
+                salsa::plumbing::QueryStorageOps::fmt_index(
+                    &*self.#fn_name, db, input, fmt,
+                )
+            }
+        });
+    }
+
+    let mut maybe_changed_ops = proc_macro2::TokenStream::new();
+    for (Query { fn_name, .. }, query_index) in non_transparent_queries().zip(0_u16..) {
+        maybe_changed_ops.extend(quote! {
+            #query_index => {
+                salsa::plumbing::QueryStorageOps::maybe_changed_after(
+                    &*self.#fn_name, db, input, revision
+                )
+            }
+        });
+    }
+
+    let mut cycle_recovery_strategy_ops = proc_macro2::TokenStream::new();
+    for (Query { fn_name, .. }, query_index) in non_transparent_queries().zip(0_u16..) {
+        cycle_recovery_strategy_ops.extend(quote! {
+            #query_index => {
+                salsa::plumbing::QueryStorageOps::cycle_recovery_strategy(
+                    &*self.#fn_name
+                )
+            }
+        });
+    }
+
+    let mut for_each_ops = proc_macro2::TokenStream::new();
+    for Query { fn_name, .. } in non_transparent_queries() {
+        for_each_ops.extend(quote! {
+            op(&*self.#fn_name);
+        });
+    }
+
+    // Emit query group storage struct
+    output.extend(quote! {
+        #trait_vis struct #group_storage {
+            #storage_fields
+        }
+
+        // ANCHOR:group_storage_new
+        impl #group_storage {
+            #trait_vis fn new(group_index: u16) -> Self {
+                #group_storage {
+                    #(
+                        #queries_with_storage:
+                        std::sync::Arc::new(salsa::plumbing::QueryStorageOps::new(group_index)),
+                    )*
+                }
+            }
+        }
+        // ANCHOR_END:group_storage_new
+
+        // ANCHOR:group_storage_methods
+        impl #group_storage {
+            #trait_vis fn fmt_index(
+                &self,
+                db: &(#dyn_db + '_),
+                input: salsa::DatabaseKeyIndex,
+                fmt: &mut std::fmt::Formatter<'_>,
+            ) -> std::fmt::Result {
+                match input.query_index() {
+                    #fmt_ops
+                    i => panic!("salsa: impossible query index {}", i),
+                }
+            }
+
+            #trait_vis fn maybe_changed_after(
+                &self,
+                db: &(#dyn_db + '_),
+                input: salsa::DatabaseKeyIndex,
+                revision: salsa::Revision,
+            ) -> bool {
+                match input.query_index() {
+                    #maybe_changed_ops
+                    i => panic!("salsa: impossible query index {}", i),
+                }
+            }
+
+            #trait_vis fn cycle_recovery_strategy(
+                &self,
+                db: &(#dyn_db + '_),
+                input: salsa::DatabaseKeyIndex,
+            ) -> salsa::plumbing::CycleRecoveryStrategy {
+                match input.query_index() {
+                    #cycle_recovery_strategy_ops
+                    i => panic!("salsa: impossible query index {}", i),
+                }
+            }
+
+            #trait_vis fn for_each_query(
+                &self,
+                _runtime: &salsa::Runtime,
+                mut op: &mut dyn FnMut(&dyn salsa::plumbing::QueryStorageMassOps),
+            ) {
+                #for_each_ops
+            }
+        }
+        // ANCHOR_END:group_storage_methods
+    });
+    output.into()
+}
+
+struct SalsaAttr {
+    name: String,
+    tts: TokenStream,
+    span: Span,
+}
+
+impl std::fmt::Debug for SalsaAttr {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "{:?}", self.name)
+    }
+}
+
+impl TryFrom<syn::Attribute> for SalsaAttr {
+    type Error = syn::Attribute;
+
+    fn try_from(attr: syn::Attribute) -> Result<SalsaAttr, syn::Attribute> {
+        if is_not_salsa_attr_path(attr.path()) {
+            return Err(attr);
+        }
+
+        let span = attr.span();
+        let name = attr.path().segments[1].ident.to_string();
+        let tts = match attr.meta {
+            syn::Meta::Path(path) => path.into_token_stream(),
+            syn::Meta::List(ref list) => {
+                let tts = list
+                    .into_token_stream()
+                    .into_iter()
+                    .skip(attr.path().to_token_stream().into_iter().count());
+                proc_macro2::TokenStream::from_iter(tts)
+            }
+            syn::Meta::NameValue(nv) => nv.into_token_stream(),
+        }
+        .into();
+
+        Ok(SalsaAttr { name, tts, span })
+    }
+}
+
+fn is_not_salsa_attr_path(path: &syn::Path) -> bool {
+    path.segments.first().map(|s| s.ident != "salsa").unwrap_or(true) || path.segments.len() != 2
+}
+
+fn filter_attrs(attrs: Vec<Attribute>) -> (Vec<Attribute>, Vec<SalsaAttr>) {
+    let mut other = vec![];
+    let mut salsa = vec![];
+    // Leave non-salsa attributes untouched. These are
+    // attributes that don't start with `salsa::` or don't have
+    // exactly two segments in their path.
+    // Keep the salsa attributes around.
+    for attr in attrs {
+        match SalsaAttr::try_from(attr) {
+            Ok(it) => salsa.push(it),
+            Err(it) => other.push(it),
+        }
+    }
+    (other, salsa)
+}
+
+#[derive(Debug)]
+struct Query {
+    fn_name: Ident,
+    receiver: syn::Receiver,
+    query_name: String,
+    attrs: Vec<syn::Attribute>,
+    query_type: Ident,
+    storage: QueryStorage,
+    keys: Vec<(Ident, syn::Type)>,
+    value: syn::Type,
+    invoke: Option<syn::Path>,
+    cycle: Option<syn::Path>,
+}
+
+impl Query {
+    fn invoke_tt(&self) -> proc_macro2::TokenStream {
+        match &self.invoke {
+            Some(i) => i.into_token_stream(),
+            None => self.fn_name.clone().into_token_stream(),
+        }
+    }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+enum QueryStorage {
+    Memoized,
+    Dependencies,
+    Input,
+    Interned,
+    InternedLookup { intern_query_type: Ident },
+    Transparent,
+}
+
+impl QueryStorage {
+    /// Do we need a `QueryFunction` impl for this type of query?
+    fn needs_query_function(&self) -> bool {
+        match self {
+            QueryStorage::Input
+            | QueryStorage::Interned
+            | QueryStorage::InternedLookup { .. }
+            | QueryStorage::Transparent => false,
+            QueryStorage::Memoized | QueryStorage::Dependencies => true,
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/debug.rs b/src/tools/rust-analyzer/crates/salsa/src/debug.rs
new file mode 100644
index 00000000000..0925ddb3d85
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/debug.rs
@@ -0,0 +1,66 @@
+//! Debugging APIs: these are meant for use when unit-testing or
+//! debugging your application but aren't ordinarily needed.
+
+use crate::durability::Durability;
+use crate::plumbing::QueryStorageOps;
+use crate::Query;
+use crate::QueryTable;
+use std::iter::FromIterator;
+
+/// Additional methods on queries that can be used to "peek into"
+/// their current state. These methods are meant for debugging and
+/// observing the effects of garbage collection etc.
+pub trait DebugQueryTable {
+    /// Key of this query.
+    type Key;
+
+    /// Value of this query.
+    type Value;
+
+    /// Returns a lower bound on the durability for the given key.
+    /// This is typically the minimum durability of all values that
+    /// the query accessed, but we may return a lower durability in
+    /// some cases.
+    fn durability(&self, key: Self::Key) -> Durability;
+
+    /// Get the (current) set of the entries in the query table.
+    fn entries<C>(&self) -> C
+    where
+        C: FromIterator<TableEntry<Self::Key, Self::Value>>;
+}
+
+/// An entry from a query table, for debugging and inspecting the table state.
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
+#[non_exhaustive]
+pub struct TableEntry<K, V> {
+    /// key of the query
+    pub key: K,
+    /// value of the query, if it is stored
+    pub value: Option<V>,
+}
+
+impl<K, V> TableEntry<K, V> {
+    pub(crate) fn new(key: K, value: Option<V>) -> TableEntry<K, V> {
+        TableEntry { key, value }
+    }
+}
+
+impl<Q> DebugQueryTable for QueryTable<'_, Q>
+where
+    Q: Query,
+    Q::Storage: QueryStorageOps<Q>,
+{
+    type Key = Q::Key;
+    type Value = Q::Value;
+
+    fn durability(&self, key: Q::Key) -> Durability {
+        self.storage.durability(self.db, &key)
+    }
+
+    fn entries<C>(&self) -> C
+    where
+        C: FromIterator<TableEntry<Self::Key, Self::Value>>,
+    {
+        self.storage.entries(self.db)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived.rs b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
new file mode 100644
index 00000000000..c381e66e087
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/derived.rs
@@ -0,0 +1,233 @@
+//!
+use crate::debug::TableEntry;
+use crate::durability::Durability;
+use crate::hash::FxIndexMap;
+use crate::lru::Lru;
+use crate::plumbing::DerivedQueryStorageOps;
+use crate::plumbing::LruQueryStorageOps;
+use crate::plumbing::QueryFunction;
+use crate::plumbing::QueryStorageMassOps;
+use crate::plumbing::QueryStorageOps;
+use crate::runtime::StampedValue;
+use crate::Runtime;
+use crate::{Database, DatabaseKeyIndex, QueryDb, Revision};
+use parking_lot::RwLock;
+use std::borrow::Borrow;
+use std::convert::TryFrom;
+use std::hash::Hash;
+use std::marker::PhantomData;
+use triomphe::Arc;
+
+mod slot;
+use slot::Slot;
+
+/// Memoized queries store the result plus a list of the other queries
+/// that they invoked. This means we can avoid recomputing them when
+/// none of those inputs have changed.
+pub type MemoizedStorage<Q> = DerivedStorage<Q, AlwaysMemoizeValue>;
+
+/// "Dependency" queries just track their dependencies and not the
+/// actual value (which they produce on demand). This lessens the
+/// storage requirements.
+pub type DependencyStorage<Q> = DerivedStorage<Q, NeverMemoizeValue>;
+
+/// Handles storage where the value is 'derived' by executing a
+/// function (in contrast to "inputs").
+pub struct DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    group_index: u16,
+    lru_list: Lru<Slot<Q, MP>>,
+    slot_map: RwLock<FxIndexMap<Q::Key, Arc<Slot<Q, MP>>>>,
+    policy: PhantomData<MP>,
+}
+
+impl<Q, MP> std::panic::RefUnwindSafe for DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+    Q::Key: std::panic::RefUnwindSafe,
+    Q::Value: std::panic::RefUnwindSafe,
+{
+}
+
+pub trait MemoizationPolicy<Q>: Send + Sync
+where
+    Q: QueryFunction,
+{
+    fn should_memoize_value(key: &Q::Key) -> bool;
+
+    fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool;
+}
+
+pub enum AlwaysMemoizeValue {}
+impl<Q> MemoizationPolicy<Q> for AlwaysMemoizeValue
+where
+    Q: QueryFunction,
+    Q::Value: Eq,
+{
+    fn should_memoize_value(_key: &Q::Key) -> bool {
+        true
+    }
+
+    fn memoized_value_eq(old_value: &Q::Value, new_value: &Q::Value) -> bool {
+        old_value == new_value
+    }
+}
+
+pub enum NeverMemoizeValue {}
+impl<Q> MemoizationPolicy<Q> for NeverMemoizeValue
+where
+    Q: QueryFunction,
+{
+    fn should_memoize_value(_key: &Q::Key) -> bool {
+        false
+    }
+
+    fn memoized_value_eq(_old_value: &Q::Value, _new_value: &Q::Value) -> bool {
+        panic!("cannot reach since we never memoize")
+    }
+}
+
+impl<Q, MP> DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn slot(&self, key: &Q::Key) -> Arc<Slot<Q, MP>> {
+        if let Some(v) = self.slot_map.read().get(key) {
+            return v.clone();
+        }
+
+        let mut write = self.slot_map.write();
+        let entry = write.entry(key.clone());
+        let key_index = u32::try_from(entry.index()).unwrap();
+        let database_key_index = DatabaseKeyIndex {
+            group_index: self.group_index,
+            query_index: Q::QUERY_INDEX,
+            key_index,
+        };
+        entry.or_insert_with(|| Arc::new(Slot::new(key.clone(), database_key_index))).clone()
+    }
+}
+
+impl<Q, MP> QueryStorageOps<Q> for DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = Q::CYCLE_STRATEGY;
+
+    fn new(group_index: u16) -> Self {
+        DerivedStorage {
+            group_index,
+            slot_map: RwLock::new(FxIndexMap::default()),
+            lru_list: Default::default(),
+            policy: PhantomData,
+        }
+    }
+
+    fn fmt_index(
+        &self,
+        _db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        assert_eq!(index.group_index, self.group_index);
+        assert_eq!(index.query_index, Q::QUERY_INDEX);
+        let slot_map = self.slot_map.read();
+        let key = slot_map.get_index(index.key_index as usize).unwrap().0;
+        write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
+    }
+
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool {
+        assert_eq!(input.group_index, self.group_index);
+        assert_eq!(input.query_index, Q::QUERY_INDEX);
+        debug_assert!(revision < db.salsa_runtime().current_revision());
+        let slot = self.slot_map.read().get_index(input.key_index as usize).unwrap().1.clone();
+        slot.maybe_changed_after(db, revision)
+    }
+
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
+        db.unwind_if_cancelled();
+
+        let slot = self.slot(key);
+        let StampedValue { value, durability, changed_at } = slot.read(db);
+
+        if let Some(evicted) = self.lru_list.record_use(&slot) {
+            evicted.evict();
+        }
+
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            slot.database_key_index(),
+            durability,
+            changed_at,
+        );
+
+        value
+    }
+
+    fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability {
+        self.slot(key).durability(db)
+    }
+
+    fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
+    {
+        let slot_map = self.slot_map.read();
+        slot_map.values().filter_map(|slot| slot.as_table_entry()).collect()
+    }
+}
+
+impl<Q, MP> QueryStorageMassOps for DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn purge(&self) {
+        self.lru_list.purge();
+        *self.slot_map.write() = Default::default();
+    }
+}
+
+impl<Q, MP> LruQueryStorageOps for DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn set_lru_capacity(&self, new_capacity: usize) {
+        self.lru_list.set_lru_capacity(new_capacity);
+    }
+}
+
+impl<Q, MP> DerivedQueryStorageOps<Q> for DerivedStorage<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn invalidate<S>(&self, runtime: &mut Runtime, key: &S)
+    where
+        S: Eq + Hash,
+        Q::Key: Borrow<S>,
+    {
+        runtime.with_incremented_revision(|new_revision| {
+            let map_read = self.slot_map.read();
+
+            if let Some(slot) = map_read.get(key) {
+                if let Some(durability) = slot.invalidate(new_revision) {
+                    return Some(durability);
+                }
+            }
+
+            None
+        })
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs
new file mode 100644
index 00000000000..4fad791a26a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/derived/slot.rs
@@ -0,0 +1,833 @@
+//!
+use crate::debug::TableEntry;
+use crate::derived::MemoizationPolicy;
+use crate::durability::Durability;
+use crate::lru::LruIndex;
+use crate::lru::LruNode;
+use crate::plumbing::{DatabaseOps, QueryFunction};
+use crate::revision::Revision;
+use crate::runtime::local_state::ActiveQueryGuard;
+use crate::runtime::local_state::QueryInputs;
+use crate::runtime::local_state::QueryRevisions;
+use crate::runtime::Runtime;
+use crate::runtime::RuntimeId;
+use crate::runtime::StampedValue;
+use crate::runtime::WaitResult;
+use crate::Cycle;
+use crate::{Database, DatabaseKeyIndex, Event, EventKind, QueryDb};
+use parking_lot::{RawRwLock, RwLock};
+use std::marker::PhantomData;
+use std::ops::Deref;
+use std::sync::atomic::{AtomicBool, Ordering};
+use tracing::{debug, info};
+
+pub(super) struct Slot<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    key: Q::Key,
+    database_key_index: DatabaseKeyIndex,
+    state: RwLock<QueryState<Q>>,
+    policy: PhantomData<MP>,
+    lru_index: LruIndex,
+}
+
+/// Defines the "current state" of query's memoized results.
+enum QueryState<Q>
+where
+    Q: QueryFunction,
+{
+    NotComputed,
+
+    /// The runtime with the given id is currently computing the
+    /// result of this query.
+    InProgress {
+        id: RuntimeId,
+
+        /// Set to true if any other queries are blocked,
+        /// waiting for this query to complete.
+        anyone_waiting: AtomicBool,
+    },
+
+    /// We have computed the query already, and here is the result.
+    Memoized(Memo<Q::Value>),
+}
+
+struct Memo<V> {
+    /// The result of the query, if we decide to memoize it.
+    value: Option<V>,
+
+    /// Last revision when this memo was verified; this begins
+    /// as the current revision.
+    pub(crate) verified_at: Revision,
+
+    /// Revision information
+    revisions: QueryRevisions,
+}
+
+/// Return value of `probe` helper.
+enum ProbeState<V, G> {
+    /// Another thread was active but has completed.
+    /// Try again!
+    Retry,
+
+    /// No entry for this key at all.
+    NotComputed(G),
+
+    /// There is an entry, but its contents have not been
+    /// verified in this revision.
+    Stale(G),
+
+    /// There is an entry, and it has been verified
+    /// in this revision, but it has no cached
+    /// value. The `Revision` is the revision where the
+    /// value last changed (if we were to recompute it).
+    NoValue(G, Revision),
+
+    /// There is an entry which has been verified,
+    /// and it has the following value-- or, we blocked
+    /// on another thread, and that resulted in a cycle.
+    UpToDate(V),
+}
+
+/// Return value of `maybe_changed_after_probe` helper.
+enum MaybeChangedSinceProbeState<G> {
+    /// Another thread was active but has completed.
+    /// Try again!
+    Retry,
+
+    /// Value may have changed in the given revision.
+    ChangedAt(Revision),
+
+    /// There is a stale cache entry that has not been
+    /// verified in this revision, so we can't say.
+    Stale(G),
+}
+
+impl<Q, MP> Slot<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    pub(super) fn new(key: Q::Key, database_key_index: DatabaseKeyIndex) -> Self {
+        Self {
+            key,
+            database_key_index,
+            state: RwLock::new(QueryState::NotComputed),
+            lru_index: LruIndex::default(),
+            policy: PhantomData,
+        }
+    }
+
+    pub(super) fn database_key_index(&self) -> DatabaseKeyIndex {
+        self.database_key_index
+    }
+
+    pub(super) fn read(&self, db: &<Q as QueryDb<'_>>::DynDb) -> StampedValue<Q::Value> {
+        let runtime = db.salsa_runtime();
+
+        // NB: We don't need to worry about people modifying the
+        // revision out from under our feet. Either `db` is a frozen
+        // database, in which case there is a lock, or the mutator
+        // thread is the current thread, and it will be prevented from
+        // doing any `set` invocations while the query function runs.
+        let revision_now = runtime.current_revision();
+
+        info!("{:?}: invoked at {:?}", self, revision_now,);
+
+        // First, do a check with a read-lock.
+        loop {
+            match self.probe(db, self.state.read(), runtime, revision_now) {
+                ProbeState::UpToDate(v) => return v,
+                ProbeState::Stale(..) | ProbeState::NoValue(..) | ProbeState::NotComputed(..) => {
+                    break
+                }
+                ProbeState::Retry => continue,
+            }
+        }
+
+        self.read_upgrade(db, revision_now)
+    }
+
+    /// Second phase of a read operation: acquires an upgradable-read
+    /// and -- if needed -- validates whether inputs have changed,
+    /// recomputes value, etc. This is invoked after our initial probe
+    /// shows a potentially out of date value.
+    fn read_upgrade(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        revision_now: Revision,
+    ) -> StampedValue<Q::Value> {
+        let runtime = db.salsa_runtime();
+
+        debug!("{:?}: read_upgrade(revision_now={:?})", self, revision_now,);
+
+        // Check with an upgradable read to see if there is a value
+        // already. (This permits other readers but prevents anyone
+        // else from running `read_upgrade` at the same time.)
+        let mut old_memo = loop {
+            match self.probe(db, self.state.upgradable_read(), runtime, revision_now) {
+                ProbeState::UpToDate(v) => return v,
+                ProbeState::Stale(state)
+                | ProbeState::NotComputed(state)
+                | ProbeState::NoValue(state, _) => {
+                    type RwLockUpgradableReadGuard<'a, T> =
+                        lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
+
+                    let mut state = RwLockUpgradableReadGuard::upgrade(state);
+                    match std::mem::replace(&mut *state, QueryState::in_progress(runtime.id())) {
+                        QueryState::Memoized(old_memo) => break Some(old_memo),
+                        QueryState::InProgress { .. } => unreachable!(),
+                        QueryState::NotComputed => break None,
+                    }
+                }
+                ProbeState::Retry => continue,
+            }
+        };
+
+        let panic_guard = PanicGuard::new(self.database_key_index, self, runtime);
+        let active_query = runtime.push_query(self.database_key_index);
+
+        // If we have an old-value, it *may* now be stale, since there
+        // has been a new revision since the last time we checked. So,
+        // first things first, let's walk over each of our previous
+        // inputs and check whether they are out of date.
+        if let Some(memo) = &mut old_memo {
+            if let Some(value) = memo.verify_value(db.ops_database(), revision_now, &active_query) {
+                info!("{:?}: validated old memoized value", self,);
+
+                db.salsa_event(Event {
+                    runtime_id: runtime.id(),
+                    kind: EventKind::DidValidateMemoizedValue {
+                        database_key: self.database_key_index,
+                    },
+                });
+
+                panic_guard.proceed(old_memo);
+
+                return value;
+            }
+        }
+
+        self.execute(db, runtime, revision_now, active_query, panic_guard, old_memo)
+    }
+
+    fn execute(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        runtime: &Runtime,
+        revision_now: Revision,
+        active_query: ActiveQueryGuard<'_>,
+        panic_guard: PanicGuard<'_, Q, MP>,
+        old_memo: Option<Memo<Q::Value>>,
+    ) -> StampedValue<Q::Value> {
+        tracing::info!("{:?}: executing query", self.database_key_index.debug(db));
+
+        db.salsa_event(Event {
+            runtime_id: db.salsa_runtime().id(),
+            kind: EventKind::WillExecute { database_key: self.database_key_index },
+        });
+
+        // Query was not previously executed, or value is potentially
+        // stale, or value is absent. Let's execute!
+        let value = match Cycle::catch(|| Q::execute(db, self.key.clone())) {
+            Ok(v) => v,
+            Err(cycle) => {
+                tracing::debug!(
+                    "{:?}: caught cycle {:?}, have strategy {:?}",
+                    self.database_key_index.debug(db),
+                    cycle,
+                    Q::CYCLE_STRATEGY,
+                );
+                match Q::CYCLE_STRATEGY {
+                    crate::plumbing::CycleRecoveryStrategy::Panic => {
+                        panic_guard.proceed(None);
+                        cycle.throw()
+                    }
+                    crate::plumbing::CycleRecoveryStrategy::Fallback => {
+                        if let Some(c) = active_query.take_cycle() {
+                            assert!(c.is(&cycle));
+                            Q::cycle_fallback(db, &cycle, &self.key)
+                        } else {
+                            // we are not a participant in this cycle
+                            debug_assert!(!cycle
+                                .participant_keys()
+                                .any(|k| k == self.database_key_index));
+                            cycle.throw()
+                        }
+                    }
+                }
+            }
+        };
+
+        let mut revisions = active_query.pop();
+
+        // We assume that query is side-effect free -- that is, does
+        // not mutate the "inputs" to the query system. Sanity check
+        // that assumption here, at least to the best of our ability.
+        assert_eq!(
+            runtime.current_revision(),
+            revision_now,
+            "revision altered during query execution",
+        );
+
+        // If the new value is equal to the old one, then it didn't
+        // really change, even if some of its inputs have. So we can
+        // "backdate" its `changed_at` revision to be the same as the
+        // old value.
+        if let Some(old_memo) = &old_memo {
+            if let Some(old_value) = &old_memo.value {
+                // Careful: if the value became less durable than it
+                // used to be, that is a "breaking change" that our
+                // consumers must be aware of. Becoming *more* durable
+                // is not. See the test `constant_to_non_constant`.
+                if revisions.durability >= old_memo.revisions.durability
+                    && MP::memoized_value_eq(old_value, &value)
+                {
+                    debug!(
+                        "read_upgrade({:?}): value is equal, back-dating to {:?}",
+                        self, old_memo.revisions.changed_at,
+                    );
+
+                    assert!(old_memo.revisions.changed_at <= revisions.changed_at);
+                    revisions.changed_at = old_memo.revisions.changed_at;
+                }
+            }
+        }
+
+        let new_value = StampedValue {
+            value,
+            durability: revisions.durability,
+            changed_at: revisions.changed_at,
+        };
+
+        let memo_value =
+            if self.should_memoize_value(&self.key) { Some(new_value.value.clone()) } else { None };
+
+        debug!("read_upgrade({:?}): result.revisions = {:#?}", self, revisions,);
+
+        panic_guard.proceed(Some(Memo { value: memo_value, verified_at: revision_now, revisions }));
+
+        new_value
+    }
+
+    /// Helper for `read` that does a shallow check (not recursive) if we have an up-to-date value.
+    ///
+    /// Invoked with the guard `state` corresponding to the `QueryState` of some `Slot` (the guard
+    /// can be either read or write). Returns a suitable `ProbeState`:
+    ///
+    /// - `ProbeState::UpToDate(r)` if the table has an up-to-date value (or we blocked on another
+    ///   thread that produced such a value).
+    /// - `ProbeState::StaleOrAbsent(g)` if either (a) there is no memo for this key, (b) the memo
+    ///   has no value; or (c) the memo has not been verified at the current revision.
+    ///
+    /// Note that in case `ProbeState::UpToDate`, the lock will have been released.
+    fn probe<StateGuard>(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        state: StateGuard,
+        runtime: &Runtime,
+        revision_now: Revision,
+    ) -> ProbeState<StampedValue<Q::Value>, StateGuard>
+    where
+        StateGuard: Deref<Target = QueryState<Q>>,
+    {
+        match &*state {
+            QueryState::NotComputed => ProbeState::NotComputed(state),
+
+            QueryState::InProgress { id, anyone_waiting } => {
+                let other_id = *id;
+
+                // NB: `Ordering::Relaxed` is sufficient here,
+                // as there are no loads that are "gated" on this
+                // value. Everything that is written is also protected
+                // by a lock that must be acquired. The role of this
+                // boolean is to decide *whether* to acquire the lock,
+                // not to gate future atomic reads.
+                anyone_waiting.store(true, Ordering::Relaxed);
+
+                self.block_on_or_unwind(db, runtime, other_id, state);
+
+                // Other thread completely normally, so our value may be available now.
+                ProbeState::Retry
+            }
+
+            QueryState::Memoized(memo) => {
+                debug!(
+                    "{:?}: found memoized value, verified_at={:?}, changed_at={:?}",
+                    self, memo.verified_at, memo.revisions.changed_at,
+                );
+
+                if memo.verified_at < revision_now {
+                    return ProbeState::Stale(state);
+                }
+
+                if let Some(value) = &memo.value {
+                    let value = StampedValue {
+                        durability: memo.revisions.durability,
+                        changed_at: memo.revisions.changed_at,
+                        value: value.clone(),
+                    };
+
+                    info!("{:?}: returning memoized value changed at {:?}", self, value.changed_at);
+
+                    ProbeState::UpToDate(value)
+                } else {
+                    let changed_at = memo.revisions.changed_at;
+                    ProbeState::NoValue(state, changed_at)
+                }
+            }
+        }
+    }
+
+    pub(super) fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb) -> Durability {
+        match &*self.state.read() {
+            QueryState::NotComputed => Durability::LOW,
+            QueryState::InProgress { .. } => panic!("query in progress"),
+            QueryState::Memoized(memo) => {
+                if memo.check_durability(db.salsa_runtime()) {
+                    memo.revisions.durability
+                } else {
+                    Durability::LOW
+                }
+            }
+        }
+    }
+
+    pub(super) fn as_table_entry(&self) -> Option<TableEntry<Q::Key, Q::Value>> {
+        match &*self.state.read() {
+            QueryState::NotComputed => None,
+            QueryState::InProgress { .. } => Some(TableEntry::new(self.key.clone(), None)),
+            QueryState::Memoized(memo) => {
+                Some(TableEntry::new(self.key.clone(), memo.value.clone()))
+            }
+        }
+    }
+
+    pub(super) fn evict(&self) {
+        let mut state = self.state.write();
+        if let QueryState::Memoized(memo) = &mut *state {
+            // Evicting a value with an untracked input could
+            // lead to inconsistencies. Note that we can't check
+            // `has_untracked_input` when we add the value to the cache,
+            // because inputs can become untracked in the next revision.
+            if memo.has_untracked_input() {
+                return;
+            }
+            memo.value = None;
+        }
+    }
+
+    pub(super) fn invalidate(&self, new_revision: Revision) -> Option<Durability> {
+        tracing::debug!("Slot::invalidate(new_revision = {:?})", new_revision);
+        match &mut *self.state.write() {
+            QueryState::Memoized(memo) => {
+                memo.revisions.inputs = QueryInputs::Untracked;
+                memo.revisions.changed_at = new_revision;
+                Some(memo.revisions.durability)
+            }
+            QueryState::NotComputed => None,
+            QueryState::InProgress { .. } => unreachable!(),
+        }
+    }
+
+    pub(super) fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        revision: Revision,
+    ) -> bool {
+        let runtime = db.salsa_runtime();
+        let revision_now = runtime.current_revision();
+
+        db.unwind_if_cancelled();
+
+        debug!(
+            "maybe_changed_after({:?}) called with revision={:?}, revision_now={:?}",
+            self, revision, revision_now,
+        );
+
+        // Do an initial probe with just the read-lock.
+        //
+        // If we find that a cache entry for the value is present
+        // but hasn't been verified in this revision, we'll have to
+        // do more.
+        loop {
+            match self.maybe_changed_after_probe(db, self.state.read(), runtime, revision_now) {
+                MaybeChangedSinceProbeState::Retry => continue,
+                MaybeChangedSinceProbeState::ChangedAt(changed_at) => return changed_at > revision,
+                MaybeChangedSinceProbeState::Stale(state) => {
+                    drop(state);
+                    return self.maybe_changed_after_upgrade(db, revision);
+                }
+            }
+        }
+    }
+
+    fn maybe_changed_after_probe<StateGuard>(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        state: StateGuard,
+        runtime: &Runtime,
+        revision_now: Revision,
+    ) -> MaybeChangedSinceProbeState<StateGuard>
+    where
+        StateGuard: Deref<Target = QueryState<Q>>,
+    {
+        match self.probe(db, state, runtime, revision_now) {
+            ProbeState::Retry => MaybeChangedSinceProbeState::Retry,
+
+            ProbeState::Stale(state) => MaybeChangedSinceProbeState::Stale(state),
+
+            // If we know when value last changed, we can return right away.
+            // Note that we don't need the actual value to be available.
+            ProbeState::NoValue(_, changed_at)
+            | ProbeState::UpToDate(StampedValue { value: _, durability: _, changed_at }) => {
+                MaybeChangedSinceProbeState::ChangedAt(changed_at)
+            }
+
+            // If we have nothing cached, then value may have changed.
+            ProbeState::NotComputed(_) => MaybeChangedSinceProbeState::ChangedAt(revision_now),
+        }
+    }
+
+    fn maybe_changed_after_upgrade(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        revision: Revision,
+    ) -> bool {
+        let runtime = db.salsa_runtime();
+        let revision_now = runtime.current_revision();
+
+        // Get an upgradable read lock, which permits other reads but no writers.
+        // Probe again. If the value is stale (needs to be verified), then upgrade
+        // to a write lock and swap it with InProgress while we work.
+        let mut old_memo = match self.maybe_changed_after_probe(
+            db,
+            self.state.upgradable_read(),
+            runtime,
+            revision_now,
+        ) {
+            MaybeChangedSinceProbeState::ChangedAt(changed_at) => return changed_at > revision,
+
+            // If another thread was active, then the cache line is going to be
+            // either verified or cleared out. Just recurse to figure out which.
+            // Note that we don't need an upgradable read.
+            MaybeChangedSinceProbeState::Retry => return self.maybe_changed_after(db, revision),
+
+            MaybeChangedSinceProbeState::Stale(state) => {
+                type RwLockUpgradableReadGuard<'a, T> =
+                    lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>;
+
+                let mut state = RwLockUpgradableReadGuard::upgrade(state);
+                match std::mem::replace(&mut *state, QueryState::in_progress(runtime.id())) {
+                    QueryState::Memoized(old_memo) => old_memo,
+                    QueryState::NotComputed | QueryState::InProgress { .. } => unreachable!(),
+                }
+            }
+        };
+
+        let panic_guard = PanicGuard::new(self.database_key_index, self, runtime);
+        let active_query = runtime.push_query(self.database_key_index);
+
+        if old_memo.verify_revisions(db.ops_database(), revision_now, &active_query) {
+            let maybe_changed = old_memo.revisions.changed_at > revision;
+            panic_guard.proceed(Some(old_memo));
+            maybe_changed
+        } else if old_memo.value.is_some() {
+            // We found that this memoized value may have changed
+            // but we have an old value. We can re-run the code and
+            // actually *check* if it has changed.
+            let StampedValue { changed_at, .. } =
+                self.execute(db, runtime, revision_now, active_query, panic_guard, Some(old_memo));
+            changed_at > revision
+        } else {
+            // We found that inputs to this memoized value may have chanced
+            // but we don't have an old value to compare against or re-use.
+            // No choice but to drop the memo and say that its value may have changed.
+            panic_guard.proceed(None);
+            true
+        }
+    }
+
+    /// Helper: see [`Runtime::try_block_on_or_unwind`].
+    fn block_on_or_unwind<MutexGuard>(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        runtime: &Runtime,
+        other_id: RuntimeId,
+        mutex_guard: MutexGuard,
+    ) {
+        runtime.block_on_or_unwind(
+            db.ops_database(),
+            self.database_key_index,
+            other_id,
+            mutex_guard,
+        )
+    }
+
+    fn should_memoize_value(&self, key: &Q::Key) -> bool {
+        MP::should_memoize_value(key)
+    }
+}
+
+impl<Q> QueryState<Q>
+where
+    Q: QueryFunction,
+{
+    fn in_progress(id: RuntimeId) -> Self {
+        QueryState::InProgress { id, anyone_waiting: Default::default() }
+    }
+}
+
+struct PanicGuard<'me, Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    database_key_index: DatabaseKeyIndex,
+    slot: &'me Slot<Q, MP>,
+    runtime: &'me Runtime,
+}
+
+impl<'me, Q, MP> PanicGuard<'me, Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn new(
+        database_key_index: DatabaseKeyIndex,
+        slot: &'me Slot<Q, MP>,
+        runtime: &'me Runtime,
+    ) -> Self {
+        Self { database_key_index, slot, runtime }
+    }
+
+    /// Indicates that we have concluded normally (without panicking).
+    /// If `opt_memo` is some, then this memo is installed as the new
+    /// memoized value. If `opt_memo` is `None`, then the slot is cleared
+    /// and has no value.
+    fn proceed(mut self, opt_memo: Option<Memo<Q::Value>>) {
+        self.overwrite_placeholder(WaitResult::Completed, opt_memo);
+        std::mem::forget(self)
+    }
+
+    /// Overwrites the `InProgress` placeholder for `key` that we
+    /// inserted; if others were blocked, waiting for us to finish,
+    /// then notify them.
+    fn overwrite_placeholder(&mut self, wait_result: WaitResult, opt_memo: Option<Memo<Q::Value>>) {
+        let mut write = self.slot.state.write();
+
+        let old_value = match opt_memo {
+            // Replace the `InProgress` marker that we installed with the new
+            // memo, thus releasing our unique access to this key.
+            Some(memo) => std::mem::replace(&mut *write, QueryState::Memoized(memo)),
+
+            // We had installed an `InProgress` marker, but we panicked before
+            // it could be removed. At this point, we therefore "own" unique
+            // access to our slot, so we can just remove the key.
+            None => std::mem::replace(&mut *write, QueryState::NotComputed),
+        };
+
+        match old_value {
+            QueryState::InProgress { id, anyone_waiting } => {
+                assert_eq!(id, self.runtime.id());
+
+                // NB: As noted on the `store`, `Ordering::Relaxed` is
+                // sufficient here. This boolean signals us on whether to
+                // acquire a mutex; the mutex will guarantee that all writes
+                // we are interested in are visible.
+                if anyone_waiting.load(Ordering::Relaxed) {
+                    self.runtime.unblock_queries_blocked_on(self.database_key_index, wait_result);
+                }
+            }
+            _ => panic!(
+                "\
+Unexpected panic during query evaluation, aborting the process.
+
+Please report this bug to https://github.com/salsa-rs/salsa/issues."
+            ),
+        }
+    }
+}
+
+impl<'me, Q, MP> Drop for PanicGuard<'me, Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn drop(&mut self) {
+        if std::thread::panicking() {
+            // We panicked before we could proceed and need to remove `key`.
+            self.overwrite_placeholder(WaitResult::Panicked, None)
+        } else {
+            // If no panic occurred, then panic guard ought to be
+            // "forgotten" and so this Drop code should never run.
+            panic!(".forget() was not called")
+        }
+    }
+}
+
+impl<V> Memo<V>
+where
+    V: Clone,
+{
+    /// Determines whether the value stored in this memo (if any) is still
+    /// valid in the current revision. If so, returns a stamped value.
+    ///
+    /// If needed, this will walk each dependency and
+    /// recursively invoke `maybe_changed_after`, which may in turn
+    /// re-execute the dependency. This can cause cycles to occur,
+    /// so the current query must be pushed onto the
+    /// stack to permit cycle detection and recovery: therefore,
+    /// takes the `active_query` argument as evidence.
+    fn verify_value(
+        &mut self,
+        db: &dyn Database,
+        revision_now: Revision,
+        active_query: &ActiveQueryGuard<'_>,
+    ) -> Option<StampedValue<V>> {
+        // If we don't have a memoized value, nothing to validate.
+        if self.value.is_none() {
+            return None;
+        }
+        if self.verify_revisions(db, revision_now, active_query) {
+            Some(StampedValue {
+                durability: self.revisions.durability,
+                changed_at: self.revisions.changed_at,
+                value: self.value.as_ref().unwrap().clone(),
+            })
+        } else {
+            None
+        }
+    }
+
+    /// Determines whether the value represented by this memo is still
+    /// valid in the current revision; note that the value itself is
+    /// not needed for this check. If needed, this will walk each
+    /// dependency and recursively invoke `maybe_changed_after`, which
+    /// may in turn re-execute the dependency. This can cause cycles to occur,
+    /// so the current query must be pushed onto the
+    /// stack to permit cycle detection and recovery: therefore,
+    /// takes the `active_query` argument as evidence.
+    fn verify_revisions(
+        &mut self,
+        db: &dyn Database,
+        revision_now: Revision,
+        _active_query: &ActiveQueryGuard<'_>,
+    ) -> bool {
+        assert!(self.verified_at != revision_now);
+        let verified_at = self.verified_at;
+
+        debug!(
+            "verify_revisions: verified_at={:?}, revision_now={:?}, inputs={:#?}",
+            verified_at, revision_now, self.revisions.inputs
+        );
+
+        if self.check_durability(db.salsa_runtime()) {
+            return self.mark_value_as_verified(revision_now);
+        }
+
+        match &self.revisions.inputs {
+            // We can't validate values that had untracked inputs; just have to
+            // re-execute.
+            QueryInputs::Untracked => {
+                return false;
+            }
+
+            QueryInputs::NoInputs => {}
+
+            // Check whether any of our inputs changed since the
+            // **last point where we were verified** (not since we
+            // last changed). This is important: if we have
+            // memoized values, then an input may have changed in
+            // revision R2, but we found that *our* value was the
+            // same regardless, so our change date is still
+            // R1. But our *verification* date will be R2, and we
+            // are only interested in finding out whether the
+            // input changed *again*.
+            QueryInputs::Tracked { inputs } => {
+                let changed_input =
+                    inputs.iter().find(|&&input| db.maybe_changed_after(input, verified_at));
+                if let Some(input) = changed_input {
+                    debug!("validate_memoized_value: `{:?}` may have changed", input);
+
+                    return false;
+                }
+            }
+        };
+
+        self.mark_value_as_verified(revision_now)
+    }
+
+    /// True if this memo is known not to have changed based on its durability.
+    fn check_durability(&self, runtime: &Runtime) -> bool {
+        let last_changed = runtime.last_changed_revision(self.revisions.durability);
+        debug!(
+            "check_durability(last_changed={:?} <= verified_at={:?}) = {:?}",
+            last_changed,
+            self.verified_at,
+            last_changed <= self.verified_at,
+        );
+        last_changed <= self.verified_at
+    }
+
+    fn mark_value_as_verified(&mut self, revision_now: Revision) -> bool {
+        self.verified_at = revision_now;
+        true
+    }
+
+    fn has_untracked_input(&self) -> bool {
+        matches!(self.revisions.inputs, QueryInputs::Untracked)
+    }
+}
+
+impl<Q, MP> std::fmt::Debug for Slot<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "{:?}({:?})", Q::default(), self.key)
+    }
+}
+
+impl<Q, MP> LruNode for Slot<Q, MP>
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+{
+    fn lru_index(&self) -> &LruIndex {
+        &self.lru_index
+    }
+}
+
+/// Check that `Slot<Q, MP>: Send + Sync` as long as
+/// `DB::DatabaseData: Send + Sync`, which in turn implies that
+/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
+#[allow(dead_code)]
+fn check_send_sync<Q, MP>()
+where
+    Q: QueryFunction,
+    MP: MemoizationPolicy<Q>,
+    Q::Key: Send + Sync,
+    Q::Value: Send + Sync,
+{
+    fn is_send_sync<T: Send + Sync>() {}
+    is_send_sync::<Slot<Q, MP>>();
+}
+
+/// Check that `Slot<Q, MP>: 'static` as long as
+/// `DB::DatabaseData: 'static`, which in turn implies that
+/// `Q::Key: 'static`, `Q::Value: 'static`.
+#[allow(dead_code)]
+fn check_static<Q, MP>()
+where
+    Q: QueryFunction + 'static,
+    MP: MemoizationPolicy<Q> + 'static,
+    Q::Key: 'static,
+    Q::Value: 'static,
+{
+    fn is_static<T: 'static>() {}
+    is_static::<Slot<Q, MP>>();
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/doctest.rs b/src/tools/rust-analyzer/crates/salsa/src/doctest.rs
new file mode 100644
index 00000000000..29a80663567
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/doctest.rs
@@ -0,0 +1,115 @@
+//!
+#![allow(dead_code)]
+
+/// Test that a database with a key/value that is not `Send` will,
+/// indeed, not be `Send`.
+///
+/// ```compile_fail,E0277
+/// use std::rc::Rc;
+///
+/// #[salsa::query_group(NoSendSyncStorage)]
+/// trait NoSendSyncDatabase: salsa::Database {
+///     fn no_send_sync_value(&self, key: bool) -> Rc<bool>;
+///     fn no_send_sync_key(&self, key: Rc<bool>) -> bool;
+/// }
+///
+/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Rc<bool> {
+///     Rc::new(key)
+/// }
+///
+/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Rc<bool>) -> bool {
+///     *key
+/// }
+///
+/// #[salsa::database(NoSendSyncStorage)]
+/// #[derive(Default)]
+/// struct DatabaseImpl {
+///     storage: salsa::Storage<Self>,
+/// }
+///
+/// impl salsa::Database for DatabaseImpl {
+/// }
+///
+/// fn is_send<T: Send>(_: T) { }
+///
+/// fn assert_send() {
+///    is_send(DatabaseImpl::default());
+/// }
+/// ```
+fn test_key_not_send_db_not_send() {}
+
+/// Test that a database with a key/value that is not `Sync` will not
+/// be `Send`.
+///
+/// ```compile_fail,E0277
+/// use std::rc::Rc;
+/// use std::cell::Cell;
+///
+/// #[salsa::query_group(NoSendSyncStorage)]
+/// trait NoSendSyncDatabase: salsa::Database {
+///     fn no_send_sync_value(&self, key: bool) -> Cell<bool>;
+///     fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
+/// }
+///
+/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
+///     Cell::new(key)
+/// }
+///
+/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
+///     *key
+/// }
+///
+/// #[salsa::database(NoSendSyncStorage)]
+/// #[derive(Default)]
+/// struct DatabaseImpl {
+///     runtime: salsa::Storage<Self>,
+/// }
+///
+/// impl salsa::Database for DatabaseImpl {
+/// }
+///
+/// fn is_send<T: Send>(_: T) { }
+///
+/// fn assert_send() {
+///    is_send(DatabaseImpl::default());
+/// }
+/// ```
+fn test_key_not_sync_db_not_send() {}
+
+/// Test that a database with a key/value that is not `Sync` will
+/// not be `Sync`.
+///
+/// ```compile_fail,E0277
+/// use std::cell::Cell;
+/// use std::rc::Rc;
+///
+/// #[salsa::query_group(NoSendSyncStorage)]
+/// trait NoSendSyncDatabase: salsa::Database {
+///     fn no_send_sync_value(&self, key: bool) -> Cell<bool>;
+///     fn no_send_sync_key(&self, key: Cell<bool>) -> bool;
+/// }
+///
+/// fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Cell<bool> {
+///     Cell::new(key)
+/// }
+///
+/// fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Cell<bool>) -> bool {
+///     *key
+/// }
+///
+/// #[salsa::database(NoSendSyncStorage)]
+/// #[derive(Default)]
+/// struct DatabaseImpl {
+///     runtime: salsa::Storage<Self>,
+/// }
+///
+/// impl salsa::Database for DatabaseImpl {
+/// }
+///
+/// fn is_sync<T: Sync>(_: T) { }
+///
+/// fn assert_send() {
+///    is_sync(DatabaseImpl::default());
+/// }
+/// ```
+fn test_key_not_sync_db_not_sync() {}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/durability.rs b/src/tools/rust-analyzer/crates/salsa/src/durability.rs
new file mode 100644
index 00000000000..0c82f6345ab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/durability.rs
@@ -0,0 +1,50 @@
+//!
+/// Describes how likely a value is to change -- how "durable" it is.
+/// By default, inputs have `Durability::LOW` and interned values have
+/// `Durability::HIGH`. But inputs can be explicitly set with other
+/// durabilities.
+///
+/// We use durabilities to optimize the work of "revalidating" a query
+/// after some input has changed. Ordinarily, in a new revision,
+/// queries have to trace all their inputs back to the base inputs to
+/// determine if any of those inputs have changed. But if we know that
+/// the only changes were to inputs of low durability (the common
+/// case), and we know that the query only used inputs of medium
+/// durability or higher, then we can skip that enumeration.
+///
+/// Typically, one assigns low durabilites to inputs that the user is
+/// frequently editing. Medium or high durabilities are used for
+/// configuration, the source from library crates, or other things
+/// that are unlikely to be edited.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+pub struct Durability(u8);
+
+impl Durability {
+    /// Low durability: things that change frequently.
+    ///
+    /// Example: part of the crate being edited
+    pub const LOW: Durability = Durability(0);
+
+    /// Medium durability: things that change sometimes, but rarely.
+    ///
+    /// Example: a Cargo.toml file
+    pub const MEDIUM: Durability = Durability(1);
+
+    /// High durability: things that are not expected to change under
+    /// common usage.
+    ///
+    /// Example: the standard library or something from crates.io
+    pub const HIGH: Durability = Durability(2);
+
+    /// The maximum possible durability; equivalent to HIGH but
+    /// "conceptually" distinct (i.e., if we add more durability
+    /// levels, this could change).
+    pub(crate) const MAX: Durability = Self::HIGH;
+
+    /// Number of durability levels.
+    pub(crate) const LEN: usize = 3;
+
+    pub(crate) fn index(self) -> usize {
+        self.0 as usize
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/hash.rs b/src/tools/rust-analyzer/crates/salsa/src/hash.rs
new file mode 100644
index 00000000000..47a2dd1ce0c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/hash.rs
@@ -0,0 +1,4 @@
+//!
+pub(crate) type FxHasher = std::hash::BuildHasherDefault<rustc_hash::FxHasher>;
+pub(crate) type FxIndexSet<K> = indexmap::IndexSet<K, FxHasher>;
+pub(crate) type FxIndexMap<K, V> = indexmap::IndexMap<K, V, FxHasher>;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/input.rs b/src/tools/rust-analyzer/crates/salsa/src/input.rs
new file mode 100644
index 00000000000..4e8fca6149b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/input.rs
@@ -0,0 +1,384 @@
+//!
+use crate::debug::TableEntry;
+use crate::durability::Durability;
+use crate::hash::FxIndexMap;
+use crate::plumbing::CycleRecoveryStrategy;
+use crate::plumbing::InputQueryStorageOps;
+use crate::plumbing::QueryStorageMassOps;
+use crate::plumbing::QueryStorageOps;
+use crate::revision::Revision;
+use crate::runtime::StampedValue;
+use crate::Database;
+use crate::Query;
+use crate::Runtime;
+use crate::{DatabaseKeyIndex, QueryDb};
+use indexmap::map::Entry;
+use parking_lot::RwLock;
+use std::convert::TryFrom;
+use std::iter;
+use tracing::debug;
+
+/// Input queries store the result plus a list of the other queries
+/// that they invoked. This means we can avoid recomputing them when
+/// none of those inputs have changed.
+pub struct InputStorage<Q>
+where
+    Q: Query,
+{
+    group_index: u16,
+    slots: RwLock<FxIndexMap<Q::Key, Slot<Q::Value>>>,
+}
+
+struct Slot<V> {
+    database_key_index: DatabaseKeyIndex,
+    stamped_value: RwLock<StampedValue<V>>,
+}
+
+impl<Q> std::panic::RefUnwindSafe for InputStorage<Q>
+where
+    Q: Query,
+    Q::Key: std::panic::RefUnwindSafe,
+    Q::Value: std::panic::RefUnwindSafe,
+{
+}
+
+impl<Q> QueryStorageOps<Q> for InputStorage<Q>
+where
+    Q: Query,
+{
+    const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
+
+    fn new(group_index: u16) -> Self {
+        InputStorage { group_index, slots: Default::default() }
+    }
+
+    fn fmt_index(
+        &self,
+        _db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        assert_eq!(index.group_index, self.group_index);
+        assert_eq!(index.query_index, Q::QUERY_INDEX);
+        let slot_map = self.slots.read();
+        let key = slot_map.get_index(index.key_index as usize).unwrap().0;
+        write!(fmt, "{}({:?})", Q::QUERY_NAME, key)
+    }
+
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool {
+        assert_eq!(input.group_index, self.group_index);
+        assert_eq!(input.query_index, Q::QUERY_INDEX);
+        debug_assert!(revision < db.salsa_runtime().current_revision());
+        let slots = &self.slots.read();
+        let slot = slots.get_index(input.key_index as usize).unwrap().1;
+
+        debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,);
+
+        let changed_at = slot.stamped_value.read().changed_at;
+
+        debug!("maybe_changed_after: changed_at = {:?}", changed_at);
+
+        changed_at > revision
+    }
+
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
+        db.unwind_if_cancelled();
+
+        let slots = &self.slots.read();
+        let slot = slots
+            .get(key)
+            .unwrap_or_else(|| panic!("no value set for {:?}({:?})", Q::default(), key));
+
+        let StampedValue { value, durability, changed_at } = slot.stamped_value.read().clone();
+
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            slot.database_key_index,
+            durability,
+            changed_at,
+        );
+
+        value
+    }
+
+    fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability {
+        match self.slots.read().get(key) {
+            Some(slot) => slot.stamped_value.read().durability,
+            None => panic!("no value set for {:?}({:?})", Q::default(), key),
+        }
+    }
+
+    fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
+    {
+        let slots = self.slots.read();
+        slots
+            .iter()
+            .map(|(key, slot)| {
+                TableEntry::new(key.clone(), Some(slot.stamped_value.read().value.clone()))
+            })
+            .collect()
+    }
+}
+
+impl<Q> QueryStorageMassOps for InputStorage<Q>
+where
+    Q: Query,
+{
+    fn purge(&self) {
+        *self.slots.write() = Default::default();
+    }
+}
+
+impl<Q> InputQueryStorageOps<Q> for InputStorage<Q>
+where
+    Q: Query,
+{
+    fn set(&self, runtime: &mut Runtime, key: &Q::Key, value: Q::Value, durability: Durability) {
+        tracing::debug!("{:?}({:?}) = {:?} ({:?})", Q::default(), key, value, durability);
+
+        // The value is changing, so we need a new revision (*). We also
+        // need to update the 'last changed' revision by invoking
+        // `guard.mark_durability_as_changed`.
+        //
+        // CAREFUL: This will block until the global revision lock can
+        // be acquired. If there are still queries executing, they may
+        // need to read from this input. Therefore, we wait to acquire
+        // the lock on `map` until we also hold the global query write
+        // lock.
+        //
+        // (*) Technically, since you can't presently access an input
+        // for a non-existent key, and you can't enumerate the set of
+        // keys, we only need a new revision if the key used to
+        // exist. But we may add such methods in the future and this
+        // case doesn't generally seem worth optimizing for.
+        runtime.with_incremented_revision(|next_revision| {
+            let mut slots = self.slots.write();
+
+            // Do this *after* we acquire the lock, so that we are not
+            // racing with somebody else to modify this same cell.
+            // (Otherwise, someone else might write a *newer* revision
+            // into the same cell while we block on the lock.)
+            let stamped_value = StampedValue { value, durability, changed_at: next_revision };
+
+            match slots.entry(key.clone()) {
+                Entry::Occupied(entry) => {
+                    let mut slot_stamped_value = entry.get().stamped_value.write();
+                    let old_durability = slot_stamped_value.durability;
+                    *slot_stamped_value = stamped_value;
+                    Some(old_durability)
+                }
+
+                Entry::Vacant(entry) => {
+                    let key_index = u32::try_from(entry.index()).unwrap();
+                    let database_key_index = DatabaseKeyIndex {
+                        group_index: self.group_index,
+                        query_index: Q::QUERY_INDEX,
+                        key_index,
+                    };
+                    entry.insert(Slot {
+                        database_key_index,
+                        stamped_value: RwLock::new(stamped_value),
+                    });
+                    None
+                }
+            }
+        });
+    }
+}
+
+/// Same as `InputStorage`, but optimized for queries that take no inputs.
+pub struct UnitInputStorage<Q>
+where
+    Q: Query<Key = ()>,
+{
+    group_index: u16,
+    slot: UnitSlot<Q::Value>,
+}
+
+struct UnitSlot<V> {
+    database_key_index: DatabaseKeyIndex,
+    stamped_value: RwLock<Option<StampedValue<V>>>,
+}
+
+impl<Q> std::panic::RefUnwindSafe for UnitInputStorage<Q>
+where
+    Q: Query<Key = ()>,
+    Q::Key: std::panic::RefUnwindSafe,
+    Q::Value: std::panic::RefUnwindSafe,
+{
+}
+
+impl<Q> QueryStorageOps<Q> for UnitInputStorage<Q>
+where
+    Q: Query<Key = ()>,
+{
+    const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
+
+    fn new(group_index: u16) -> Self {
+        let database_key_index =
+            DatabaseKeyIndex { group_index, query_index: Q::QUERY_INDEX, key_index: 0 };
+        UnitInputStorage {
+            group_index,
+            slot: UnitSlot { database_key_index, stamped_value: RwLock::new(None) },
+        }
+    }
+
+    fn fmt_index(
+        &self,
+        _db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        assert_eq!(index.group_index, self.group_index);
+        assert_eq!(index.query_index, Q::QUERY_INDEX);
+        write!(fmt, "{}", Q::QUERY_NAME)
+    }
+
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool {
+        assert_eq!(input.group_index, self.group_index);
+        assert_eq!(input.query_index, Q::QUERY_INDEX);
+        debug_assert!(revision < db.salsa_runtime().current_revision());
+
+        debug!("maybe_changed_after(slot={:?}, revision={:?})", Q::default(), revision,);
+
+        let changed_at = self.slot.stamped_value.read().as_ref().unwrap().changed_at;
+
+        debug!("maybe_changed_after: changed_at = {:?}", changed_at);
+
+        changed_at > revision
+    }
+
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, &(): &Q::Key) -> Q::Value {
+        db.unwind_if_cancelled();
+
+        let StampedValue { value, durability, changed_at } = self
+            .slot
+            .stamped_value
+            .read()
+            .clone()
+            .unwrap_or_else(|| panic!("no value set for {:?}", Q::default()));
+
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            self.slot.database_key_index,
+            durability,
+            changed_at,
+        );
+
+        value
+    }
+
+    fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, &(): &Q::Key) -> Durability {
+        match &*self.slot.stamped_value.read() {
+            Some(stamped_value) => stamped_value.durability,
+            None => panic!("no value set for {:?}", Q::default(),),
+        }
+    }
+
+    fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
+    {
+        iter::once(TableEntry::new(
+            (),
+            self.slot.stamped_value.read().as_ref().map(|it| it.value.clone()),
+        ))
+        .collect()
+    }
+}
+
+impl<Q> QueryStorageMassOps for UnitInputStorage<Q>
+where
+    Q: Query<Key = ()>,
+{
+    fn purge(&self) {
+        *self.slot.stamped_value.write() = Default::default();
+    }
+}
+
+impl<Q> InputQueryStorageOps<Q> for UnitInputStorage<Q>
+where
+    Q: Query<Key = ()>,
+{
+    fn set(&self, runtime: &mut Runtime, (): &Q::Key, value: Q::Value, durability: Durability) {
+        tracing::debug!("{:?} = {:?} ({:?})", Q::default(), value, durability);
+
+        // The value is changing, so we need a new revision (*). We also
+        // need to update the 'last changed' revision by invoking
+        // `guard.mark_durability_as_changed`.
+        //
+        // CAREFUL: This will block until the global revision lock can
+        // be acquired. If there are still queries executing, they may
+        // need to read from this input. Therefore, we wait to acquire
+        // the lock on `map` until we also hold the global query write
+        // lock.
+        //
+        // (*) Technically, since you can't presently access an input
+        // for a non-existent key, and you can't enumerate the set of
+        // keys, we only need a new revision if the key used to
+        // exist. But we may add such methods in the future and this
+        // case doesn't generally seem worth optimizing for.
+        runtime.with_incremented_revision(|next_revision| {
+            let mut stamped_value_slot = self.slot.stamped_value.write();
+
+            // Do this *after* we acquire the lock, so that we are not
+            // racing with somebody else to modify this same cell.
+            // (Otherwise, someone else might write a *newer* revision
+            // into the same cell while we block on the lock.)
+            let stamped_value = StampedValue { value, durability, changed_at: next_revision };
+
+            match &mut *stamped_value_slot {
+                Some(slot_stamped_value) => {
+                    let old_durability = slot_stamped_value.durability;
+                    *slot_stamped_value = stamped_value;
+                    Some(old_durability)
+                }
+
+                stamped_value_slot @ None => {
+                    *stamped_value_slot = Some(stamped_value);
+                    None
+                }
+            }
+        });
+    }
+}
+
+/// Check that `Slot<Q, MP>: Send + Sync` as long as
+/// `DB::DatabaseData: Send + Sync`, which in turn implies that
+/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
+#[allow(dead_code)]
+fn check_send_sync<Q>()
+where
+    Q: Query,
+    Q::Key: Send + Sync,
+    Q::Value: Send + Sync,
+{
+    fn is_send_sync<T: Send + Sync>() {}
+    is_send_sync::<Slot<Q::Value>>();
+    is_send_sync::<UnitSlot<Q::Value>>();
+}
+
+/// Check that `Slot<Q, MP>: 'static` as long as
+/// `DB::DatabaseData: 'static`, which in turn implies that
+/// `Q::Key: 'static`, `Q::Value: 'static`.
+#[allow(dead_code)]
+fn check_static<Q>()
+where
+    Q: Query + 'static,
+    Q::Key: 'static,
+    Q::Value: 'static,
+{
+    fn is_static<T: 'static>() {}
+    is_static::<Slot<Q::Value>>();
+    is_static::<UnitSlot<Q::Value>>();
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/intern_id.rs b/src/tools/rust-analyzer/crates/salsa/src/intern_id.rs
new file mode 100644
index 00000000000..a7bbc088f9c
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/intern_id.rs
@@ -0,0 +1,131 @@
+//!
+use std::fmt;
+use std::num::NonZeroU32;
+
+/// The "raw-id" is used for interned keys in salsa -- it is basically
+/// a newtype'd u32. Typically, it is wrapped in a type of your own
+/// devising. For more information about interned keys, see [the
+/// interned key RFC][rfc].
+///
+/// # Creating a `InternId`
+//
+/// InternId values can be constructed using the `From` impls,
+/// which are implemented for `u32` and `usize`:
+///
+/// ```
+/// # use salsa::InternId;
+/// let intern_id1 = InternId::from(22_u32);
+/// let intern_id2 = InternId::from(22_usize);
+/// assert_eq!(intern_id1, intern_id2);
+/// ```
+///
+/// # Converting to a u32 or usize
+///
+/// Normally, there should be no need to access the underlying integer
+/// in a `InternId`. But if you do need to do so, you can convert to a
+/// `usize` using the `as_u32` or `as_usize` methods or the `From` impls.
+///
+/// ```
+/// # use salsa::InternId;
+/// let intern_id = InternId::from(22_u32);
+/// let value = u32::from(intern_id);
+/// assert_eq!(value, 22);
+/// ```
+///
+/// ## Illegal values
+///
+/// Be warned, however, that `InternId` values cannot be created from
+/// *arbitrary* values -- in particular large values greater than
+/// `InternId::MAX` will panic. Those large values are reserved so that
+/// the Rust compiler can use them as sentinel values, which means
+/// that (for example) `Option<InternId>` is represented in a single
+/// word.
+///
+/// ```should_panic
+/// # use salsa::InternId;
+/// InternId::from(InternId::MAX);
+/// ```
+///
+/// [rfc]: https://github.com/salsa-rs/salsa-rfcs/pull/2
+#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct InternId {
+    value: NonZeroU32,
+}
+
+impl InternId {
+    /// The maximum allowed `InternId`. This value can grow between
+    /// releases without affecting semver.
+    pub const MAX: u32 = 0xFFFF_FF00;
+
+    /// Creates a new InternId.
+    ///
+    /// # Safety
+    ///
+    /// `value` must be less than `MAX`
+    pub const unsafe fn new_unchecked(value: u32) -> Self {
+        debug_assert!(value < InternId::MAX);
+        InternId { value: NonZeroU32::new_unchecked(value + 1) }
+    }
+
+    /// Convert this raw-id into a u32 value.
+    ///
+    /// ```
+    /// # use salsa::InternId;
+    /// let intern_id = InternId::from(22_u32);
+    /// let value = intern_id.as_usize();
+    /// assert_eq!(value, 22);
+    /// ```
+    pub fn as_u32(self) -> u32 {
+        self.value.get() - 1
+    }
+
+    /// Convert this raw-id into a usize value.
+    ///
+    /// ```
+    /// # use salsa::InternId;
+    /// let intern_id = InternId::from(22_u32);
+    /// let value = intern_id.as_usize();
+    /// assert_eq!(value, 22);
+    /// ```
+    pub fn as_usize(self) -> usize {
+        self.as_u32() as usize
+    }
+}
+
+impl From<InternId> for u32 {
+    fn from(raw: InternId) -> u32 {
+        raw.as_u32()
+    }
+}
+
+impl From<InternId> for usize {
+    fn from(raw: InternId) -> usize {
+        raw.as_usize()
+    }
+}
+
+impl From<u32> for InternId {
+    fn from(id: u32) -> InternId {
+        assert!(id < InternId::MAX);
+        unsafe { InternId::new_unchecked(id) }
+    }
+}
+
+impl From<usize> for InternId {
+    fn from(id: usize) -> InternId {
+        assert!(id < (InternId::MAX as usize));
+        unsafe { InternId::new_unchecked(id as u32) }
+    }
+}
+
+impl fmt::Debug for InternId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_usize().fmt(f)
+    }
+}
+
+impl fmt::Display for InternId {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        self.as_usize().fmt(f)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/interned.rs b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
new file mode 100644
index 00000000000..731839e9598
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/interned.rs
@@ -0,0 +1,508 @@
+//!
+use crate::debug::TableEntry;
+use crate::durability::Durability;
+use crate::intern_id::InternId;
+use crate::plumbing::CycleRecoveryStrategy;
+use crate::plumbing::HasQueryGroup;
+use crate::plumbing::QueryStorageMassOps;
+use crate::plumbing::QueryStorageOps;
+use crate::revision::Revision;
+use crate::Query;
+use crate::QueryTable;
+use crate::{Database, DatabaseKeyIndex, QueryDb};
+use parking_lot::RwLock;
+use rustc_hash::FxHashMap;
+use std::collections::hash_map::Entry;
+use std::convert::From;
+use std::fmt::Debug;
+use std::hash::Hash;
+use triomphe::Arc;
+
+const INTERN_DURABILITY: Durability = Durability::HIGH;
+
+/// Handles storage where the value is 'derived' by executing a
+/// function (in contrast to "inputs").
+pub struct InternedStorage<Q>
+where
+    Q: Query,
+    Q::Key: InternValue,
+    Q::Value: InternKey,
+{
+    group_index: u16,
+    tables: RwLock<InternTables<MappedKey<Q>, Q::Key>>,
+}
+
+/// Storage for the looking up interned things.
+pub struct LookupInternedStorage<Q, IQ>
+where
+    Q: Query,
+    Q::Key: InternKey,
+    Q::Value: InternValue,
+{
+    phantom: std::marker::PhantomData<(Q::Key, IQ)>,
+}
+
+struct InternTables<K, V> {
+    /// Map from the key to the corresponding intern-index.
+    map: FxHashMap<K, InternId>,
+
+    /// For each valid intern-index, stores the interned value.
+    values: Vec<Arc<Slot<V>>>,
+}
+
+/// Trait implemented for the "key" that results from a
+/// `#[salsa::intern]` query.  This is basically meant to be a
+/// "newtype"'d `u32`.
+pub trait InternKey {
+    /// Create an instance of the intern-key from a `u32` value.
+    fn from_intern_id(v: InternId) -> Self;
+
+    /// Extract the `u32` with which the intern-key was created.
+    fn as_intern_id(&self) -> InternId;
+}
+
+impl InternKey for InternId {
+    fn from_intern_id(v: InternId) -> InternId {
+        v
+    }
+
+    fn as_intern_id(&self) -> InternId {
+        *self
+    }
+}
+
+/// Trait implemented for the "value" that is being interned.
+pub trait InternValue {
+    /// They key used to intern this value by.
+    type Key: Eq + Hash + Debug + Clone;
+    /// Maps the value to a key that will be used to intern it.
+    fn into_key(&self) -> Self::Key;
+    /// Calls the given function with the key that was used to intern this value.
+    ///
+    /// This is mainly used to prevent frequent cloning of the key when doing a lookup.
+    #[inline]
+    fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
+        f(&self.into_key())
+    }
+}
+
+impl<A: InternValue + Eq + Hash + Debug + Clone, B: InternValue + Eq + Hash + Debug + Clone>
+    InternValue for (A, B)
+{
+    type Key = Self;
+    #[inline]
+    fn into_key(&self) -> Self::Key {
+        self.clone()
+    }
+    #[inline]
+    fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
+        f(self)
+    }
+}
+
+/// Implement [`InternValue`] trivially, that is without actually mapping at all.
+#[macro_export]
+macro_rules! impl_intern_value_trivial {
+    ($($ty:ty),*) => {
+        $(
+            impl $crate::InternValue for $ty {
+                type Key = $ty;
+                #[inline]
+                fn into_key(&self) -> Self::Key {
+                    self.clone()
+                }
+                #[inline]
+                fn with_key<F: FnOnce(&Self::Key) -> T, T>(&self, f: F) -> T {
+                    f(self)
+                }
+            }
+        )*
+    };
+}
+impl_intern_value_trivial!(String);
+#[derive(Debug)]
+struct Slot<V> {
+    /// DatabaseKeyIndex for this slot.
+    database_key_index: DatabaseKeyIndex,
+
+    /// Value that was interned.
+    value: V,
+
+    /// When was this intern'd?
+    ///
+    /// (This informs the "changed-at" result)
+    interned_at: Revision,
+}
+
+impl<Q> std::panic::RefUnwindSafe for InternedStorage<Q>
+where
+    Q: Query,
+    Q::Key: InternValue,
+    Q::Key: std::panic::RefUnwindSafe,
+    Q::Value: InternKey,
+    Q::Value: std::panic::RefUnwindSafe,
+{
+}
+
+impl<K: Debug + Hash + Eq, V> InternTables<K, V> {
+    /// Returns the slot for the given key.
+    fn slot_for_key(&self, key: &K) -> Option<(Arc<Slot<V>>, InternId)> {
+        let &index = self.map.get(key)?;
+        Some((self.slot_for_index(index), index))
+    }
+
+    /// Returns the slot at the given index.
+    fn slot_for_index(&self, index: InternId) -> Arc<Slot<V>> {
+        let slot = &self.values[index.as_usize()];
+        slot.clone()
+    }
+}
+
+impl<K, V> Default for InternTables<K, V>
+where
+    K: Eq + Hash,
+{
+    fn default() -> Self {
+        Self { map: Default::default(), values: Default::default() }
+    }
+}
+
+type MappedKey<Q> = <<Q as Query>::Key as InternValue>::Key;
+
+impl<Q> InternedStorage<Q>
+where
+    Q: Query,
+    Q::Key: InternValue,
+    Q::Value: InternKey,
+{
+    /// Creates a new slot.
+    fn intern_index(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        mapped_key: MappedKey<Q>,
+        insert: impl FnOnce(Q::Value) -> Q::Key,
+    ) -> (Arc<Slot<Q::Key>>, InternId) {
+        let revision_now = db.salsa_runtime().current_revision();
+
+        let mut tables = self.tables.write();
+        let tables = &mut *tables;
+        let entry = match tables.map.entry(mapped_key) {
+            Entry::Vacant(entry) => entry,
+            Entry::Occupied(entry) => {
+                // Somebody inserted this key while we were waiting
+                // for the write lock. In this case, we don't need to
+                // update the `accessed_at` field because they should
+                // have already done so!
+                let index = *entry.get();
+                let slot = &tables.values[index.as_usize()];
+                return (slot.clone(), index);
+            }
+        };
+
+        let create_slot = |index: InternId| {
+            let database_key_index = DatabaseKeyIndex {
+                group_index: self.group_index,
+                query_index: Q::QUERY_INDEX,
+                key_index: index.as_u32(),
+            };
+            Arc::new(Slot {
+                database_key_index,
+                value: insert(Q::Value::from_intern_id(index)),
+                interned_at: revision_now,
+            })
+        };
+
+        let index = InternId::from(tables.values.len());
+        let slot = create_slot(index);
+        tables.values.push(slot.clone());
+        entry.insert(index);
+
+        (slot, index)
+    }
+
+    fn intern_check(&self, key: &MappedKey<Q>) -> Option<(Arc<Slot<Q::Key>>, InternId)> {
+        self.tables.read().slot_for_key(key)
+    }
+
+    /// Given an index, lookup and clone its value, updating the
+    /// `accessed_at` time if necessary.
+    fn lookup_value(&self, index: InternId) -> Arc<Slot<Q::Key>> {
+        self.tables.read().slot_for_index(index)
+    }
+
+    fn fetch_or_insert(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        key: MappedKey<Q>,
+        insert: impl FnOnce(Q::Value) -> Q::Key,
+    ) -> Q::Value {
+        db.unwind_if_cancelled();
+        let (slot, index) = match self.intern_check(&key) {
+            Some(i) => i,
+            None => self.intern_index(db, key, insert),
+        };
+        let changed_at = slot.interned_at;
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            slot.database_key_index,
+            INTERN_DURABILITY,
+            changed_at,
+        );
+        <Q::Value>::from_intern_id(index)
+    }
+}
+
+impl<Q> QueryStorageOps<Q> for InternedStorage<Q>
+where
+    Q: Query,
+    Q::Key: InternValue,
+    Q::Value: InternKey,
+{
+    const CYCLE_STRATEGY: crate::plumbing::CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
+
+    fn new(group_index: u16) -> Self {
+        InternedStorage { group_index, tables: RwLock::new(InternTables::default()) }
+    }
+
+    fn fmt_index(
+        &self,
+        _db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        assert_eq!(index.group_index, self.group_index);
+        assert_eq!(index.query_index, Q::QUERY_INDEX);
+        let intern_id = InternId::from(index.key_index);
+        let slot = self.lookup_value(intern_id);
+        write!(fmt, "{}({:?})", Q::QUERY_NAME, slot.value)
+    }
+
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool {
+        assert_eq!(input.group_index, self.group_index);
+        assert_eq!(input.query_index, Q::QUERY_INDEX);
+        debug_assert!(revision < db.salsa_runtime().current_revision());
+        let intern_id = InternId::from(input.key_index);
+        let slot = self.lookup_value(intern_id);
+        slot.maybe_changed_after(revision)
+    }
+
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
+        db.unwind_if_cancelled();
+
+        let (slot, index) = match key.with_key(|key| self.intern_check(key)) {
+            Some(i) => i,
+            None => self.intern_index(db, key.into_key(), |_| key.clone()),
+        };
+        let changed_at = slot.interned_at;
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            slot.database_key_index,
+            INTERN_DURABILITY,
+            changed_at,
+        );
+        <Q::Value>::from_intern_id(index)
+    }
+
+    fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, _key: &Q::Key) -> Durability {
+        INTERN_DURABILITY
+    }
+
+    fn entries<C>(&self, _db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
+    {
+        let tables = self.tables.read();
+        tables
+            .map
+            .values()
+            .map(|index| {
+                TableEntry::new(
+                    tables.values[index.as_usize()].value.clone(),
+                    Some(<Q::Value>::from_intern_id(*index)),
+                )
+            })
+            .collect()
+    }
+}
+
+impl<Q> QueryStorageMassOps for InternedStorage<Q>
+where
+    Q: Query,
+    Q::Key: InternValue,
+    Q::Value: InternKey,
+{
+    fn purge(&self) {
+        *self.tables.write() = Default::default();
+    }
+}
+
+// Workaround for
+// ```
+// IQ: for<'d> QueryDb<
+//     'd,
+//     DynDb = <Q as QueryDb<'d>>::DynDb,
+//     Group = <Q as QueryDb<'d>>::Group,
+//     GroupStorage = <Q as QueryDb<'d>>::GroupStorage,
+// >,
+// ```
+// not working to make rustc know DynDb, Group and GroupStorage being the same in `Q` and `IQ`
+#[doc(hidden)]
+pub trait EqualDynDb<'d, IQ>: QueryDb<'d>
+where
+    IQ: QueryDb<'d>,
+{
+    fn convert_db(d: &Self::DynDb) -> &IQ::DynDb;
+    fn convert_group_storage(d: &Self::GroupStorage) -> &IQ::GroupStorage;
+}
+
+impl<'d, IQ, Q> EqualDynDb<'d, IQ> for Q
+where
+    Q: QueryDb<'d, DynDb = IQ::DynDb, Group = IQ::Group, GroupStorage = IQ::GroupStorage>,
+    Q::DynDb: HasQueryGroup<Q::Group>,
+    IQ: QueryDb<'d>,
+{
+    fn convert_db(d: &Self::DynDb) -> &IQ::DynDb {
+        d
+    }
+    fn convert_group_storage(d: &Self::GroupStorage) -> &IQ::GroupStorage {
+        d
+    }
+}
+
+impl<Q, IQ> QueryStorageOps<Q> for LookupInternedStorage<Q, IQ>
+where
+    Q: Query,
+    Q::Key: InternKey,
+    Q::Value: InternValue,
+    IQ: Query<Key = Q::Value, Value = Q::Key, Storage = InternedStorage<IQ>>,
+    for<'d> Q: EqualDynDb<'d, IQ>,
+{
+    const CYCLE_STRATEGY: CycleRecoveryStrategy = CycleRecoveryStrategy::Panic;
+
+    fn new(_group_index: u16) -> Self {
+        LookupInternedStorage { phantom: std::marker::PhantomData }
+    }
+
+    fn fmt_index(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result {
+        let group_storage =
+            <<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
+        let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
+        interned_storage.fmt_index(Q::convert_db(db), index, fmt)
+    }
+
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool {
+        let group_storage =
+            <<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
+        let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
+        interned_storage.maybe_changed_after(Q::convert_db(db), input, revision)
+    }
+
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value {
+        let index = key.as_intern_id();
+        let group_storage =
+            <<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
+        let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
+        let slot = interned_storage.lookup_value(index);
+        let value = slot.value.clone();
+        let interned_at = slot.interned_at;
+        db.salsa_runtime().report_query_read_and_unwind_if_cycle_resulted(
+            slot.database_key_index,
+            INTERN_DURABILITY,
+            interned_at,
+        );
+        value
+    }
+
+    fn durability(&self, _db: &<Q as QueryDb<'_>>::DynDb, _key: &Q::Key) -> Durability {
+        INTERN_DURABILITY
+    }
+
+    fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>,
+    {
+        let group_storage =
+            <<Q as QueryDb<'_>>::DynDb as HasQueryGroup<Q::Group>>::group_storage(db);
+        let interned_storage = IQ::query_storage(Q::convert_group_storage(group_storage));
+        let tables = interned_storage.tables.read();
+        tables
+            .map
+            .values()
+            .map(|index| {
+                TableEntry::new(
+                    <Q::Key>::from_intern_id(*index),
+                    Some(tables.values[index.as_usize()].value.clone()),
+                )
+            })
+            .collect()
+    }
+}
+
+impl<Q, IQ> QueryStorageMassOps for LookupInternedStorage<Q, IQ>
+where
+    Q: Query,
+    Q::Key: InternKey,
+    Q::Value: InternValue,
+    IQ: Query<Key = Q::Value, Value = Q::Key>,
+{
+    fn purge(&self) {}
+}
+
+impl<K> Slot<K> {
+    fn maybe_changed_after(&self, revision: Revision) -> bool {
+        self.interned_at > revision
+    }
+}
+
+/// Check that `Slot<Q, MP>: Send + Sync` as long as
+/// `DB::DatabaseData: Send + Sync`, which in turn implies that
+/// `Q::Key: Send + Sync`, `Q::Value: Send + Sync`.
+#[allow(dead_code)]
+fn check_send_sync<K>()
+where
+    K: Send + Sync,
+{
+    fn is_send_sync<T: Send + Sync>() {}
+    is_send_sync::<Slot<K>>();
+}
+
+/// Check that `Slot<Q, MP>: 'static` as long as
+/// `DB::DatabaseData: 'static`, which in turn implies that
+/// `Q::Key: 'static`, `Q::Value: 'static`.
+#[allow(dead_code)]
+fn check_static<K>()
+where
+    K: 'static,
+{
+    fn is_static<T: 'static>() {}
+    is_static::<Slot<K>>();
+}
+
+impl<'me, Q> QueryTable<'me, Q>
+where
+    Q: Query<Storage = InternedStorage<Q>>,
+    Q::Key: InternValue,
+    Q::Value: InternKey,
+{
+    /// Fetches the intern id for the given key or inserts it if it does not exist.
+    pub fn get_or_insert(
+        &self,
+        key: MappedKey<Q>,
+        insert: impl FnOnce(Q::Value) -> Q::Key,
+    ) -> Q::Value {
+        self.storage.fetch_or_insert(self.db, key, insert)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lib.rs b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
new file mode 100644
index 00000000000..2d58beafb2a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/lib.rs
@@ -0,0 +1,742 @@
+//!
+#![allow(clippy::type_complexity)]
+#![allow(clippy::question_mark)]
+#![warn(rust_2018_idioms)]
+#![warn(missing_docs)]
+
+//! The salsa crate is a crate for incremental recomputation.  It
+//! permits you to define a "database" of queries with both inputs and
+//! values derived from those inputs; as you set the inputs, you can
+//! re-execute the derived queries and it will try to re-use results
+//! from previous invocations as appropriate.
+
+mod derived;
+mod doctest;
+mod durability;
+mod hash;
+mod input;
+mod intern_id;
+mod interned;
+mod lru;
+mod revision;
+mod runtime;
+mod storage;
+
+pub mod debug;
+/// Items in this module are public for implementation reasons,
+/// and are exempt from the SemVer guarantees.
+#[doc(hidden)]
+pub mod plumbing;
+
+use crate::plumbing::CycleRecoveryStrategy;
+use crate::plumbing::DerivedQueryStorageOps;
+use crate::plumbing::InputQueryStorageOps;
+use crate::plumbing::LruQueryStorageOps;
+use crate::plumbing::QueryStorageMassOps;
+use crate::plumbing::QueryStorageOps;
+pub use crate::revision::Revision;
+use std::fmt::{self, Debug};
+use std::hash::Hash;
+use std::panic::AssertUnwindSafe;
+use std::panic::{self, UnwindSafe};
+
+pub use crate::durability::Durability;
+pub use crate::intern_id::InternId;
+pub use crate::interned::{InternKey, InternValue};
+pub use crate::runtime::Runtime;
+pub use crate::runtime::RuntimeId;
+pub use crate::storage::Storage;
+
+/// The base trait which your "query context" must implement. Gives
+/// access to the salsa runtime, which you must embed into your query
+/// context (along with whatever other state you may require).
+pub trait Database: plumbing::DatabaseOps {
+    /// This function is invoked at key points in the salsa
+    /// runtime. It permits the database to be customized and to
+    /// inject logging or other custom behavior.
+    fn salsa_event(&self, event_fn: Event) {
+        #![allow(unused_variables)]
+    }
+
+    /// Starts unwinding the stack if the current revision is cancelled.
+    ///
+    /// This method can be called by query implementations that perform
+    /// potentially expensive computations, in order to speed up propagation of
+    /// cancellation.
+    ///
+    /// Cancellation will automatically be triggered by salsa on any query
+    /// invocation.
+    ///
+    /// This method should not be overridden by `Database` implementors. A
+    /// `salsa_event` is emitted when this method is called, so that should be
+    /// used instead.
+    #[inline]
+    fn unwind_if_cancelled(&self) {
+        let runtime = self.salsa_runtime();
+        self.salsa_event(Event {
+            runtime_id: runtime.id(),
+            kind: EventKind::WillCheckCancellation,
+        });
+
+        let current_revision = runtime.current_revision();
+        let pending_revision = runtime.pending_revision();
+        tracing::debug!(
+            "unwind_if_cancelled: current_revision={:?}, pending_revision={:?}",
+            current_revision,
+            pending_revision
+        );
+        if pending_revision > current_revision {
+            runtime.unwind_cancelled();
+        }
+    }
+
+    /// Gives access to the underlying salsa runtime.
+    ///
+    /// This method should not be overridden by `Database` implementors.
+    fn salsa_runtime(&self) -> &Runtime {
+        self.ops_salsa_runtime()
+    }
+
+    /// Gives access to the underlying salsa runtime.
+    ///
+    /// This method should not be overridden by `Database` implementors.
+    fn salsa_runtime_mut(&mut self) -> &mut Runtime {
+        self.ops_salsa_runtime_mut()
+    }
+}
+
+/// The `Event` struct identifies various notable things that can
+/// occur during salsa execution. Instances of this struct are given
+/// to `salsa_event`.
+pub struct Event {
+    /// The id of the snapshot that triggered the event.  Usually
+    /// 1-to-1 with a thread, as well.
+    pub runtime_id: RuntimeId,
+
+    /// What sort of event was it.
+    pub kind: EventKind,
+}
+
+impl Event {
+    /// Returns a type that gives a user-readable debug output.
+    /// Use like `println!("{:?}", index.debug(db))`.
+    pub fn debug<'me, D: ?Sized>(&'me self, db: &'me D) -> impl std::fmt::Debug + 'me
+    where
+        D: plumbing::DatabaseOps,
+    {
+        EventDebug { event: self, db }
+    }
+}
+
+impl fmt::Debug for Event {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("Event")
+            .field("runtime_id", &self.runtime_id)
+            .field("kind", &self.kind)
+            .finish()
+    }
+}
+
+struct EventDebug<'me, D: ?Sized>
+where
+    D: plumbing::DatabaseOps,
+{
+    event: &'me Event,
+    db: &'me D,
+}
+
+impl<'me, D: ?Sized> fmt::Debug for EventDebug<'me, D>
+where
+    D: plumbing::DatabaseOps,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        fmt.debug_struct("Event")
+            .field("runtime_id", &self.event.runtime_id)
+            .field("kind", &self.event.kind.debug(self.db))
+            .finish()
+    }
+}
+
+/// An enum identifying the various kinds of events that can occur.
+pub enum EventKind {
+    /// Occurs when we found that all inputs to a memoized value are
+    /// up-to-date and hence the value can be re-used without
+    /// executing the closure.
+    ///
+    /// Executes before the "re-used" value is returned.
+    DidValidateMemoizedValue {
+        /// The database-key for the affected value. Implements `Debug`.
+        database_key: DatabaseKeyIndex,
+    },
+
+    /// Indicates that another thread (with id `other_runtime_id`) is processing the
+    /// given query (`database_key`), so we will block until they
+    /// finish.
+    ///
+    /// Executes after we have registered with the other thread but
+    /// before they have answered us.
+    ///
+    /// (NB: you can find the `id` of the current thread via the
+    /// `salsa_runtime`)
+    WillBlockOn {
+        /// The id of the runtime we will block on.
+        other_runtime_id: RuntimeId,
+
+        /// The database-key for the affected value. Implements `Debug`.
+        database_key: DatabaseKeyIndex,
+    },
+
+    /// Indicates that the function for this query will be executed.
+    /// This is either because it has never executed before or because
+    /// its inputs may be out of date.
+    WillExecute {
+        /// The database-key for the affected value. Implements `Debug`.
+        database_key: DatabaseKeyIndex,
+    },
+
+    /// Indicates that `unwind_if_cancelled` was called and salsa will check if
+    /// the current revision has been cancelled.
+    WillCheckCancellation,
+}
+
+impl EventKind {
+    /// Returns a type that gives a user-readable debug output.
+    /// Use like `println!("{:?}", index.debug(db))`.
+    pub fn debug<'me, D: ?Sized>(&'me self, db: &'me D) -> impl std::fmt::Debug + 'me
+    where
+        D: plumbing::DatabaseOps,
+    {
+        EventKindDebug { kind: self, db }
+    }
+}
+
+impl fmt::Debug for EventKind {
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self {
+            EventKind::DidValidateMemoizedValue { database_key } => fmt
+                .debug_struct("DidValidateMemoizedValue")
+                .field("database_key", database_key)
+                .finish(),
+            EventKind::WillBlockOn { other_runtime_id, database_key } => fmt
+                .debug_struct("WillBlockOn")
+                .field("other_runtime_id", other_runtime_id)
+                .field("database_key", database_key)
+                .finish(),
+            EventKind::WillExecute { database_key } => {
+                fmt.debug_struct("WillExecute").field("database_key", database_key).finish()
+            }
+            EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(),
+        }
+    }
+}
+
+struct EventKindDebug<'me, D: ?Sized>
+where
+    D: plumbing::DatabaseOps,
+{
+    kind: &'me EventKind,
+    db: &'me D,
+}
+
+impl<'me, D: ?Sized> fmt::Debug for EventKindDebug<'me, D>
+where
+    D: plumbing::DatabaseOps,
+{
+    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+        match self.kind {
+            EventKind::DidValidateMemoizedValue { database_key } => fmt
+                .debug_struct("DidValidateMemoizedValue")
+                .field("database_key", &database_key.debug(self.db))
+                .finish(),
+            EventKind::WillBlockOn { other_runtime_id, database_key } => fmt
+                .debug_struct("WillBlockOn")
+                .field("other_runtime_id", &other_runtime_id)
+                .field("database_key", &database_key.debug(self.db))
+                .finish(),
+            EventKind::WillExecute { database_key } => fmt
+                .debug_struct("WillExecute")
+                .field("database_key", &database_key.debug(self.db))
+                .finish(),
+            EventKind::WillCheckCancellation => fmt.debug_struct("WillCheckCancellation").finish(),
+        }
+    }
+}
+
+/// Indicates a database that also supports parallel query
+/// evaluation. All of Salsa's base query support is capable of
+/// parallel execution, but for it to work, your query key/value types
+/// must also be `Send`, as must any additional data in your database.
+pub trait ParallelDatabase: Database + Send {
+    /// Creates a second handle to the database that holds the
+    /// database fixed at a particular revision. So long as this
+    /// "frozen" handle exists, any attempt to [`set`] an input will
+    /// block.
+    ///
+    /// [`set`]: struct.QueryTable.html#method.set
+    ///
+    /// This is the method you are meant to use most of the time in a
+    /// parallel setting where modifications may arise asynchronously
+    /// (e.g., a language server). In this context, it is common to
+    /// wish to "fork off" a snapshot of the database performing some
+    /// series of queries in parallel and arranging the results. Using
+    /// this method for that purpose ensures that those queries will
+    /// see a consistent view of the database (it is also advisable
+    /// for those queries to use the [`Runtime::unwind_if_cancelled`]
+    /// method to check for cancellation).
+    ///
+    /// # Panics
+    ///
+    /// It is not permitted to create a snapshot from inside of a
+    /// query. Attepting to do so will panic.
+    ///
+    /// # Deadlock warning
+    ///
+    /// The intended pattern for snapshots is that, once created, they
+    /// are sent to another thread and used from there. As such, the
+    /// `snapshot` acquires a "read lock" on the database --
+    /// therefore, so long as the `snapshot` is not dropped, any
+    /// attempt to `set` a value in the database will block. If the
+    /// `snapshot` is owned by the same thread that is attempting to
+    /// `set`, this will cause a problem.
+    ///
+    /// # How to implement this
+    ///
+    /// Typically, this method will create a second copy of your
+    /// database type (`MyDatabaseType`, in the example below),
+    /// cloning over each of the fields from `self` into this new
+    /// copy. For the field that stores the salsa runtime, you should
+    /// use [the `Runtime::snapshot` method][rfm] to create a snapshot of the
+    /// runtime. Finally, package up the result using `Snapshot::new`,
+    /// which is a simple wrapper type that only gives `&self` access
+    /// to the database within (thus preventing the use of methods
+    /// that may mutate the inputs):
+    ///
+    /// [rfm]: struct.Runtime.html#method.snapshot
+    ///
+    /// ```rust,ignore
+    /// impl ParallelDatabase for MyDatabaseType {
+    ///     fn snapshot(&self) -> Snapshot<Self> {
+    ///         Snapshot::new(
+    ///             MyDatabaseType {
+    ///                 runtime: self.runtime.snapshot(self),
+    ///                 other_field: self.other_field.clone(),
+    ///             }
+    ///         )
+    ///     }
+    /// }
+    /// ```
+    fn snapshot(&self) -> Snapshot<Self>;
+}
+
+/// Simple wrapper struct that takes ownership of a database `DB` and
+/// only gives `&self` access to it. See [the `snapshot` method][fm]
+/// for more details.
+///
+/// [fm]: trait.ParallelDatabase.html#method.snapshot
+#[derive(Debug)]
+pub struct Snapshot<DB: ?Sized>
+where
+    DB: ParallelDatabase,
+{
+    db: DB,
+}
+
+impl<DB> Snapshot<DB>
+where
+    DB: ParallelDatabase,
+{
+    /// Creates a `Snapshot` that wraps the given database handle
+    /// `db`. From this point forward, only shared references to `db`
+    /// will be possible.
+    pub fn new(db: DB) -> Self {
+        Snapshot { db }
+    }
+}
+
+impl<DB> std::ops::Deref for Snapshot<DB>
+where
+    DB: ParallelDatabase,
+{
+    type Target = DB;
+
+    fn deref(&self) -> &DB {
+        &self.db
+    }
+}
+
+/// An integer that uniquely identifies a particular query instance within the
+/// database. Used to track dependencies between queries. Fully ordered and
+/// equatable but those orderings are arbitrary, and meant to be used only for
+/// inserting into maps and the like.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct DatabaseKeyIndex {
+    group_index: u16,
+    query_index: u16,
+    key_index: u32,
+}
+
+impl DatabaseKeyIndex {
+    /// Returns the index of the query group containing this key.
+    #[inline]
+    pub fn group_index(self) -> u16 {
+        self.group_index
+    }
+
+    /// Returns the index of the query within its query group.
+    #[inline]
+    pub fn query_index(self) -> u16 {
+        self.query_index
+    }
+
+    /// Returns the index of this particular query key within the query.
+    #[inline]
+    pub fn key_index(self) -> u32 {
+        self.key_index
+    }
+
+    /// Returns a type that gives a user-readable debug output.
+    /// Use like `println!("{:?}", index.debug(db))`.
+    pub fn debug<D: ?Sized>(self, db: &D) -> impl std::fmt::Debug + '_
+    where
+        D: plumbing::DatabaseOps,
+    {
+        DatabaseKeyIndexDebug { index: self, db }
+    }
+}
+
+/// Helper type for `DatabaseKeyIndex::debug`
+struct DatabaseKeyIndexDebug<'me, D: ?Sized>
+where
+    D: plumbing::DatabaseOps,
+{
+    index: DatabaseKeyIndex,
+    db: &'me D,
+}
+
+impl<D: ?Sized> std::fmt::Debug for DatabaseKeyIndexDebug<'_, D>
+where
+    D: plumbing::DatabaseOps,
+{
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        self.db.fmt_index(self.index, fmt)
+    }
+}
+
+/// Trait implements by all of the "special types" associated with
+/// each of your queries.
+///
+/// Base trait of `Query` that has a lifetime parameter to allow the `DynDb` to be non-'static.
+pub trait QueryDb<'d>: Sized {
+    /// Dyn version of the associated trait for this query group.
+    type DynDb: ?Sized + Database + HasQueryGroup<Self::Group> + 'd;
+
+    /// Associate query group struct.
+    type Group: plumbing::QueryGroup<GroupStorage = Self::GroupStorage>;
+
+    /// Generated struct that contains storage for all queries in a group.
+    type GroupStorage;
+}
+
+/// Trait implements by all of the "special types" associated with
+/// each of your queries.
+pub trait Query: Debug + Default + Sized + for<'d> QueryDb<'d> {
+    /// Type that you you give as a parameter -- for queries with zero
+    /// or more than one input, this will be a tuple.
+    type Key: Clone + Debug + Hash + Eq;
+
+    /// What value does the query return?
+    type Value: Clone + Debug;
+
+    /// Internal struct storing the values for the query.
+    // type Storage: plumbing::QueryStorageOps<Self>;
+    type Storage;
+
+    /// A unique index identifying this query within the group.
+    const QUERY_INDEX: u16;
+
+    /// Name of the query method (e.g., `foo`)
+    const QUERY_NAME: &'static str;
+
+    /// Extact storage for this query from the storage for its group.
+    fn query_storage<'a>(
+        group_storage: &'a <Self as QueryDb<'_>>::GroupStorage,
+    ) -> &'a std::sync::Arc<Self::Storage>;
+
+    /// Extact storage for this query from the storage for its group.
+    fn query_storage_mut<'a>(
+        group_storage: &'a <Self as QueryDb<'_>>::GroupStorage,
+    ) -> &'a std::sync::Arc<Self::Storage>;
+}
+
+/// Return value from [the `query` method] on `Database`.
+/// Gives access to various less common operations on queries.
+///
+/// [the `query` method]: trait.Database.html#method.query
+pub struct QueryTable<'me, Q>
+where
+    Q: Query,
+{
+    db: &'me <Q as QueryDb<'me>>::DynDb,
+    storage: &'me Q::Storage,
+}
+
+impl<'me, Q> QueryTable<'me, Q>
+where
+    Q: Query,
+    Q::Storage: QueryStorageOps<Q>,
+{
+    /// Constructs a new `QueryTable`.
+    pub fn new(db: &'me <Q as QueryDb<'me>>::DynDb, storage: &'me Q::Storage) -> Self {
+        Self { db, storage }
+    }
+
+    /// Execute the query on a given input. Usually it's easier to
+    /// invoke the trait method directly. Note that for variadic
+    /// queries (those with no inputs, or those with more than one
+    /// input) the key will be a tuple.
+    pub fn get(&self, key: Q::Key) -> Q::Value {
+        self.storage.fetch(self.db, &key)
+    }
+
+    /// Completely clears the storage for this query.
+    ///
+    /// This method breaks internal invariants of salsa, so any further queries
+    /// might return nonsense results. It is useful only in very specific
+    /// circumstances -- for example, when one wants to observe which values
+    /// dropped together with the table
+    pub fn purge(&self)
+    where
+        Q::Storage: plumbing::QueryStorageMassOps,
+    {
+        self.storage.purge();
+    }
+}
+
+/// Return value from [the `query_mut` method] on `Database`.
+/// Gives access to the `set` method, notably, that is used to
+/// set the value of an input query.
+///
+/// [the `query_mut` method]: trait.Database.html#method.query_mut
+pub struct QueryTableMut<'me, Q>
+where
+    Q: Query + 'me,
+{
+    runtime: &'me mut Runtime,
+    storage: &'me Q::Storage,
+}
+
+impl<'me, Q> QueryTableMut<'me, Q>
+where
+    Q: Query,
+{
+    /// Constructs a new `QueryTableMut`.
+    pub fn new(runtime: &'me mut Runtime, storage: &'me Q::Storage) -> Self {
+        Self { runtime, storage }
+    }
+
+    /// Assign a value to an "input query". Must be used outside of
+    /// an active query computation.
+    ///
+    /// If you are using `snapshot`, see the notes on blocking
+    /// and cancellation on [the `query_mut` method].
+    ///
+    /// [the `query_mut` method]: trait.Database.html#method.query_mut
+    pub fn set(&mut self, key: Q::Key, value: Q::Value)
+    where
+        Q::Storage: plumbing::InputQueryStorageOps<Q>,
+    {
+        self.set_with_durability(key, value, Durability::LOW);
+    }
+
+    /// Assign a value to an "input query", with the additional
+    /// promise that this value will **never change**. Must be used
+    /// outside of an active query computation.
+    ///
+    /// If you are using `snapshot`, see the notes on blocking
+    /// and cancellation on [the `query_mut` method].
+    ///
+    /// [the `query_mut` method]: trait.Database.html#method.query_mut
+    pub fn set_with_durability(&mut self, key: Q::Key, value: Q::Value, durability: Durability)
+    where
+        Q::Storage: plumbing::InputQueryStorageOps<Q>,
+    {
+        self.storage.set(self.runtime, &key, value, durability);
+    }
+
+    /// Sets the size of LRU cache of values for this query table.
+    ///
+    /// That is, at most `cap` values will be preset in the table at the same
+    /// time. This helps with keeping maximum memory usage under control, at the
+    /// cost of potential extra recalculations of evicted values.
+    ///
+    /// If `cap` is zero, all values are preserved, this is the default.
+    pub fn set_lru_capacity(&self, cap: usize)
+    where
+        Q::Storage: plumbing::LruQueryStorageOps,
+    {
+        self.storage.set_lru_capacity(cap);
+    }
+
+    /// Marks the computed value as outdated.
+    ///
+    /// This causes salsa to re-execute the query function on the next access to
+    /// the query, even if all dependencies are up to date.
+    ///
+    /// This is most commonly used as part of the [on-demand input
+    /// pattern](https://salsa-rs.github.io/salsa/common_patterns/on_demand_inputs.html).
+    pub fn invalidate(&mut self, key: &Q::Key)
+    where
+        Q::Storage: plumbing::DerivedQueryStorageOps<Q>,
+    {
+        self.storage.invalidate(self.runtime, key)
+    }
+}
+
+/// A panic payload indicating that execution of a salsa query was cancelled.
+///
+/// This can occur for a few reasons:
+/// *
+/// *
+/// *
+#[derive(Debug)]
+#[non_exhaustive]
+pub enum Cancelled {
+    /// The query was operating on revision R, but there is a pending write to move to revision R+1.
+    #[non_exhaustive]
+    PendingWrite,
+
+    /// The query was blocked on another thread, and that thread panicked.
+    #[non_exhaustive]
+    PropagatedPanic,
+}
+
+impl Cancelled {
+    fn throw(self) -> ! {
+        // We use resume and not panic here to avoid running the panic
+        // hook (that is, to avoid collecting and printing backtrace).
+        std::panic::resume_unwind(Box::new(self));
+    }
+
+    /// Runs `f`, and catches any salsa cancellation.
+    pub fn catch<F, T>(f: F) -> Result<T, Cancelled>
+    where
+        F: FnOnce() -> T + UnwindSafe,
+    {
+        match panic::catch_unwind(f) {
+            Ok(t) => Ok(t),
+            Err(payload) => match payload.downcast() {
+                Ok(cancelled) => Err(*cancelled),
+                Err(payload) => panic::resume_unwind(payload),
+            },
+        }
+    }
+}
+
+impl std::fmt::Display for Cancelled {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let why = match self {
+            Cancelled::PendingWrite => "pending write",
+            Cancelled::PropagatedPanic => "propagated panic",
+        };
+        f.write_str("cancelled because of ")?;
+        f.write_str(why)
+    }
+}
+
+impl std::error::Error for Cancelled {}
+
+/// Captures the participants of a cycle that occurred when executing a query.
+///
+/// This type is meant to be used to help give meaningful error messages to the
+/// user or to help salsa developers figure out why their program is resulting
+/// in a computation cycle.
+///
+/// It is used in a few ways:
+///
+/// * During [cycle recovery](https://https://salsa-rs.github.io/salsa/cycles/fallback.html),
+///   where it is given to the fallback function.
+/// * As the panic value when an unexpected cycle (i.e., a cycle where one or more participants
+///   lacks cycle recovery information) occurs.
+///
+/// You can read more about cycle handling in
+/// the [salsa book](https://https://salsa-rs.github.io/salsa/cycles.html).
+#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Cycle {
+    participants: plumbing::CycleParticipants,
+}
+
+impl Cycle {
+    pub(crate) fn new(participants: plumbing::CycleParticipants) -> Self {
+        Self { participants }
+    }
+
+    /// True if two `Cycle` values represent the same cycle.
+    pub(crate) fn is(&self, cycle: &Cycle) -> bool {
+        triomphe::Arc::ptr_eq(&self.participants, &cycle.participants)
+    }
+
+    pub(crate) fn throw(self) -> ! {
+        tracing::debug!("throwing cycle {:?}", self);
+        std::panic::resume_unwind(Box::new(self))
+    }
+
+    pub(crate) fn catch<T>(execute: impl FnOnce() -> T) -> Result<T, Cycle> {
+        match std::panic::catch_unwind(AssertUnwindSafe(execute)) {
+            Ok(v) => Ok(v),
+            Err(err) => match err.downcast::<Cycle>() {
+                Ok(cycle) => Err(*cycle),
+                Err(other) => std::panic::resume_unwind(other),
+            },
+        }
+    }
+
+    /// Iterate over the [`DatabaseKeyIndex`] for each query participating
+    /// in the cycle. The start point of this iteration within the cycle
+    /// is arbitrary but deterministic, but the ordering is otherwise determined
+    /// by the execution.
+    pub fn participant_keys(&self) -> impl Iterator<Item = DatabaseKeyIndex> + '_ {
+        self.participants.iter().copied()
+    }
+
+    /// Returns a vector with the debug information for
+    /// all the participants in the cycle.
+    pub fn all_participants<DB: ?Sized + Database>(&self, db: &DB) -> Vec<String> {
+        self.participant_keys().map(|d| format!("{:?}", d.debug(db))).collect()
+    }
+
+    /// Returns a vector with the debug information for
+    /// those participants in the cycle that lacked recovery
+    /// information.
+    pub fn unexpected_participants<DB: ?Sized + Database>(&self, db: &DB) -> Vec<String> {
+        self.participant_keys()
+            .filter(|&d| db.cycle_recovery_strategy(d) == CycleRecoveryStrategy::Panic)
+            .map(|d| format!("{:?}", d.debug(db)))
+            .collect()
+    }
+
+    /// Returns a "debug" view onto this strict that can be used to print out information.
+    pub fn debug<'me, DB: ?Sized + Database>(&'me self, db: &'me DB) -> impl std::fmt::Debug + 'me {
+        struct UnexpectedCycleDebug<'me> {
+            c: &'me Cycle,
+            db: &'me dyn Database,
+        }
+
+        impl<'me> std::fmt::Debug for UnexpectedCycleDebug<'me> {
+            fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+                fmt.debug_struct("UnexpectedCycle")
+                    .field("all_participants", &self.c.all_participants(self.db))
+                    .field("unexpected_participants", &self.c.unexpected_participants(self.db))
+                    .finish()
+            }
+        }
+
+        UnexpectedCycleDebug { c: self, db: db.ops_database() }
+    }
+}
+
+// Re-export the procedural macros.
+#[allow(unused_imports)]
+#[macro_use]
+extern crate salsa_macros;
+use plumbing::HasQueryGroup;
+pub use salsa_macros::*;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/lru.rs b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
new file mode 100644
index 00000000000..c6b9778f20a
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/lru.rs
@@ -0,0 +1,325 @@
+//!
+use oorandom::Rand64;
+use parking_lot::Mutex;
+use std::fmt::Debug;
+use std::sync::atomic::AtomicUsize;
+use std::sync::atomic::Ordering;
+use triomphe::Arc;
+
+/// A simple and approximate concurrent lru list.
+///
+/// We assume but do not verify that each node is only used with one
+/// list. If this is not the case, it is not *unsafe*, but panics and
+/// weird results will ensue.
+///
+/// Each "node" in the list is of type `Node` and must implement
+/// `LruNode`, which is a trait that gives access to a field that
+/// stores the index in the list. This index gives us a rough idea of
+/// how recently the node has been used.
+#[derive(Debug)]
+pub(crate) struct Lru<Node>
+where
+    Node: LruNode,
+{
+    green_zone: AtomicUsize,
+    data: Mutex<LruData<Node>>,
+}
+
+#[derive(Debug)]
+struct LruData<Node> {
+    end_red_zone: usize,
+    end_yellow_zone: usize,
+    end_green_zone: usize,
+    rng: Rand64,
+    entries: Vec<Arc<Node>>,
+}
+
+pub(crate) trait LruNode: Sized + Debug {
+    fn lru_index(&self) -> &LruIndex;
+}
+
+#[derive(Debug)]
+pub(crate) struct LruIndex {
+    /// Index in the approprate LRU list, or std::usize::MAX if not a
+    /// member.
+    index: AtomicUsize,
+}
+
+impl<Node> Default for Lru<Node>
+where
+    Node: LruNode,
+{
+    fn default() -> Self {
+        Lru::new()
+    }
+}
+
+// We always use a fixed seed for our randomness so that we have
+// predictable results.
+const LRU_SEED: &str = "Hello, Rustaceans";
+
+impl<Node> Lru<Node>
+where
+    Node: LruNode,
+{
+    /// Creates a new LRU list where LRU caching is disabled.
+    pub(crate) fn new() -> Self {
+        Self::with_seed(LRU_SEED)
+    }
+
+    #[cfg_attr(not(test), allow(dead_code))]
+    fn with_seed(seed: &str) -> Self {
+        Lru { green_zone: AtomicUsize::new(0), data: Mutex::new(LruData::with_seed(seed)) }
+    }
+
+    /// Adjust the total number of nodes permitted to have a value at
+    /// once.  If `len` is zero, this disables LRU caching completely.
+    pub(crate) fn set_lru_capacity(&self, len: usize) {
+        let mut data = self.data.lock();
+
+        // We require each zone to have at least 1 slot. Therefore,
+        // the length cannot be just 1 or 2.
+        if len == 0 {
+            self.green_zone.store(0, Ordering::Release);
+            data.resize(0, 0, 0);
+        } else {
+            let len = std::cmp::max(len, 3);
+
+            // Top 10% is the green zone. This must be at least length 1.
+            let green_zone = std::cmp::max(len / 10, 1);
+
+            // Next 20% is the yellow zone.
+            let yellow_zone = std::cmp::max(len / 5, 1);
+
+            // Remaining 70% is the red zone.
+            let red_zone = len - yellow_zone - green_zone;
+
+            // We need quick access to the green zone.
+            self.green_zone.store(green_zone, Ordering::Release);
+
+            // Resize existing array.
+            data.resize(green_zone, yellow_zone, red_zone);
+        }
+    }
+
+    /// Records that `node` was used. This may displace an old node (if the LRU limits are
+    pub(crate) fn record_use(&self, node: &Arc<Node>) -> Option<Arc<Node>> {
+        tracing::debug!("record_use(node={:?})", node);
+
+        // Load green zone length and check if the LRU cache is even enabled.
+        let green_zone = self.green_zone.load(Ordering::Acquire);
+        tracing::debug!("record_use: green_zone={}", green_zone);
+        if green_zone == 0 {
+            return None;
+        }
+
+        // Find current index of list (if any) and the current length
+        // of our green zone.
+        let index = node.lru_index().load();
+        tracing::debug!("record_use: index={}", index);
+
+        // Already a member of the list, and in the green zone -- nothing to do!
+        if index < green_zone {
+            return None;
+        }
+
+        self.data.lock().record_use(node)
+    }
+
+    pub(crate) fn purge(&self) {
+        self.green_zone.store(0, Ordering::SeqCst);
+        *self.data.lock() = LruData::with_seed(LRU_SEED);
+    }
+}
+
+impl<Node> LruData<Node>
+where
+    Node: LruNode,
+{
+    fn with_seed(seed_str: &str) -> Self {
+        Self::with_rng(rng_with_seed(seed_str))
+    }
+
+    fn with_rng(rng: Rand64) -> Self {
+        LruData { end_yellow_zone: 0, end_green_zone: 0, end_red_zone: 0, entries: Vec::new(), rng }
+    }
+
+    fn green_zone(&self) -> std::ops::Range<usize> {
+        0..self.end_green_zone
+    }
+
+    fn yellow_zone(&self) -> std::ops::Range<usize> {
+        self.end_green_zone..self.end_yellow_zone
+    }
+
+    fn red_zone(&self) -> std::ops::Range<usize> {
+        self.end_yellow_zone..self.end_red_zone
+    }
+
+    fn resize(&mut self, len_green_zone: usize, len_yellow_zone: usize, len_red_zone: usize) {
+        self.end_green_zone = len_green_zone;
+        self.end_yellow_zone = self.end_green_zone + len_yellow_zone;
+        self.end_red_zone = self.end_yellow_zone + len_red_zone;
+        let entries = std::mem::replace(&mut self.entries, Vec::with_capacity(self.end_red_zone));
+
+        tracing::debug!("green_zone = {:?}", self.green_zone());
+        tracing::debug!("yellow_zone = {:?}", self.yellow_zone());
+        tracing::debug!("red_zone = {:?}", self.red_zone());
+
+        // We expect to resize when the LRU cache is basically empty.
+        // So just forget all the old LRU indices to start.
+        for entry in entries {
+            entry.lru_index().clear();
+        }
+    }
+
+    /// Records that a node was used. If it is already a member of the
+    /// LRU list, it is promoted to the green zone (unless it's
+    /// already there). Otherwise, it is added to the list first and
+    /// *then* promoted to the green zone. Adding a new node to the
+    /// list may displace an old member of the red zone, in which case
+    /// that is returned.
+    fn record_use(&mut self, node: &Arc<Node>) -> Option<Arc<Node>> {
+        tracing::debug!("record_use(node={:?})", node);
+
+        // NB: When this is invoked, we have typically already loaded
+        // the LRU index (to check if it is in green zone). But that
+        // check was done outside the lock and -- for all we know --
+        // the index may have changed since. So we always reload.
+        let index = node.lru_index().load();
+
+        if index < self.end_green_zone {
+            None
+        } else if index < self.end_yellow_zone {
+            self.promote_yellow_to_green(node, index);
+            None
+        } else if index < self.end_red_zone {
+            self.promote_red_to_green(node, index);
+            None
+        } else {
+            self.insert_new(node)
+        }
+    }
+
+    /// Inserts a node that is not yet a member of the LRU list. If
+    /// the list is at capacity, this can displace an existing member.
+    fn insert_new(&mut self, node: &Arc<Node>) -> Option<Arc<Node>> {
+        debug_assert!(!node.lru_index().is_in_lru());
+
+        // Easy case: we still have capacity. Push it, and then promote
+        // it up to the appropriate zone.
+        let len = self.entries.len();
+        if len < self.end_red_zone {
+            self.entries.push(node.clone());
+            node.lru_index().store(len);
+            tracing::debug!("inserted node {:?} at {}", node, len);
+            return self.record_use(node);
+        }
+
+        // Harder case: no capacity. Create some by evicting somebody from red
+        // zone and then promoting.
+        let victim_index = self.pick_index(self.red_zone());
+        let victim_node = std::mem::replace(&mut self.entries[victim_index], node.clone());
+        tracing::debug!("evicting red node {:?} from {}", victim_node, victim_index);
+        victim_node.lru_index().clear();
+        self.promote_red_to_green(node, victim_index);
+        Some(victim_node)
+    }
+
+    /// Promotes the node `node`, stored at `red_index` (in the red
+    /// zone), into a green index, demoting yellow/green nodes at
+    /// random.
+    ///
+    /// NB: It is not required that `node.lru_index()` is up-to-date
+    /// when entering this method.
+    fn promote_red_to_green(&mut self, node: &Arc<Node>, red_index: usize) {
+        debug_assert!(self.red_zone().contains(&red_index));
+
+        // Pick a yellow at random and switch places with it.
+        //
+        // Subtle: we do not update `node.lru_index` *yet* -- we're
+        // going to invoke `self.promote_yellow` next, and it will get
+        // updated then.
+        let yellow_index = self.pick_index(self.yellow_zone());
+        tracing::debug!(
+            "demoting yellow node {:?} from {} to red at {}",
+            self.entries[yellow_index],
+            yellow_index,
+            red_index,
+        );
+        self.entries.swap(yellow_index, red_index);
+        self.entries[red_index].lru_index().store(red_index);
+
+        // Now move ourselves up into the green zone.
+        self.promote_yellow_to_green(node, yellow_index);
+    }
+
+    /// Promotes the node `node`, stored at `yellow_index` (in the
+    /// yellow zone), into a green index, demoting a green node at
+    /// random to replace it.
+    ///
+    /// NB: It is not required that `node.lru_index()` is up-to-date
+    /// when entering this method.
+    fn promote_yellow_to_green(&mut self, node: &Arc<Node>, yellow_index: usize) {
+        debug_assert!(self.yellow_zone().contains(&yellow_index));
+
+        // Pick a yellow at random and switch places with it.
+        let green_index = self.pick_index(self.green_zone());
+        tracing::debug!(
+            "demoting green node {:?} from {} to yellow at {}",
+            self.entries[green_index],
+            green_index,
+            yellow_index
+        );
+        self.entries.swap(green_index, yellow_index);
+        self.entries[yellow_index].lru_index().store(yellow_index);
+        node.lru_index().store(green_index);
+
+        tracing::debug!("promoted {:?} to green index {}", node, green_index);
+    }
+
+    fn pick_index(&mut self, zone: std::ops::Range<usize>) -> usize {
+        let end_index = std::cmp::min(zone.end, self.entries.len());
+        self.rng.rand_range(zone.start as u64..end_index as u64) as usize
+    }
+}
+
+impl Default for LruIndex {
+    fn default() -> Self {
+        Self { index: AtomicUsize::new(std::usize::MAX) }
+    }
+}
+
+impl LruIndex {
+    fn load(&self) -> usize {
+        self.index.load(Ordering::Acquire) // see note on ordering below
+    }
+
+    fn store(&self, value: usize) {
+        self.index.store(value, Ordering::Release) // see note on ordering below
+    }
+
+    fn clear(&self) {
+        self.store(std::usize::MAX);
+    }
+
+    fn is_in_lru(&self) -> bool {
+        self.load() != std::usize::MAX
+    }
+}
+
+fn rng_with_seed(seed_str: &str) -> Rand64 {
+    let mut seed: [u8; 16] = [0; 16];
+    for (i, &b) in seed_str.as_bytes().iter().take(16).enumerate() {
+        seed[i] = b;
+    }
+    Rand64::new(u128::from_le_bytes(seed))
+}
+
+// A note on ordering:
+//
+// I chose to use AcqRel for the ordering but I don't think it's
+// strictly needed.  All writes occur under a lock, so they should be
+// ordered w/r/t one another.  As for the reads, they can occur
+// outside the lock, but they don't themselves enable dependent reads
+// -- if the reads are out of bounds, we would acquire a lock.
diff --git a/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs
new file mode 100644
index 00000000000..71332e39cad
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/plumbing.rs
@@ -0,0 +1,238 @@
+//!
+#![allow(missing_docs)]
+
+use crate::debug::TableEntry;
+use crate::durability::Durability;
+use crate::Cycle;
+use crate::Database;
+use crate::Query;
+use crate::QueryTable;
+use crate::QueryTableMut;
+use std::borrow::Borrow;
+use std::fmt::Debug;
+use std::hash::Hash;
+use triomphe::Arc;
+
+pub use crate::derived::DependencyStorage;
+pub use crate::derived::MemoizedStorage;
+pub use crate::input::{InputStorage, UnitInputStorage};
+pub use crate::interned::InternedStorage;
+pub use crate::interned::LookupInternedStorage;
+pub use crate::{revision::Revision, DatabaseKeyIndex, QueryDb, Runtime};
+
+/// Defines various associated types. An impl of this
+/// should be generated for your query-context type automatically by
+/// the `database_storage` macro, so you shouldn't need to mess
+/// with this trait directly.
+pub trait DatabaseStorageTypes: Database {
+    /// Defines the "storage type", where all the query data is kept.
+    /// This type is defined by the `database_storage` macro.
+    type DatabaseStorage: Default;
+}
+
+/// Internal operations that the runtime uses to operate on the database.
+pub trait DatabaseOps {
+    /// Upcast this type to a `dyn Database`.
+    fn ops_database(&self) -> &dyn Database;
+
+    /// Gives access to the underlying salsa runtime.
+    fn ops_salsa_runtime(&self) -> &Runtime;
+
+    /// Gives access to the underlying salsa runtime.
+    fn ops_salsa_runtime_mut(&mut self) -> &mut Runtime;
+
+    /// Formats a database key index in a human readable fashion.
+    fn fmt_index(
+        &self,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result;
+
+    /// True if the computed value for `input` may have changed since `revision`.
+    fn maybe_changed_after(&self, input: DatabaseKeyIndex, revision: Revision) -> bool;
+
+    /// Find the `CycleRecoveryStrategy` for a given input.
+    fn cycle_recovery_strategy(&self, input: DatabaseKeyIndex) -> CycleRecoveryStrategy;
+
+    /// Executes the callback for each kind of query.
+    fn for_each_query(&self, op: &mut dyn FnMut(&dyn QueryStorageMassOps));
+}
+
+/// Internal operations performed on the query storage as a whole
+/// (note that these ops do not need to know the identity of the
+/// query, unlike `QueryStorageOps`).
+pub trait QueryStorageMassOps {
+    fn purge(&self);
+}
+
+pub trait DatabaseKey: Clone + Debug + Eq + Hash {}
+
+pub trait QueryFunction: Query {
+    /// See `CycleRecoveryStrategy`
+    const CYCLE_STRATEGY: CycleRecoveryStrategy;
+
+    fn execute(db: &<Self as QueryDb<'_>>::DynDb, key: Self::Key) -> Self::Value;
+
+    fn cycle_fallback(
+        db: &<Self as QueryDb<'_>>::DynDb,
+        cycle: &Cycle,
+        key: &Self::Key,
+    ) -> Self::Value {
+        let _ = (db, cycle, key);
+        panic!("query `{:?}` doesn't support cycle fallback", Self::default())
+    }
+}
+
+/// Cycle recovery strategy: Is this query capable of recovering from
+/// a cycle that results from executing the function? If so, how?
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+pub enum CycleRecoveryStrategy {
+    /// Cannot recover from cycles: panic.
+    ///
+    /// This is the default. It is also what happens if a cycle
+    /// occurs and the queries involved have different recovery
+    /// strategies.
+    ///
+    /// In the case of a failure due to a cycle, the panic
+    /// value will be XXX (FIXME).
+    Panic,
+
+    /// Recovers from cycles by storing a sentinel value.
+    ///
+    /// This value is computed by the `QueryFunction::cycle_fallback`
+    /// function.
+    Fallback,
+}
+
+/// Create a query table, which has access to the storage for the query
+/// and offers methods like `get`.
+pub fn get_query_table<'me, Q>(db: &'me <Q as QueryDb<'me>>::DynDb) -> QueryTable<'me, Q>
+where
+    Q: Query + 'me,
+    Q::Storage: QueryStorageOps<Q>,
+{
+    let group_storage: &Q::GroupStorage = HasQueryGroup::group_storage(db);
+    let query_storage: &Q::Storage = Q::query_storage(group_storage);
+    QueryTable::new(db, query_storage)
+}
+
+/// Create a mutable query table, which has access to the storage
+/// for the query and offers methods like `set`.
+pub fn get_query_table_mut<'me, Q>(db: &'me mut <Q as QueryDb<'me>>::DynDb) -> QueryTableMut<'me, Q>
+where
+    Q: Query,
+{
+    let (group_storage, runtime) = HasQueryGroup::group_storage_mut(db);
+    let query_storage = Q::query_storage_mut(group_storage);
+    QueryTableMut::new(runtime, &**query_storage)
+}
+
+pub trait QueryGroup: Sized {
+    type GroupStorage;
+
+    /// Dyn version of the associated database trait.
+    type DynDb: ?Sized + Database + HasQueryGroup<Self>;
+}
+
+/// Trait implemented by a database for each group that it supports.
+/// `S` and `K` are the types for *group storage* and *group key*, respectively.
+pub trait HasQueryGroup<G>: Database
+where
+    G: QueryGroup,
+{
+    /// Access the group storage struct from the database.
+    fn group_storage(&self) -> &G::GroupStorage;
+
+    /// Access the group storage struct from the database.
+    /// Also returns a ref to the `Runtime`, since otherwise
+    /// the database is borrowed and one cannot get access to it.
+    fn group_storage_mut(&mut self) -> (&G::GroupStorage, &mut Runtime);
+}
+
+// ANCHOR:QueryStorageOps
+pub trait QueryStorageOps<Q>
+where
+    Self: QueryStorageMassOps,
+    Q: Query,
+{
+    // ANCHOR_END:QueryStorageOps
+
+    /// See CycleRecoveryStrategy
+    const CYCLE_STRATEGY: CycleRecoveryStrategy;
+
+    fn new(group_index: u16) -> Self;
+
+    /// Format a database key index in a suitable way.
+    fn fmt_index(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        index: DatabaseKeyIndex,
+        fmt: &mut std::fmt::Formatter<'_>,
+    ) -> std::fmt::Result;
+
+    // ANCHOR:maybe_changed_after
+    /// True if the value of `input`, which must be from this query, may have
+    /// changed after the given revision ended.
+    ///
+    /// This function should only be invoked with a revision less than the current
+    /// revision.
+    fn maybe_changed_after(
+        &self,
+        db: &<Q as QueryDb<'_>>::DynDb,
+        input: DatabaseKeyIndex,
+        revision: Revision,
+    ) -> bool;
+    // ANCHOR_END:maybe_changed_after
+
+    fn cycle_recovery_strategy(&self) -> CycleRecoveryStrategy {
+        Self::CYCLE_STRATEGY
+    }
+
+    // ANCHOR:fetch
+    /// Execute the query, returning the result (often, the result
+    /// will be memoized).  This is the "main method" for
+    /// queries.
+    ///
+    /// Returns `Err` in the event of a cycle, meaning that computing
+    /// the value for this `key` is recursively attempting to fetch
+    /// itself.
+    fn fetch(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Q::Value;
+    // ANCHOR_END:fetch
+
+    /// Returns the durability associated with a given key.
+    fn durability(&self, db: &<Q as QueryDb<'_>>::DynDb, key: &Q::Key) -> Durability;
+
+    /// Get the (current) set of the entries in the query storage
+    fn entries<C>(&self, db: &<Q as QueryDb<'_>>::DynDb) -> C
+    where
+        C: std::iter::FromIterator<TableEntry<Q::Key, Q::Value>>;
+}
+
+/// An optional trait that is implemented for "user mutable" storage:
+/// that is, storage whose value is not derived from other storage but
+/// is set independently.
+pub trait InputQueryStorageOps<Q>
+where
+    Q: Query,
+{
+    fn set(&self, runtime: &mut Runtime, key: &Q::Key, new_value: Q::Value, durability: Durability);
+}
+
+/// An optional trait that is implemented for "user mutable" storage:
+/// that is, storage whose value is not derived from other storage but
+/// is set independently.
+pub trait LruQueryStorageOps {
+    fn set_lru_capacity(&self, new_capacity: usize);
+}
+
+pub trait DerivedQueryStorageOps<Q>
+where
+    Q: Query,
+{
+    fn invalidate<S>(&self, runtime: &mut Runtime, key: &S)
+    where
+        S: Eq + Hash,
+        Q::Key: Borrow<S>;
+}
+
+pub type CycleParticipants = Arc<Vec<DatabaseKeyIndex>>;
diff --git a/src/tools/rust-analyzer/crates/salsa/src/revision.rs b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
new file mode 100644
index 00000000000..d97aaf9deba
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/revision.rs
@@ -0,0 +1,67 @@
+//!
+use std::num::NonZeroU32;
+use std::sync::atomic::{AtomicU32, Ordering};
+
+/// Value of the initial revision, as a u32. We don't use 0
+/// because we want to use a `NonZeroU32`.
+const START: u32 = 1;
+
+/// A unique identifier for the current version of the database; each
+/// time an input is changed, the revision number is incremented.
+/// `Revision` is used internally to track which values may need to be
+/// recomputed, but is not something you should have to interact with
+/// directly as a user of salsa.
+#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct Revision {
+    generation: NonZeroU32,
+}
+
+impl Revision {
+    pub(crate) fn start() -> Self {
+        Self::from(START)
+    }
+
+    pub(crate) fn from(g: u32) -> Self {
+        Self { generation: NonZeroU32::new(g).unwrap() }
+    }
+
+    pub(crate) fn next(self) -> Revision {
+        Self::from(self.generation.get() + 1)
+    }
+
+    fn as_u32(self) -> u32 {
+        self.generation.get()
+    }
+}
+
+impl std::fmt::Debug for Revision {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        write!(fmt, "R{}", self.generation)
+    }
+}
+
+#[derive(Debug)]
+pub(crate) struct AtomicRevision {
+    data: AtomicU32,
+}
+
+impl AtomicRevision {
+    pub(crate) fn start() -> Self {
+        Self { data: AtomicU32::new(START) }
+    }
+
+    pub(crate) fn load(&self) -> Revision {
+        Revision::from(self.data.load(Ordering::SeqCst))
+    }
+
+    pub(crate) fn store(&self, r: Revision) {
+        self.data.store(r.as_u32(), Ordering::SeqCst);
+    }
+
+    /// Increment by 1, returning previous value.
+    pub(crate) fn fetch_then_increment(&self) -> Revision {
+        let v = self.data.fetch_add(1, Ordering::SeqCst);
+        assert!(v != u32::max_value(), "revision overflow");
+        Revision::from(v)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs
new file mode 100644
index 00000000000..40b8856991f
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime.rs
@@ -0,0 +1,667 @@
+//!
+use crate::durability::Durability;
+use crate::hash::FxIndexSet;
+use crate::plumbing::CycleRecoveryStrategy;
+use crate::revision::{AtomicRevision, Revision};
+use crate::{Cancelled, Cycle, Database, DatabaseKeyIndex, Event, EventKind};
+use parking_lot::lock_api::{RawRwLock, RawRwLockRecursive};
+use parking_lot::{Mutex, RwLock};
+use std::hash::Hash;
+use std::panic::panic_any;
+use std::sync::atomic::{AtomicUsize, Ordering};
+use tracing::debug;
+use triomphe::Arc;
+
+mod dependency_graph;
+use dependency_graph::DependencyGraph;
+
+pub(crate) mod local_state;
+use local_state::LocalState;
+
+use self::local_state::{ActiveQueryGuard, QueryInputs, QueryRevisions};
+
+/// The salsa runtime stores the storage for all queries as well as
+/// tracking the query stack and dependencies between cycles.
+///
+/// Each new runtime you create (e.g., via `Runtime::new` or
+/// `Runtime::default`) will have an independent set of query storage
+/// associated with it. Normally, therefore, you only do this once, at
+/// the start of your application.
+pub struct Runtime {
+    /// Our unique runtime id.
+    id: RuntimeId,
+
+    /// If this is a "forked" runtime, then the `revision_guard` will
+    /// be `Some`; this guard holds a read-lock on the global query
+    /// lock.
+    revision_guard: Option<RevisionGuard>,
+
+    /// Local state that is specific to this runtime (thread).
+    local_state: LocalState,
+
+    /// Shared state that is accessible via all runtimes.
+    shared_state: Arc<SharedState>,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) enum WaitResult {
+    Completed,
+    Panicked,
+    Cycle(Cycle),
+}
+
+impl Default for Runtime {
+    fn default() -> Self {
+        Runtime {
+            id: RuntimeId { counter: 0 },
+            revision_guard: None,
+            shared_state: Default::default(),
+            local_state: Default::default(),
+        }
+    }
+}
+
+impl std::fmt::Debug for Runtime {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        fmt.debug_struct("Runtime")
+            .field("id", &self.id())
+            .field("forked", &self.revision_guard.is_some())
+            .field("shared_state", &self.shared_state)
+            .finish()
+    }
+}
+
+impl Runtime {
+    /// Create a new runtime; equivalent to `Self::default`. This is
+    /// used when creating a new database.
+    pub fn new() -> Self {
+        Self::default()
+    }
+
+    /// See [`crate::storage::Storage::snapshot`].
+    pub(crate) fn snapshot(&self) -> Self {
+        if self.local_state.query_in_progress() {
+            panic!("it is not legal to `snapshot` during a query (see salsa-rs/salsa#80)");
+        }
+
+        let revision_guard = RevisionGuard::new(&self.shared_state);
+
+        let id = RuntimeId { counter: self.shared_state.next_id.fetch_add(1, Ordering::SeqCst) };
+
+        Runtime {
+            id,
+            revision_guard: Some(revision_guard),
+            shared_state: self.shared_state.clone(),
+            local_state: Default::default(),
+        }
+    }
+
+    /// A "synthetic write" causes the system to act *as though* some
+    /// input of durability `durability` has changed. This is mostly
+    /// useful for profiling scenarios.
+    ///
+    /// **WARNING:** Just like an ordinary write, this method triggers
+    /// cancellation. If you invoke it while a snapshot exists, it
+    /// will block until that snapshot is dropped -- if that snapshot
+    /// is owned by the current thread, this could trigger deadlock.
+    pub fn synthetic_write(&mut self, durability: Durability) {
+        self.with_incremented_revision(|_next_revision| Some(durability));
+    }
+
+    /// The unique identifier attached to this `SalsaRuntime`. Each
+    /// snapshotted runtime has a distinct identifier.
+    #[inline]
+    pub fn id(&self) -> RuntimeId {
+        self.id
+    }
+
+    /// Returns the database-key for the query that this thread is
+    /// actively executing (if any).
+    pub fn active_query(&self) -> Option<DatabaseKeyIndex> {
+        self.local_state.active_query()
+    }
+
+    /// Read current value of the revision counter.
+    #[inline]
+    pub(crate) fn current_revision(&self) -> Revision {
+        self.shared_state.revisions[0].load()
+    }
+
+    /// The revision in which values with durability `d` may have last
+    /// changed.  For D0, this is just the current revision. But for
+    /// higher levels of durability, this value may lag behind the
+    /// current revision. If we encounter a value of durability Di,
+    /// then, we can check this function to get a "bound" on when the
+    /// value may have changed, which allows us to skip walking its
+    /// dependencies.
+    #[inline]
+    pub(crate) fn last_changed_revision(&self, d: Durability) -> Revision {
+        self.shared_state.revisions[d.index()].load()
+    }
+
+    /// Read current value of the revision counter.
+    #[inline]
+    pub(crate) fn pending_revision(&self) -> Revision {
+        self.shared_state.pending_revision.load()
+    }
+
+    #[cold]
+    pub(crate) fn unwind_cancelled(&self) {
+        self.report_untracked_read();
+        Cancelled::PendingWrite.throw();
+    }
+
+    /// Acquires the **global query write lock** (ensuring that no queries are
+    /// executing) and then increments the current revision counter; invokes
+    /// `op` with the global query write lock still held.
+    ///
+    /// While we wait to acquire the global query write lock, this method will
+    /// also increment `pending_revision_increments`, thus signalling to queries
+    /// that their results are "cancelled" and they should abort as expeditiously
+    /// as possible.
+    ///
+    /// The `op` closure should actually perform the writes needed. It is given
+    /// the new revision as an argument, and its return value indicates whether
+    /// any pre-existing value was modified:
+    ///
+    /// - returning `None` means that no pre-existing value was modified (this
+    ///   could occur e.g. when setting some key on an input that was never set
+    ///   before)
+    /// - returning `Some(d)` indicates that a pre-existing value was modified
+    ///   and it had the durability `d`. This will update the records for when
+    ///   values with each durability were modified.
+    ///
+    /// Note that, given our writer model, we can assume that only one thread is
+    /// attempting to increment the global revision at a time.
+    pub(crate) fn with_incremented_revision<F>(&mut self, op: F)
+    where
+        F: FnOnce(Revision) -> Option<Durability>,
+    {
+        tracing::debug!("increment_revision()");
+
+        if !self.permits_increment() {
+            panic!("increment_revision invoked during a query computation");
+        }
+
+        // Set the `pending_revision` field so that people
+        // know current revision is cancelled.
+        let current_revision = self.shared_state.pending_revision.fetch_then_increment();
+
+        // To modify the revision, we need the lock.
+        let shared_state = self.shared_state.clone();
+        let _lock = shared_state.query_lock.write();
+
+        let old_revision = self.shared_state.revisions[0].fetch_then_increment();
+        assert_eq!(current_revision, old_revision);
+
+        let new_revision = current_revision.next();
+
+        debug!("increment_revision: incremented to {:?}", new_revision);
+
+        if let Some(d) = op(new_revision) {
+            for rev in &self.shared_state.revisions[1..=d.index()] {
+                rev.store(new_revision);
+            }
+        }
+    }
+
+    pub(crate) fn permits_increment(&self) -> bool {
+        self.revision_guard.is_none() && !self.local_state.query_in_progress()
+    }
+
+    #[inline]
+    pub(crate) fn push_query(&self, database_key_index: DatabaseKeyIndex) -> ActiveQueryGuard<'_> {
+        self.local_state.push_query(database_key_index)
+    }
+
+    /// Reports that the currently active query read the result from
+    /// another query.
+    ///
+    /// Also checks whether the "cycle participant" flag is set on
+    /// the current stack frame -- if so, panics with `CycleParticipant`
+    /// value, which should be caught by the code executing the query.
+    ///
+    /// # Parameters
+    ///
+    /// - `database_key`: the query whose result was read
+    /// - `changed_revision`: the last revision in which the result of that
+    ///   query had changed
+    pub(crate) fn report_query_read_and_unwind_if_cycle_resulted(
+        &self,
+        input: DatabaseKeyIndex,
+        durability: Durability,
+        changed_at: Revision,
+    ) {
+        self.local_state
+            .report_query_read_and_unwind_if_cycle_resulted(input, durability, changed_at);
+    }
+
+    /// Reports that the query depends on some state unknown to salsa.
+    ///
+    /// Queries which report untracked reads will be re-executed in the next
+    /// revision.
+    pub fn report_untracked_read(&self) {
+        self.local_state.report_untracked_read(self.current_revision());
+    }
+
+    /// Acts as though the current query had read an input with the given durability; this will force the current query's durability to be at most `durability`.
+    ///
+    /// This is mostly useful to control the durability level for [on-demand inputs](https://salsa-rs.github.io/salsa/common_patterns/on_demand_inputs.html).
+    pub fn report_synthetic_read(&self, durability: Durability) {
+        let changed_at = self.last_changed_revision(durability);
+        self.local_state.report_synthetic_read(durability, changed_at);
+    }
+
+    /// Handles a cycle in the dependency graph that was detected when the
+    /// current thread tried to block on `database_key_index` which is being
+    /// executed by `to_id`. If this function returns, then `to_id` no longer
+    /// depends on the current thread, and so we should continue executing
+    /// as normal. Otherwise, the function will throw a `Cycle` which is expected
+    /// to be caught by some frame on our stack. This occurs either if there is
+    /// a frame on our stack with cycle recovery (possibly the top one!) or if there
+    /// is no cycle recovery at all.
+    fn unblock_cycle_and_maybe_throw(
+        &self,
+        db: &dyn Database,
+        dg: &mut DependencyGraph,
+        database_key_index: DatabaseKeyIndex,
+        to_id: RuntimeId,
+    ) {
+        debug!("unblock_cycle_and_maybe_throw(database_key={:?})", database_key_index);
+
+        let mut from_stack = self.local_state.take_query_stack();
+        let from_id = self.id();
+
+        // Make a "dummy stack frame". As we iterate through the cycle, we will collect the
+        // inputs from each participant. Then, if we are participating in cycle recovery, we
+        // will propagate those results to all participants.
+        let mut cycle_query = ActiveQuery::new(database_key_index);
+
+        // Identify the cycle participants:
+        let cycle = {
+            let mut v = vec![];
+            dg.for_each_cycle_participant(
+                from_id,
+                &mut from_stack,
+                database_key_index,
+                to_id,
+                |aqs| {
+                    aqs.iter_mut().for_each(|aq| {
+                        cycle_query.add_from(aq);
+                        v.push(aq.database_key_index);
+                    });
+                },
+            );
+
+            // We want to give the participants in a deterministic order
+            // (at least for this execution, not necessarily across executions),
+            // no matter where it started on the stack. Find the minimum
+            // key and rotate it to the front.
+            let min = v.iter().min().unwrap();
+            let index = v.iter().position(|p| p == min).unwrap();
+            v.rotate_left(index);
+
+            // No need to store extra memory.
+            v.shrink_to_fit();
+
+            Cycle::new(Arc::new(v))
+        };
+        debug!("cycle {:?}, cycle_query {:#?}", cycle.debug(db), cycle_query,);
+
+        // We can remove the cycle participants from the list of dependencies;
+        // they are a strongly connected component (SCC) and we only care about
+        // dependencies to things outside the SCC that control whether it will
+        // form again.
+        cycle_query.remove_cycle_participants(&cycle);
+
+        // Mark each cycle participant that has recovery set, along with
+        // any frames that come after them on the same thread. Those frames
+        // are going to be unwound so that fallback can occur.
+        dg.for_each_cycle_participant(from_id, &mut from_stack, database_key_index, to_id, |aqs| {
+            aqs.iter_mut()
+                .skip_while(|aq| match db.cycle_recovery_strategy(aq.database_key_index) {
+                    CycleRecoveryStrategy::Panic => true,
+                    CycleRecoveryStrategy::Fallback => false,
+                })
+                .for_each(|aq| {
+                    debug!("marking {:?} for fallback", aq.database_key_index.debug(db));
+                    aq.take_inputs_from(&cycle_query);
+                    assert!(aq.cycle.is_none());
+                    aq.cycle = Some(cycle.clone());
+                });
+        });
+
+        // Unblock every thread that has cycle recovery with a `WaitResult::Cycle`.
+        // They will throw the cycle, which will be caught by the frame that has
+        // cycle recovery so that it can execute that recovery.
+        let (me_recovered, others_recovered) =
+            dg.maybe_unblock_runtimes_in_cycle(from_id, &from_stack, database_key_index, to_id);
+
+        self.local_state.restore_query_stack(from_stack);
+
+        if me_recovered {
+            // If the current thread has recovery, we want to throw
+            // so that it can begin.
+            cycle.throw()
+        } else if others_recovered {
+            // If other threads have recovery but we didn't: return and we will block on them.
+        } else {
+            // if nobody has recover, then we panic
+            panic_any(cycle);
+        }
+    }
+
+    /// Block until `other_id` completes executing `database_key`;
+    /// panic or unwind in the case of a cycle.
+    ///
+    /// `query_mutex_guard` is the guard for the current query's state;
+    /// it will be dropped after we have successfully registered the
+    /// dependency.
+    ///
+    /// # Propagating panics
+    ///
+    /// If the thread `other_id` panics, then our thread is considered
+    /// cancelled, so this function will panic with a `Cancelled` value.
+    ///
+    /// # Cycle handling
+    ///
+    /// If the thread `other_id` already depends on the current thread,
+    /// and hence there is a cycle in the query graph, then this function
+    /// will unwind instead of returning normally. The method of unwinding
+    /// depends on the [`Self::mutual_cycle_recovery_strategy`]
+    /// of the cycle participants:
+    ///
+    /// * [`CycleRecoveryStrategy::Panic`]: panic with the [`Cycle`] as the value.
+    /// * [`CycleRecoveryStrategy::Fallback`]: initiate unwinding with [`CycleParticipant::unwind`].
+    pub(crate) fn block_on_or_unwind<QueryMutexGuard>(
+        &self,
+        db: &dyn Database,
+        database_key: DatabaseKeyIndex,
+        other_id: RuntimeId,
+        query_mutex_guard: QueryMutexGuard,
+    ) {
+        let mut dg = self.shared_state.dependency_graph.lock();
+
+        if dg.depends_on(other_id, self.id()) {
+            self.unblock_cycle_and_maybe_throw(db, &mut dg, database_key, other_id);
+
+            // If the above fn returns, then (via cycle recovery) it has unblocked the
+            // cycle, so we can continue.
+            assert!(!dg.depends_on(other_id, self.id()));
+        }
+
+        db.salsa_event(Event {
+            runtime_id: self.id(),
+            kind: EventKind::WillBlockOn { other_runtime_id: other_id, database_key },
+        });
+
+        let stack = self.local_state.take_query_stack();
+
+        let (stack, result) = DependencyGraph::block_on(
+            dg,
+            self.id(),
+            database_key,
+            other_id,
+            stack,
+            query_mutex_guard,
+        );
+
+        self.local_state.restore_query_stack(stack);
+
+        match result {
+            WaitResult::Completed => (),
+
+            // If the other thread panicked, then we consider this thread
+            // cancelled. The assumption is that the panic will be detected
+            // by the other thread and responded to appropriately.
+            WaitResult::Panicked => Cancelled::PropagatedPanic.throw(),
+
+            WaitResult::Cycle(c) => c.throw(),
+        }
+    }
+
+    /// Invoked when this runtime completed computing `database_key` with
+    /// the given result `wait_result` (`wait_result` should be `None` if
+    /// computing `database_key` panicked and could not complete).
+    /// This function unblocks any dependent queries and allows them
+    /// to continue executing.
+    pub(crate) fn unblock_queries_blocked_on(
+        &self,
+        database_key: DatabaseKeyIndex,
+        wait_result: WaitResult,
+    ) {
+        self.shared_state
+            .dependency_graph
+            .lock()
+            .unblock_runtimes_blocked_on(database_key, wait_result);
+    }
+}
+
+/// State that will be common to all threads (when we support multiple threads)
+struct SharedState {
+    /// Stores the next id to use for a snapshotted runtime (starts at 1).
+    next_id: AtomicUsize,
+
+    /// Whenever derived queries are executing, they acquire this lock
+    /// in read mode. Mutating inputs (and thus creating a new
+    /// revision) requires a write lock (thus guaranteeing that no
+    /// derived queries are in progress). Note that this is not needed
+    /// to prevent **race conditions** -- the revision counter itself
+    /// is stored in an `AtomicUsize` so it can be cheaply read
+    /// without acquiring the lock.  Rather, the `query_lock` is used
+    /// to ensure a higher-level consistency property.
+    query_lock: RwLock<()>,
+
+    /// This is typically equal to `revision` -- set to `revision+1`
+    /// when a new revision is pending (which implies that the current
+    /// revision is cancelled).
+    pending_revision: AtomicRevision,
+
+    /// Stores the "last change" revision for values of each duration.
+    /// This vector is always of length at least 1 (for Durability 0)
+    /// but its total length depends on the number of durations. The
+    /// element at index 0 is special as it represents the "current
+    /// revision".  In general, we have the invariant that revisions
+    /// in here are *declining* -- that is, `revisions[i] >=
+    /// revisions[i + 1]`, for all `i`. This is because when you
+    /// modify a value with durability D, that implies that values
+    /// with durability less than D may have changed too.
+    revisions: Vec<AtomicRevision>,
+
+    /// The dependency graph tracks which runtimes are blocked on one
+    /// another, waiting for queries to terminate.
+    dependency_graph: Mutex<DependencyGraph>,
+}
+
+impl SharedState {
+    fn with_durabilities(durabilities: usize) -> Self {
+        SharedState {
+            next_id: AtomicUsize::new(1),
+            query_lock: Default::default(),
+            revisions: (0..durabilities).map(|_| AtomicRevision::start()).collect(),
+            pending_revision: AtomicRevision::start(),
+            dependency_graph: Default::default(),
+        }
+    }
+}
+
+impl std::panic::RefUnwindSafe for SharedState {}
+
+impl Default for SharedState {
+    fn default() -> Self {
+        Self::with_durabilities(Durability::LEN)
+    }
+}
+
+impl std::fmt::Debug for SharedState {
+    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        let query_lock = if self.query_lock.try_write().is_some() {
+            "<unlocked>"
+        } else if self.query_lock.try_read().is_some() {
+            "<rlocked>"
+        } else {
+            "<wlocked>"
+        };
+        fmt.debug_struct("SharedState")
+            .field("query_lock", &query_lock)
+            .field("revisions", &self.revisions)
+            .field("pending_revision", &self.pending_revision)
+            .finish()
+    }
+}
+
+#[derive(Debug)]
+struct ActiveQuery {
+    /// What query is executing
+    database_key_index: DatabaseKeyIndex,
+
+    /// Minimum durability of inputs observed so far.
+    durability: Durability,
+
+    /// Maximum revision of all inputs observed. If we observe an
+    /// untracked read, this will be set to the most recent revision.
+    changed_at: Revision,
+
+    /// Set of subqueries that were accessed thus far, or `None` if
+    /// there was an untracked the read.
+    dependencies: Option<FxIndexSet<DatabaseKeyIndex>>,
+
+    /// Stores the entire cycle, if one is found and this query is part of it.
+    cycle: Option<Cycle>,
+}
+
+impl ActiveQuery {
+    fn new(database_key_index: DatabaseKeyIndex) -> Self {
+        ActiveQuery {
+            database_key_index,
+            durability: Durability::MAX,
+            changed_at: Revision::start(),
+            dependencies: Some(FxIndexSet::default()),
+            cycle: None,
+        }
+    }
+
+    fn add_read(&mut self, input: DatabaseKeyIndex, durability: Durability, revision: Revision) {
+        if let Some(set) = &mut self.dependencies {
+            set.insert(input);
+        }
+
+        self.durability = self.durability.min(durability);
+        self.changed_at = self.changed_at.max(revision);
+    }
+
+    fn add_untracked_read(&mut self, changed_at: Revision) {
+        self.dependencies = None;
+        self.durability = Durability::LOW;
+        self.changed_at = changed_at;
+    }
+
+    fn add_synthetic_read(&mut self, durability: Durability, revision: Revision) {
+        self.dependencies = None;
+        self.durability = self.durability.min(durability);
+        self.changed_at = self.changed_at.max(revision);
+    }
+
+    pub(crate) fn revisions(&self) -> QueryRevisions {
+        let inputs = match &self.dependencies {
+            None => QueryInputs::Untracked,
+
+            Some(dependencies) => {
+                if dependencies.is_empty() {
+                    QueryInputs::NoInputs
+                } else {
+                    QueryInputs::Tracked { inputs: dependencies.iter().copied().collect() }
+                }
+            }
+        };
+
+        QueryRevisions { changed_at: self.changed_at, inputs, durability: self.durability }
+    }
+
+    /// Adds any dependencies from `other` into `self`.
+    /// Used during cycle recovery, see [`Runtime::create_cycle_error`].
+    fn add_from(&mut self, other: &ActiveQuery) {
+        self.changed_at = self.changed_at.max(other.changed_at);
+        self.durability = self.durability.min(other.durability);
+        if let Some(other_dependencies) = &other.dependencies {
+            if let Some(my_dependencies) = &mut self.dependencies {
+                my_dependencies.extend(other_dependencies.iter().copied());
+            }
+        } else {
+            self.dependencies = None;
+        }
+    }
+
+    /// Removes the participants in `cycle` from my dependencies.
+    /// Used during cycle recovery, see [`Runtime::create_cycle_error`].
+    fn remove_cycle_participants(&mut self, cycle: &Cycle) {
+        if let Some(my_dependencies) = &mut self.dependencies {
+            for p in cycle.participant_keys() {
+                my_dependencies.remove(&p);
+            }
+        }
+    }
+
+    /// Copy the changed-at, durability, and dependencies from `cycle_query`.
+    /// Used during cycle recovery, see [`Runtime::create_cycle_error`].
+    pub(crate) fn take_inputs_from(&mut self, cycle_query: &ActiveQuery) {
+        self.changed_at = cycle_query.changed_at;
+        self.durability = cycle_query.durability;
+        self.dependencies = cycle_query.dependencies.clone();
+    }
+}
+
+/// A unique identifier for a particular runtime. Each time you create
+/// a snapshot, a fresh `RuntimeId` is generated. Once a snapshot is
+/// complete, its `RuntimeId` may potentially be re-used.
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
+pub struct RuntimeId {
+    counter: usize,
+}
+
+#[derive(Clone, Debug)]
+pub(crate) struct StampedValue<V> {
+    pub(crate) value: V,
+    pub(crate) durability: Durability,
+    pub(crate) changed_at: Revision,
+}
+
+struct RevisionGuard {
+    shared_state: Arc<SharedState>,
+}
+
+impl RevisionGuard {
+    fn new(shared_state: &Arc<SharedState>) -> Self {
+        // Subtle: we use a "recursive" lock here so that it is not an
+        // error to acquire a read-lock when one is already held (this
+        // happens when a query uses `snapshot` to spawn off parallel
+        // workers, for example).
+        //
+        // This has the side-effect that we are responsible to ensure
+        // that people contending for the write lock do not starve,
+        // but this is what we achieve via the cancellation mechanism.
+        //
+        // (In particular, since we only ever have one "mutating
+        // handle" to the database, the only contention for the global
+        // query lock occurs when there are "futures" evaluating
+        // queries in parallel, and those futures hold a read-lock
+        // already, so the starvation problem is more about them bring
+        // themselves to a close, versus preventing other people from
+        // *starting* work).
+        unsafe {
+            shared_state.query_lock.raw().lock_shared_recursive();
+        }
+
+        Self { shared_state: shared_state.clone() }
+    }
+}
+
+impl Drop for RevisionGuard {
+    fn drop(&mut self) {
+        // Release our read-lock without using RAII. As documented in
+        // `Snapshot::new` above, this requires the unsafe keyword.
+        unsafe {
+            self.shared_state.query_lock.raw().unlock_shared();
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs
new file mode 100644
index 00000000000..e41eb280dee
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/dependency_graph.rs
@@ -0,0 +1,251 @@
+//!
+use triomphe::Arc;
+
+use crate::{DatabaseKeyIndex, RuntimeId};
+use parking_lot::{Condvar, MutexGuard};
+use rustc_hash::FxHashMap;
+use smallvec::SmallVec;
+
+use super::{ActiveQuery, WaitResult};
+
+type QueryStack = Vec<ActiveQuery>;
+
+#[derive(Debug, Default)]
+pub(super) struct DependencyGraph {
+    /// A `(K -> V)` pair in this map indicates that the the runtime
+    /// `K` is blocked on some query executing in the runtime `V`.
+    /// This encodes a graph that must be acyclic (or else deadlock
+    /// will result).
+    edges: FxHashMap<RuntimeId, Edge>,
+
+    /// Encodes the `RuntimeId` that are blocked waiting for the result
+    /// of a given query.
+    query_dependents: FxHashMap<DatabaseKeyIndex, SmallVec<[RuntimeId; 4]>>,
+
+    /// When a key K completes which had dependent queries Qs blocked on it,
+    /// it stores its `WaitResult` here. As they wake up, each query Q in Qs will
+    /// come here to fetch their results.
+    wait_results: FxHashMap<RuntimeId, (QueryStack, WaitResult)>,
+}
+
+#[derive(Debug)]
+struct Edge {
+    blocked_on_id: RuntimeId,
+    blocked_on_key: DatabaseKeyIndex,
+    stack: QueryStack,
+
+    /// Signalled whenever a query with dependents completes.
+    /// Allows those dependents to check if they are ready to unblock.
+    condvar: Arc<parking_lot::Condvar>,
+}
+
+impl DependencyGraph {
+    /// True if `from_id` depends on `to_id`.
+    ///
+    /// (i.e., there is a path from `from_id` to `to_id` in the graph.)
+    pub(super) fn depends_on(&mut self, from_id: RuntimeId, to_id: RuntimeId) -> bool {
+        let mut p = from_id;
+        while let Some(q) = self.edges.get(&p).map(|edge| edge.blocked_on_id) {
+            if q == to_id {
+                return true;
+            }
+
+            p = q;
+        }
+        p == to_id
+    }
+
+    /// Invokes `closure` with a `&mut ActiveQuery` for each query that participates in the cycle.
+    /// The cycle runs as follows:
+    ///
+    /// 1. The runtime `from_id`, which has the stack `from_stack`, would like to invoke `database_key`...
+    /// 2. ...but `database_key` is already being executed by `to_id`...
+    /// 3. ...and `to_id` is transitively dependent on something which is present on `from_stack`.
+    pub(super) fn for_each_cycle_participant(
+        &mut self,
+        from_id: RuntimeId,
+        from_stack: &mut QueryStack,
+        database_key: DatabaseKeyIndex,
+        to_id: RuntimeId,
+        mut closure: impl FnMut(&mut [ActiveQuery]),
+    ) {
+        debug_assert!(self.depends_on(to_id, from_id));
+
+        // To understand this algorithm, consider this [drawing](https://is.gd/TGLI9v):
+        //
+        //    database_key = QB2
+        //    from_id = A
+        //    to_id = B
+        //    from_stack = [QA1, QA2, QA3]
+        //
+        //    self.edges[B] = { C, QC2, [QB1..QB3] }
+        //    self.edges[C] = { A, QA2, [QC1..QC3] }
+        //
+        //         The cyclic
+        //         edge we have
+        //         failed to add.
+        //           :
+        //    A      :    B         C
+        //           :
+        //    QA1    v    QB1       QC1
+        // ┌► QA2    ┌──► QB2   ┌─► QC2
+        // │  QA3 ───┘    QB3 ──┘   QC3 ───┐
+        // │                               │
+        // └───────────────────────────────┘
+        //
+        // Final output: [QB2, QB3, QC2, QC3, QA2, QA3]
+
+        let mut id = to_id;
+        let mut key = database_key;
+        while id != from_id {
+            // Looking at the diagram above, the idea is to
+            // take the edge from `to_id` starting at `key`
+            // (inclusive) and down to the end. We can then
+            // load up the next thread (i.e., we start at B/QB2,
+            // and then load up the dependency on C/QC2).
+            let edge = self.edges.get_mut(&id).unwrap();
+            let prefix = edge.stack.iter_mut().take_while(|p| p.database_key_index != key).count();
+            closure(&mut edge.stack[prefix..]);
+            id = edge.blocked_on_id;
+            key = edge.blocked_on_key;
+        }
+
+        // Finally, we copy in the results from `from_stack`.
+        let prefix = from_stack.iter_mut().take_while(|p| p.database_key_index != key).count();
+        closure(&mut from_stack[prefix..]);
+    }
+
+    /// Unblock each blocked runtime (excluding the current one) if some
+    /// query executing in that runtime is participating in cycle fallback.
+    ///
+    /// Returns a boolean (Current, Others) where:
+    /// * Current is true if the current runtime has cycle participants
+    ///   with fallback;
+    /// * Others is true if other runtimes were unblocked.
+    pub(super) fn maybe_unblock_runtimes_in_cycle(
+        &mut self,
+        from_id: RuntimeId,
+        from_stack: &QueryStack,
+        database_key: DatabaseKeyIndex,
+        to_id: RuntimeId,
+    ) -> (bool, bool) {
+        // See diagram in `for_each_cycle_participant`.
+        let mut id = to_id;
+        let mut key = database_key;
+        let mut others_unblocked = false;
+        while id != from_id {
+            let edge = self.edges.get(&id).unwrap();
+            let prefix = edge.stack.iter().take_while(|p| p.database_key_index != key).count();
+            let next_id = edge.blocked_on_id;
+            let next_key = edge.blocked_on_key;
+
+            if let Some(cycle) = edge.stack[prefix..].iter().rev().find_map(|aq| aq.cycle.clone()) {
+                // Remove `id` from the list of runtimes blocked on `next_key`:
+                self.query_dependents.get_mut(&next_key).unwrap().retain(|r| *r != id);
+
+                // Unblock runtime so that it can resume execution once lock is released:
+                self.unblock_runtime(id, WaitResult::Cycle(cycle));
+
+                others_unblocked = true;
+            }
+
+            id = next_id;
+            key = next_key;
+        }
+
+        let prefix = from_stack.iter().take_while(|p| p.database_key_index != key).count();
+        let this_unblocked = from_stack[prefix..].iter().any(|aq| aq.cycle.is_some());
+
+        (this_unblocked, others_unblocked)
+    }
+
+    /// Modifies the graph so that `from_id` is blocked
+    /// on `database_key`, which is being computed by
+    /// `to_id`.
+    ///
+    /// For this to be reasonable, the lock on the
+    /// results table for `database_key` must be held.
+    /// This ensures that computing `database_key` doesn't
+    /// complete before `block_on` executes.
+    ///
+    /// Preconditions:
+    /// * No path from `to_id` to `from_id`
+    ///   (i.e., `me.depends_on(to_id, from_id)` is false)
+    /// * `held_mutex` is a read lock (or stronger) on `database_key`
+    pub(super) fn block_on<QueryMutexGuard>(
+        mut me: MutexGuard<'_, Self>,
+        from_id: RuntimeId,
+        database_key: DatabaseKeyIndex,
+        to_id: RuntimeId,
+        from_stack: QueryStack,
+        query_mutex_guard: QueryMutexGuard,
+    ) -> (QueryStack, WaitResult) {
+        let condvar = me.add_edge(from_id, database_key, to_id, from_stack);
+
+        // Release the mutex that prevents `database_key`
+        // from completing, now that the edge has been added.
+        drop(query_mutex_guard);
+
+        loop {
+            if let Some(stack_and_result) = me.wait_results.remove(&from_id) {
+                debug_assert!(!me.edges.contains_key(&from_id));
+                return stack_and_result;
+            }
+            condvar.wait(&mut me);
+        }
+    }
+
+    /// Helper for `block_on`: performs actual graph modification
+    /// to add a dependency edge from `from_id` to `to_id`, which is
+    /// computing `database_key`.
+    fn add_edge(
+        &mut self,
+        from_id: RuntimeId,
+        database_key: DatabaseKeyIndex,
+        to_id: RuntimeId,
+        from_stack: QueryStack,
+    ) -> Arc<parking_lot::Condvar> {
+        assert_ne!(from_id, to_id);
+        debug_assert!(!self.edges.contains_key(&from_id));
+        debug_assert!(!self.depends_on(to_id, from_id));
+
+        let condvar = Arc::new(Condvar::new());
+        self.edges.insert(
+            from_id,
+            Edge {
+                blocked_on_id: to_id,
+                blocked_on_key: database_key,
+                stack: from_stack,
+                condvar: condvar.clone(),
+            },
+        );
+        self.query_dependents.entry(database_key).or_default().push(from_id);
+        condvar
+    }
+
+    /// Invoked when runtime `to_id` completes executing
+    /// `database_key`.
+    pub(super) fn unblock_runtimes_blocked_on(
+        &mut self,
+        database_key: DatabaseKeyIndex,
+        wait_result: WaitResult,
+    ) {
+        let dependents = self.query_dependents.remove(&database_key).unwrap_or_default();
+
+        for from_id in dependents {
+            self.unblock_runtime(from_id, wait_result.clone());
+        }
+    }
+
+    /// Unblock the runtime with the given id with the given wait-result.
+    /// This will cause it resume execution (though it will have to grab
+    /// the lock on this data structure first, to recover the wait result).
+    fn unblock_runtime(&mut self, id: RuntimeId, wait_result: WaitResult) {
+        let edge = self.edges.remove(&id).expect("not blocked");
+        self.wait_results.insert(id, (edge.stack, wait_result));
+
+        // Now that we have inserted the `wait_results`,
+        // notify the thread.
+        edge.condvar.notify_one();
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs
new file mode 100644
index 00000000000..91b95dffe78
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/runtime/local_state.rs
@@ -0,0 +1,214 @@
+//!
+use tracing::debug;
+
+use crate::durability::Durability;
+use crate::runtime::ActiveQuery;
+use crate::runtime::Revision;
+use crate::Cycle;
+use crate::DatabaseKeyIndex;
+use std::cell::RefCell;
+use triomphe::Arc;
+
+/// State that is specific to a single execution thread.
+///
+/// Internally, this type uses ref-cells.
+///
+/// **Note also that all mutations to the database handle (and hence
+/// to the local-state) must be undone during unwinding.**
+pub(super) struct LocalState {
+    /// Vector of active queries.
+    ///
+    /// This is normally `Some`, but it is set to `None`
+    /// while the query is blocked waiting for a result.
+    ///
+    /// Unwinding note: pushes onto this vector must be popped -- even
+    /// during unwinding.
+    query_stack: RefCell<Option<Vec<ActiveQuery>>>,
+}
+
+/// Summarizes "all the inputs that a query used"
+#[derive(Debug, Clone)]
+pub(crate) struct QueryRevisions {
+    /// The most revision in which some input changed.
+    pub(crate) changed_at: Revision,
+
+    /// Minimum durability of the inputs to this query.
+    pub(crate) durability: Durability,
+
+    /// The inputs that went into our query, if we are tracking them.
+    pub(crate) inputs: QueryInputs,
+}
+
+/// Every input.
+#[derive(Debug, Clone)]
+pub(crate) enum QueryInputs {
+    /// Non-empty set of inputs, fully known
+    Tracked { inputs: Arc<[DatabaseKeyIndex]> },
+
+    /// Empty set of inputs, fully known.
+    NoInputs,
+
+    /// Unknown quantity of inputs
+    Untracked,
+}
+
+impl Default for LocalState {
+    fn default() -> Self {
+        LocalState { query_stack: RefCell::new(Some(Vec::new())) }
+    }
+}
+
+impl LocalState {
+    #[inline]
+    pub(super) fn push_query(&self, database_key_index: DatabaseKeyIndex) -> ActiveQueryGuard<'_> {
+        let mut query_stack = self.query_stack.borrow_mut();
+        let query_stack = query_stack.as_mut().expect("local stack taken");
+        query_stack.push(ActiveQuery::new(database_key_index));
+        ActiveQueryGuard { local_state: self, database_key_index, push_len: query_stack.len() }
+    }
+
+    fn with_query_stack<R>(&self, c: impl FnOnce(&mut Vec<ActiveQuery>) -> R) -> R {
+        c(self.query_stack.borrow_mut().as_mut().expect("query stack taken"))
+    }
+
+    pub(super) fn query_in_progress(&self) -> bool {
+        self.with_query_stack(|stack| !stack.is_empty())
+    }
+
+    pub(super) fn active_query(&self) -> Option<DatabaseKeyIndex> {
+        self.with_query_stack(|stack| {
+            stack.last().map(|active_query| active_query.database_key_index)
+        })
+    }
+
+    pub(super) fn report_query_read_and_unwind_if_cycle_resulted(
+        &self,
+        input: DatabaseKeyIndex,
+        durability: Durability,
+        changed_at: Revision,
+    ) {
+        debug!(
+            "report_query_read_and_unwind_if_cycle_resulted(input={:?}, durability={:?}, changed_at={:?})",
+            input, durability, changed_at
+        );
+        self.with_query_stack(|stack| {
+            if let Some(top_query) = stack.last_mut() {
+                top_query.add_read(input, durability, changed_at);
+
+                // We are a cycle participant:
+                //
+                //     C0 --> ... --> Ci --> Ci+1 -> ... -> Cn --> C0
+                //                        ^   ^
+                //                        :   |
+                //         This edge -----+   |
+                //                            |
+                //                            |
+                //                            N0
+                //
+                // In this case, the value we have just read from `Ci+1`
+                // is actually the cycle fallback value and not especially
+                // interesting. We unwind now with `CycleParticipant` to avoid
+                // executing the rest of our query function. This unwinding
+                // will be caught and our own fallback value will be used.
+                //
+                // Note that `Ci+1` may` have *other* callers who are not
+                // participants in the cycle (e.g., N0 in the graph above).
+                // They will not have the `cycle` marker set in their
+                // stack frames, so they will just read the fallback value
+                // from `Ci+1` and continue on their merry way.
+                if let Some(cycle) = &top_query.cycle {
+                    cycle.clone().throw()
+                }
+            }
+        })
+    }
+
+    pub(super) fn report_untracked_read(&self, current_revision: Revision) {
+        self.with_query_stack(|stack| {
+            if let Some(top_query) = stack.last_mut() {
+                top_query.add_untracked_read(current_revision);
+            }
+        })
+    }
+
+    /// Update the top query on the stack to act as though it read a value
+    /// of durability `durability` which changed in `revision`.
+    pub(super) fn report_synthetic_read(&self, durability: Durability, revision: Revision) {
+        self.with_query_stack(|stack| {
+            if let Some(top_query) = stack.last_mut() {
+                top_query.add_synthetic_read(durability, revision);
+            }
+        })
+    }
+
+    /// Takes the query stack and returns it. This is used when
+    /// the current thread is blocking. The stack must be restored
+    /// with [`Self::restore_query_stack`] when the thread unblocks.
+    pub(super) fn take_query_stack(&self) -> Vec<ActiveQuery> {
+        assert!(self.query_stack.borrow().is_some(), "query stack already taken");
+        self.query_stack.take().unwrap()
+    }
+
+    /// Restores a query stack taken with [`Self::take_query_stack`] once
+    /// the thread unblocks.
+    pub(super) fn restore_query_stack(&self, stack: Vec<ActiveQuery>) {
+        assert!(self.query_stack.borrow().is_none(), "query stack not taken");
+        self.query_stack.replace(Some(stack));
+    }
+}
+
+impl std::panic::RefUnwindSafe for LocalState {}
+
+/// When a query is pushed onto the `active_query` stack, this guard
+/// is returned to represent its slot. The guard can be used to pop
+/// the query from the stack -- in the case of unwinding, the guard's
+/// destructor will also remove the query.
+pub(crate) struct ActiveQueryGuard<'me> {
+    local_state: &'me LocalState,
+    push_len: usize,
+    database_key_index: DatabaseKeyIndex,
+}
+
+impl ActiveQueryGuard<'_> {
+    fn pop_helper(&self) -> ActiveQuery {
+        self.local_state.with_query_stack(|stack| {
+            // Sanity check: pushes and pops should be balanced.
+            assert_eq!(stack.len(), self.push_len);
+            debug_assert_eq!(stack.last().unwrap().database_key_index, self.database_key_index);
+            stack.pop().unwrap()
+        })
+    }
+
+    /// Invoked when the query has successfully completed execution.
+    pub(super) fn complete(self) -> ActiveQuery {
+        let query = self.pop_helper();
+        std::mem::forget(self);
+        query
+    }
+
+    /// Pops an active query from the stack. Returns the [`QueryRevisions`]
+    /// which summarizes the other queries that were accessed during this
+    /// query's execution.
+    #[inline]
+    pub(crate) fn pop(self) -> QueryRevisions {
+        // Extract accumulated inputs.
+        let popped_query = self.complete();
+
+        // If this frame were a cycle participant, it would have unwound.
+        assert!(popped_query.cycle.is_none());
+
+        popped_query.revisions()
+    }
+
+    /// If the active query is registered as a cycle participant, remove and
+    /// return that cycle.
+    pub(crate) fn take_cycle(&self) -> Option<Cycle> {
+        self.local_state.with_query_stack(|stack| stack.last_mut()?.cycle.take())
+    }
+}
+
+impl Drop for ActiveQueryGuard<'_> {
+    fn drop(&mut self) {
+        self.pop_helper();
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/src/storage.rs b/src/tools/rust-analyzer/crates/salsa/src/storage.rs
new file mode 100644
index 00000000000..c0e6416f4a3
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/src/storage.rs
@@ -0,0 +1,54 @@
+//!
+use crate::{plumbing::DatabaseStorageTypes, Runtime};
+use triomphe::Arc;
+
+/// Stores the cached results and dependency information for all the queries
+/// defined on your salsa database. Also embeds a [`Runtime`] which is used to
+/// manage query execution. Every database must include a `storage:
+/// Storage<Self>` field.
+pub struct Storage<DB: DatabaseStorageTypes> {
+    query_store: Arc<DB::DatabaseStorage>,
+    runtime: Runtime,
+}
+
+impl<DB: DatabaseStorageTypes> Default for Storage<DB> {
+    fn default() -> Self {
+        Self { query_store: Default::default(), runtime: Default::default() }
+    }
+}
+
+impl<DB: DatabaseStorageTypes> Storage<DB> {
+    /// Gives access to the underlying salsa runtime.
+    pub fn salsa_runtime(&self) -> &Runtime {
+        &self.runtime
+    }
+
+    /// Gives access to the underlying salsa runtime.
+    pub fn salsa_runtime_mut(&mut self) -> &mut Runtime {
+        &mut self.runtime
+    }
+
+    /// Access the query storage tables. Not meant to be used directly by end
+    /// users.
+    pub fn query_store(&self) -> &DB::DatabaseStorage {
+        &self.query_store
+    }
+
+    /// Access the query storage tables. Not meant to be used directly by end
+    /// users.
+    pub fn query_store_mut(&mut self) -> (&DB::DatabaseStorage, &mut Runtime) {
+        (&self.query_store, &mut self.runtime)
+    }
+
+    /// Returns a "snapshotted" storage, suitable for use in a forked database.
+    /// This snapshot hold a read-lock on the global state, which means that any
+    /// attempt to `set` an input will block until the forked runtime is
+    /// dropped. See `ParallelDatabase::snapshot` for more information.
+    ///
+    /// **Warning.** This second handle is intended to be used from a separate
+    /// thread. Using two database handles from the **same thread** can lead to
+    /// deadlock.
+    pub fn snapshot(&self) -> Self {
+        Storage { query_store: self.query_store.clone(), runtime: self.runtime.snapshot() }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs
new file mode 100644
index 00000000000..00ca5332440
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/cycles.rs
@@ -0,0 +1,493 @@
+use std::panic::UnwindSafe;
+
+use expect_test::expect;
+use salsa::{Durability, ParallelDatabase, Snapshot};
+use test_log::test;
+
+// Axes:
+//
+// Threading
+// * Intra-thread
+// * Cross-thread -- part of cycle is on one thread, part on another
+//
+// Recovery strategies:
+// * Panic
+// * Fallback
+// * Mixed -- multiple strategies within cycle participants
+//
+// Across revisions:
+// * N/A -- only one revision
+// * Present in new revision, not old
+// * Present in old revision, not new
+// * Present in both revisions
+//
+// Dependencies
+// * Tracked
+// * Untracked -- cycle participant(s) contain untracked reads
+//
+// Layers
+// * Direct -- cycle participant is directly invoked from test
+// * Indirect -- invoked a query that invokes the cycle
+//
+//
+// | Thread | Recovery | Old, New | Dep style | Layers   | Test Name      |
+// | ------ | -------- | -------- | --------- | ------   | ---------      |
+// | Intra  | Panic    | N/A      | Tracked   | direct   | cycle_memoized |
+// | Intra  | Panic    | N/A      | Untracked | direct   | cycle_volatile |
+// | Intra  | Fallback | N/A      | Tracked   | direct   | cycle_cycle  |
+// | Intra  | Fallback | N/A      | Tracked   | indirect | inner_cycle |
+// | Intra  | Fallback | Both     | Tracked   | direct   | cycle_revalidate |
+// | Intra  | Fallback | New      | Tracked   | direct   | cycle_appears |
+// | Intra  | Fallback | Old      | Tracked   | direct   | cycle_disappears |
+// | Intra  | Fallback | Old      | Tracked   | direct   | cycle_disappears_durability |
+// | Intra  | Mixed    | N/A      | Tracked   | direct   | cycle_mixed_1 |
+// | Intra  | Mixed    | N/A      | Tracked   | direct   | cycle_mixed_2 |
+// | Cross  | Fallback | N/A      | Tracked   | both     | parallel/cycles.rs: recover_parallel_cycle |
+// | Cross  | Panic    | N/A      | Tracked   | both     | parallel/cycles.rs: panic_parallel_cycle |
+
+#[derive(PartialEq, Eq, Hash, Clone, Debug)]
+struct Error {
+    cycle: Vec<String>,
+}
+
+#[salsa::database(GroupStruct)]
+#[derive(Default)]
+struct DatabaseImpl {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DatabaseImpl {}
+
+impl ParallelDatabase for DatabaseImpl {
+    fn snapshot(&self) -> Snapshot<Self> {
+        Snapshot::new(DatabaseImpl { storage: self.storage.snapshot() })
+    }
+}
+
+/// The queries A, B, and C in `Database` can be configured
+/// to invoke one another in arbitrary ways using this
+/// enum.
+#[derive(Debug, Copy, Clone, PartialEq, Eq)]
+enum CycleQuery {
+    None,
+    A,
+    B,
+    C,
+    AthenC,
+}
+
+#[salsa::query_group(GroupStruct)]
+trait Database: salsa::Database {
+    // `a` and `b` depend on each other and form a cycle
+    fn memoized_a(&self) -> ();
+    fn memoized_b(&self) -> ();
+    fn volatile_a(&self) -> ();
+    fn volatile_b(&self) -> ();
+
+    #[salsa::input]
+    fn a_invokes(&self) -> CycleQuery;
+
+    #[salsa::input]
+    fn b_invokes(&self) -> CycleQuery;
+
+    #[salsa::input]
+    fn c_invokes(&self) -> CycleQuery;
+
+    #[salsa::cycle(recover_a)]
+    fn cycle_a(&self) -> Result<(), Error>;
+
+    #[salsa::cycle(recover_b)]
+    fn cycle_b(&self) -> Result<(), Error>;
+
+    fn cycle_c(&self) -> Result<(), Error>;
+}
+
+fn recover_a(db: &dyn Database, cycle: &salsa::Cycle) -> Result<(), Error> {
+    Err(Error { cycle: cycle.all_participants(db) })
+}
+
+fn recover_b(db: &dyn Database, cycle: &salsa::Cycle) -> Result<(), Error> {
+    Err(Error { cycle: cycle.all_participants(db) })
+}
+
+fn memoized_a(db: &dyn Database) {
+    db.memoized_b()
+}
+
+fn memoized_b(db: &dyn Database) {
+    db.memoized_a()
+}
+
+fn volatile_a(db: &dyn Database) {
+    db.salsa_runtime().report_untracked_read();
+    db.volatile_b()
+}
+
+fn volatile_b(db: &dyn Database) {
+    db.salsa_runtime().report_untracked_read();
+    db.volatile_a()
+}
+
+impl CycleQuery {
+    fn invoke(self, db: &dyn Database) -> Result<(), Error> {
+        match self {
+            CycleQuery::A => db.cycle_a(),
+            CycleQuery::B => db.cycle_b(),
+            CycleQuery::C => db.cycle_c(),
+            CycleQuery::AthenC => {
+                let _ = db.cycle_a();
+                db.cycle_c()
+            }
+            CycleQuery::None => Ok(()),
+        }
+    }
+}
+
+fn cycle_a(db: &dyn Database) -> Result<(), Error> {
+    db.a_invokes().invoke(db)
+}
+
+fn cycle_b(db: &dyn Database) -> Result<(), Error> {
+    db.b_invokes().invoke(db)
+}
+
+fn cycle_c(db: &dyn Database) -> Result<(), Error> {
+    db.c_invokes().invoke(db)
+}
+
+#[track_caller]
+fn extract_cycle(f: impl FnOnce() + UnwindSafe) -> salsa::Cycle {
+    let v = std::panic::catch_unwind(f);
+    if let Err(d) = &v {
+        if let Some(cycle) = d.downcast_ref::<salsa::Cycle>() {
+            return cycle.clone();
+        }
+    }
+    panic!("unexpected value: {:?}", v)
+}
+
+#[test]
+fn cycle_memoized() {
+    let db = DatabaseImpl::default();
+    let cycle = extract_cycle(|| db.memoized_a());
+    expect![[r#"
+        [
+            "memoized_a(())",
+            "memoized_b(())",
+        ]
+    "#]]
+    .assert_debug_eq(&cycle.unexpected_participants(&db));
+}
+
+#[test]
+fn cycle_volatile() {
+    let db = DatabaseImpl::default();
+    let cycle = extract_cycle(|| db.volatile_a());
+    expect![[r#"
+        [
+            "volatile_a(())",
+            "volatile_b(())",
+        ]
+    "#]]
+    .assert_debug_eq(&cycle.unexpected_participants(&db));
+}
+
+#[test]
+fn cycle_cycle() {
+    let mut query = DatabaseImpl::default();
+
+    //     A --> B
+    //     ^     |
+    //     +-----+
+
+    query.set_a_invokes(CycleQuery::B);
+    query.set_b_invokes(CycleQuery::A);
+
+    assert!(query.cycle_a().is_err());
+}
+
+#[test]
+fn inner_cycle() {
+    let mut query = DatabaseImpl::default();
+
+    //     A --> B <-- C
+    //     ^     |
+    //     +-----+
+
+    query.set_a_invokes(CycleQuery::B);
+    query.set_b_invokes(CycleQuery::A);
+    query.set_c_invokes(CycleQuery::B);
+
+    let err = query.cycle_c();
+    assert!(err.is_err());
+    let cycle = err.unwrap_err().cycle;
+    expect![[r#"
+        [
+            "cycle_a(())",
+            "cycle_b(())",
+        ]
+    "#]]
+    .assert_debug_eq(&cycle);
+}
+
+#[test]
+fn cycle_revalidate() {
+    let mut db = DatabaseImpl::default();
+
+    //     A --> B
+    //     ^     |
+    //     +-----+
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::A);
+
+    assert!(db.cycle_a().is_err());
+    db.set_b_invokes(CycleQuery::A); // same value as default
+    assert!(db.cycle_a().is_err());
+}
+
+#[test]
+fn cycle_revalidate_unchanged_twice() {
+    let mut db = DatabaseImpl::default();
+
+    //     A --> B
+    //     ^     |
+    //     +-----+
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::A);
+
+    assert!(db.cycle_a().is_err());
+    db.set_c_invokes(CycleQuery::A); // force new revisi5on
+
+    // on this run
+    expect![[r#"
+        Err(
+            Error {
+                cycle: [
+                    "cycle_a(())",
+                    "cycle_b(())",
+                ],
+            },
+        )
+    "#]]
+    .assert_debug_eq(&db.cycle_a());
+}
+
+#[test]
+fn cycle_appears() {
+    let mut db = DatabaseImpl::default();
+
+    //     A --> B
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::None);
+    assert!(db.cycle_a().is_ok());
+
+    //     A --> B
+    //     ^     |
+    //     +-----+
+    db.set_b_invokes(CycleQuery::A);
+    tracing::debug!("Set Cycle Leaf");
+    assert!(db.cycle_a().is_err());
+}
+
+#[test]
+fn cycle_disappears() {
+    let mut db = DatabaseImpl::default();
+
+    //     A --> B
+    //     ^     |
+    //     +-----+
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::A);
+    assert!(db.cycle_a().is_err());
+
+    //     A --> B
+    db.set_b_invokes(CycleQuery::None);
+    assert!(db.cycle_a().is_ok());
+}
+
+/// A variant on `cycle_disappears` in which the values of
+/// `a_invokes` and `b_invokes` are set with durability values.
+/// If we are not careful, this could cause us to overlook
+/// the fact that the cycle will no longer occur.
+#[test]
+fn cycle_disappears_durability() {
+    let mut db = DatabaseImpl::default();
+    db.set_a_invokes_with_durability(CycleQuery::B, Durability::LOW);
+    db.set_b_invokes_with_durability(CycleQuery::A, Durability::HIGH);
+
+    let res = db.cycle_a();
+    assert!(res.is_err());
+
+    // At this point, `a` read `LOW` input, and `b` read `HIGH` input. However,
+    // because `b` participates in the same cycle as `a`, its final durability
+    // should be `LOW`.
+    //
+    // Check that setting a `LOW` input causes us to re-execute `b` query, and
+    // observe that the cycle goes away.
+    db.set_a_invokes_with_durability(CycleQuery::None, Durability::LOW);
+
+    let res = db.cycle_b();
+    assert!(res.is_ok());
+}
+
+#[test]
+fn cycle_mixed_1() {
+    let mut db = DatabaseImpl::default();
+    //     A --> B <-- C
+    //           |     ^
+    //           +-----+
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::C);
+    db.set_c_invokes(CycleQuery::B);
+
+    let u = db.cycle_c();
+    expect![[r#"
+        Err(
+            Error {
+                cycle: [
+                    "cycle_b(())",
+                    "cycle_c(())",
+                ],
+            },
+        )
+    "#]]
+    .assert_debug_eq(&u);
+}
+
+#[test]
+fn cycle_mixed_2() {
+    let mut db = DatabaseImpl::default();
+
+    // Configuration:
+    //
+    //     A --> B --> C
+    //     ^           |
+    //     +-----------+
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::C);
+    db.set_c_invokes(CycleQuery::A);
+
+    let u = db.cycle_a();
+    expect![[r#"
+        Err(
+            Error {
+                cycle: [
+                    "cycle_a(())",
+                    "cycle_b(())",
+                    "cycle_c(())",
+                ],
+            },
+        )
+    "#]]
+    .assert_debug_eq(&u);
+}
+
+#[test]
+fn cycle_deterministic_order() {
+    // No matter whether we start from A or B, we get the same set of participants:
+    let db = || {
+        let mut db = DatabaseImpl::default();
+        //     A --> B
+        //     ^     |
+        //     +-----+
+        db.set_a_invokes(CycleQuery::B);
+        db.set_b_invokes(CycleQuery::A);
+        db
+    };
+    let a = db().cycle_a();
+    let b = db().cycle_b();
+    expect![[r#"
+        (
+            Err(
+                Error {
+                    cycle: [
+                        "cycle_a(())",
+                        "cycle_b(())",
+                    ],
+                },
+            ),
+            Err(
+                Error {
+                    cycle: [
+                        "cycle_a(())",
+                        "cycle_b(())",
+                    ],
+                },
+            ),
+        )
+    "#]]
+    .assert_debug_eq(&(a, b));
+}
+
+#[test]
+fn cycle_multiple() {
+    // No matter whether we start from A or B, we get the same set of participants:
+    let mut db = DatabaseImpl::default();
+
+    // Configuration:
+    //
+    //     A --> B <-- C
+    //     ^     |     ^
+    //     +-----+     |
+    //           |     |
+    //           +-----+
+    //
+    // Here, conceptually, B encounters a cycle with A and then
+    // recovers.
+    db.set_a_invokes(CycleQuery::B);
+    db.set_b_invokes(CycleQuery::AthenC);
+    db.set_c_invokes(CycleQuery::B);
+
+    let c = db.cycle_c();
+    let b = db.cycle_b();
+    let a = db.cycle_a();
+    expect![[r#"
+        (
+            Err(
+                Error {
+                    cycle: [
+                        "cycle_a(())",
+                        "cycle_b(())",
+                    ],
+                },
+            ),
+            Err(
+                Error {
+                    cycle: [
+                        "cycle_a(())",
+                        "cycle_b(())",
+                    ],
+                },
+            ),
+            Err(
+                Error {
+                    cycle: [
+                        "cycle_a(())",
+                        "cycle_b(())",
+                    ],
+                },
+            ),
+        )
+    "#]]
+    .assert_debug_eq(&(a, b, c));
+}
+
+#[test]
+fn cycle_recovery_set_but_not_participating() {
+    let mut db = DatabaseImpl::default();
+
+    //     A --> C -+
+    //           ^  |
+    //           +--+
+    db.set_a_invokes(CycleQuery::C);
+    db.set_c_invokes(CycleQuery::C);
+
+    // Here we expect C to panic and A not to recover:
+    let r = extract_cycle(|| drop(db.cycle_a()));
+    expect![[r#"
+        [
+            "cycle_c(())",
+        ]
+    "#]]
+    .assert_debug_eq(&r.all_participants(&db));
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/dyn_trait.rs b/src/tools/rust-analyzer/crates/salsa/tests/dyn_trait.rs
new file mode 100644
index 00000000000..09ebc5c4ce4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/dyn_trait.rs
@@ -0,0 +1,28 @@
+//! Test that you can implement a query using a `dyn Trait` setup.
+
+#[salsa::database(DynTraitStorage)]
+#[derive(Default)]
+struct DynTraitDatabase {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DynTraitDatabase {}
+
+#[salsa::query_group(DynTraitStorage)]
+trait DynTrait {
+    #[salsa::input]
+    fn input(&self, x: u32) -> u32;
+
+    fn output(&self, x: u32) -> u32;
+}
+
+fn output(db: &dyn DynTrait, x: u32) -> u32 {
+    db.input(x) * 2
+}
+
+#[test]
+fn dyn_trait() {
+    let mut query = DynTraitDatabase::default();
+    query.set_input(22, 23);
+    assert_eq!(query.output(22), 46);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs
new file mode 100644
index 00000000000..ea0eb819786
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/constants.rs
@@ -0,0 +1,145 @@
+use crate::implementation::{TestContext, TestContextImpl};
+use salsa::debug::DebugQueryTable;
+use salsa::Durability;
+
+#[salsa::query_group(Constants)]
+pub(crate) trait ConstantsDatabase: TestContext {
+    #[salsa::input]
+    fn input(&self, key: char) -> usize;
+
+    fn add(&self, key1: char, key2: char) -> usize;
+
+    fn add3(&self, key1: char, key2: char, key3: char) -> usize;
+}
+
+fn add(db: &dyn ConstantsDatabase, key1: char, key2: char) -> usize {
+    db.log().add(format!("add({}, {})", key1, key2));
+    db.input(key1) + db.input(key2)
+}
+
+fn add3(db: &dyn ConstantsDatabase, key1: char, key2: char, key3: char) -> usize {
+    db.log().add(format!("add3({}, {}, {})", key1, key2, key3));
+    db.add(key1, key2) + db.input(key3)
+}
+
+// Test we can assign a constant and things will be correctly
+// recomputed afterwards.
+#[test]
+fn invalidate_constant() {
+    let db = &mut TestContextImpl::default();
+    db.set_input_with_durability('a', 44, Durability::HIGH);
+    db.set_input_with_durability('b', 22, Durability::HIGH);
+    assert_eq!(db.add('a', 'b'), 66);
+
+    db.set_input_with_durability('a', 66, Durability::HIGH);
+    assert_eq!(db.add('a', 'b'), 88);
+}
+
+#[test]
+fn invalidate_constant_1() {
+    let db = &mut TestContextImpl::default();
+
+    // Not constant:
+    db.set_input('a', 44);
+    assert_eq!(db.add('a', 'a'), 88);
+
+    // Becomes constant:
+    db.set_input_with_durability('a', 44, Durability::HIGH);
+    assert_eq!(db.add('a', 'a'), 88);
+
+    // Invalidates:
+    db.set_input_with_durability('a', 33, Durability::HIGH);
+    assert_eq!(db.add('a', 'a'), 66);
+}
+
+// Test cases where we assign same value to 'a' after declaring it a
+// constant.
+#[test]
+fn set_after_constant_same_value() {
+    let db = &mut TestContextImpl::default();
+    db.set_input_with_durability('a', 44, Durability::HIGH);
+    db.set_input_with_durability('a', 44, Durability::HIGH);
+    db.set_input('a', 44);
+}
+
+#[test]
+fn not_constant() {
+    let mut db = TestContextImpl::default();
+
+    db.set_input('a', 22);
+    db.set_input('b', 44);
+    assert_eq!(db.add('a', 'b'), 66);
+    assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
+}
+
+#[test]
+fn durability() {
+    let mut db = TestContextImpl::default();
+
+    db.set_input_with_durability('a', 22, Durability::HIGH);
+    db.set_input_with_durability('b', 44, Durability::HIGH);
+    assert_eq!(db.add('a', 'b'), 66);
+    assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
+}
+
+#[test]
+fn mixed_constant() {
+    let mut db = TestContextImpl::default();
+
+    db.set_input_with_durability('a', 22, Durability::HIGH);
+    db.set_input('b', 44);
+    assert_eq!(db.add('a', 'b'), 66);
+    assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
+}
+
+#[test]
+fn becomes_constant_with_change() {
+    let mut db = TestContextImpl::default();
+
+    db.set_input('a', 22);
+    db.set_input('b', 44);
+    assert_eq!(db.add('a', 'b'), 66);
+    assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
+
+    db.set_input_with_durability('a', 23, Durability::HIGH);
+    assert_eq!(db.add('a', 'b'), 67);
+    assert_eq!(Durability::LOW, AddQuery.in_db(&db).durability(('a', 'b')));
+
+    db.set_input_with_durability('b', 45, Durability::HIGH);
+    assert_eq!(db.add('a', 'b'), 68);
+    assert_eq!(Durability::HIGH, AddQuery.in_db(&db).durability(('a', 'b')));
+
+    db.set_input_with_durability('b', 45, Durability::MEDIUM);
+    assert_eq!(db.add('a', 'b'), 68);
+    assert_eq!(Durability::MEDIUM, AddQuery.in_db(&db).durability(('a', 'b')));
+}
+
+// Test a subtle case in which an input changes from constant to
+// non-constant, but its value doesn't change. If we're not careful,
+// this can cause us to incorrectly consider derived values as still
+// being constant.
+#[test]
+fn constant_to_non_constant() {
+    let mut db = TestContextImpl::default();
+
+    db.set_input_with_durability('a', 11, Durability::HIGH);
+    db.set_input_with_durability('b', 22, Durability::HIGH);
+    db.set_input_with_durability('c', 33, Durability::HIGH);
+
+    // Here, `add3` invokes `add`, which yields 33. Both calls are
+    // constant.
+    assert_eq!(db.add3('a', 'b', 'c'), 66);
+
+    db.set_input('a', 11);
+
+    // Here, `add3` invokes `add`, which *still* yields 33, but which
+    // is no longer constant. Since value didn't change, we might
+    // preserve `add3` unchanged, not noticing that it is no longer
+    // constant.
+    assert_eq!(db.add3('a', 'b', 'c'), 66);
+
+    // In that case, we would not get the correct result here, when
+    // 'a' changes *again*.
+    db.set_input('a', 22);
+    assert_eq!(db.add3('a', 'b', 'c'), 77);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/counter.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/counter.rs
new file mode 100644
index 00000000000..c04857e24c9
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/counter.rs
@@ -0,0 +1,14 @@
+use std::cell::Cell;
+
+#[derive(Default)]
+pub(crate) struct Counter {
+    value: Cell<usize>,
+}
+
+impl Counter {
+    pub(crate) fn increment(&self) -> usize {
+        let v = self.value.get();
+        self.value.set(v + 1);
+        v
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs
new file mode 100644
index 00000000000..19752bba005
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/implementation.rs
@@ -0,0 +1,59 @@
+use crate::constants;
+use crate::counter::Counter;
+use crate::log::Log;
+use crate::memoized_dep_inputs;
+use crate::memoized_inputs;
+use crate::memoized_volatile;
+
+pub(crate) trait TestContext: salsa::Database {
+    fn clock(&self) -> &Counter;
+    fn log(&self) -> &Log;
+}
+
+#[salsa::database(
+    constants::Constants,
+    memoized_dep_inputs::MemoizedDepInputs,
+    memoized_inputs::MemoizedInputs,
+    memoized_volatile::MemoizedVolatile
+)]
+#[derive(Default)]
+pub(crate) struct TestContextImpl {
+    storage: salsa::Storage<TestContextImpl>,
+    clock: Counter,
+    log: Log,
+}
+
+impl TestContextImpl {
+    #[track_caller]
+    pub(crate) fn assert_log(&self, expected_log: &[&str]) {
+        let expected_text = &format!("{:#?}", expected_log);
+        let actual_text = &format!("{:#?}", self.log().take());
+
+        if expected_text == actual_text {
+            return;
+        }
+
+        #[allow(clippy::print_stdout)]
+        for diff in dissimilar::diff(expected_text, actual_text) {
+            match diff {
+                dissimilar::Chunk::Delete(l) => println!("-{}", l),
+                dissimilar::Chunk::Equal(l) => println!(" {}", l),
+                dissimilar::Chunk::Insert(r) => println!("+{}", r),
+            }
+        }
+
+        panic!("incorrect log results");
+    }
+}
+
+impl TestContext for TestContextImpl {
+    fn clock(&self) -> &Counter {
+        &self.clock
+    }
+
+    fn log(&self) -> &Log {
+        &self.log
+    }
+}
+
+impl salsa::Database for TestContextImpl {}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/log.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/log.rs
new file mode 100644
index 00000000000..1ee57fe667d
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/log.rs
@@ -0,0 +1,16 @@
+use std::cell::RefCell;
+
+#[derive(Default)]
+pub(crate) struct Log {
+    data: RefCell<Vec<String>>,
+}
+
+impl Log {
+    pub(crate) fn add(&self, text: impl Into<String>) {
+        self.data.borrow_mut().push(text.into());
+    }
+
+    pub(crate) fn take(&self) -> Vec<String> {
+        self.data.take()
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/main.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/main.rs
new file mode 100644
index 00000000000..bcd13c75f71
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/main.rs
@@ -0,0 +1,9 @@
+mod constants;
+mod counter;
+mod implementation;
+mod log;
+mod memoized_dep_inputs;
+mod memoized_inputs;
+mod memoized_volatile;
+
+fn main() {}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_dep_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_dep_inputs.rs
new file mode 100644
index 00000000000..4ea33e0c1a0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_dep_inputs.rs
@@ -0,0 +1,60 @@
+use crate::implementation::{TestContext, TestContextImpl};
+
+#[salsa::query_group(MemoizedDepInputs)]
+pub(crate) trait MemoizedDepInputsContext: TestContext {
+    fn dep_memoized2(&self) -> usize;
+    fn dep_memoized1(&self) -> usize;
+    #[salsa::dependencies]
+    fn dep_derived1(&self) -> usize;
+    #[salsa::input]
+    fn dep_input1(&self) -> usize;
+    #[salsa::input]
+    fn dep_input2(&self) -> usize;
+}
+
+fn dep_memoized2(db: &dyn MemoizedDepInputsContext) -> usize {
+    db.log().add("Memoized2 invoked");
+    db.dep_memoized1()
+}
+
+fn dep_memoized1(db: &dyn MemoizedDepInputsContext) -> usize {
+    db.log().add("Memoized1 invoked");
+    db.dep_derived1() * 2
+}
+
+fn dep_derived1(db: &dyn MemoizedDepInputsContext) -> usize {
+    db.log().add("Derived1 invoked");
+    db.dep_input1() / 2
+}
+
+#[test]
+fn revalidate() {
+    let db = &mut TestContextImpl::default();
+
+    db.set_dep_input1(0);
+
+    // Initial run starts from Memoized2:
+    let v = db.dep_memoized2();
+    assert_eq!(v, 0);
+    db.assert_log(&["Memoized2 invoked", "Memoized1 invoked", "Derived1 invoked"]);
+
+    // After that, we first try to validate Memoized1 but wind up
+    // running Memoized2. Note that we don't try to validate
+    // Derived1, so it is invoked by Memoized1.
+    db.set_dep_input1(44);
+    let v = db.dep_memoized2();
+    assert_eq!(v, 44);
+    db.assert_log(&["Memoized1 invoked", "Derived1 invoked", "Memoized2 invoked"]);
+
+    // Here validation of Memoized1 succeeds so Memoized2 never runs.
+    db.set_dep_input1(45);
+    let v = db.dep_memoized2();
+    assert_eq!(v, 44);
+    db.assert_log(&["Memoized1 invoked", "Derived1 invoked"]);
+
+    // Here, a change to input2 doesn't affect us, so nothing runs.
+    db.set_dep_input2(45);
+    let v = db.dep_memoized2();
+    assert_eq!(v, 44);
+    db.assert_log(&[]);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_inputs.rs
new file mode 100644
index 00000000000..53d2ace8871
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_inputs.rs
@@ -0,0 +1,76 @@
+use crate::implementation::{TestContext, TestContextImpl};
+
+#[salsa::query_group(MemoizedInputs)]
+pub(crate) trait MemoizedInputsContext: TestContext {
+    fn max(&self) -> usize;
+    #[salsa::input]
+    fn input1(&self) -> usize;
+    #[salsa::input]
+    fn input2(&self) -> usize;
+}
+
+fn max(db: &dyn MemoizedInputsContext) -> usize {
+    db.log().add("Max invoked");
+    std::cmp::max(db.input1(), db.input2())
+}
+
+#[test]
+fn revalidate() {
+    let db = &mut TestContextImpl::default();
+
+    db.set_input1(0);
+    db.set_input2(0);
+
+    let v = db.max();
+    assert_eq!(v, 0);
+    db.assert_log(&["Max invoked"]);
+
+    let v = db.max();
+    assert_eq!(v, 0);
+    db.assert_log(&[]);
+
+    db.set_input1(44);
+    db.assert_log(&[]);
+
+    let v = db.max();
+    assert_eq!(v, 44);
+    db.assert_log(&["Max invoked"]);
+
+    let v = db.max();
+    assert_eq!(v, 44);
+    db.assert_log(&[]);
+
+    db.set_input1(44);
+    db.assert_log(&[]);
+    db.set_input2(66);
+    db.assert_log(&[]);
+    db.set_input1(64);
+    db.assert_log(&[]);
+
+    let v = db.max();
+    assert_eq!(v, 66);
+    db.assert_log(&["Max invoked"]);
+
+    let v = db.max();
+    assert_eq!(v, 66);
+    db.assert_log(&[]);
+}
+
+/// Test that invoking `set` on an input with the same value still
+/// triggers a new revision.
+#[test]
+fn set_after_no_change() {
+    let db = &mut TestContextImpl::default();
+
+    db.set_input2(0);
+
+    db.set_input1(44);
+    let v = db.max();
+    assert_eq!(v, 44);
+    db.assert_log(&["Max invoked"]);
+
+    db.set_input1(44);
+    let v = db.max();
+    assert_eq!(v, 44);
+    db.assert_log(&["Max invoked"]);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs
new file mode 100644
index 00000000000..6dc5030063b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/incremental/memoized_volatile.rs
@@ -0,0 +1,77 @@
+use crate::implementation::{TestContext, TestContextImpl};
+use salsa::{Database, Durability};
+
+#[salsa::query_group(MemoizedVolatile)]
+pub(crate) trait MemoizedVolatileContext: TestContext {
+    // Queries for testing a "volatile" value wrapped by
+    // memoization.
+    fn memoized2(&self) -> usize;
+    fn memoized1(&self) -> usize;
+    fn volatile(&self) -> usize;
+}
+
+fn memoized2(db: &dyn MemoizedVolatileContext) -> usize {
+    db.log().add("Memoized2 invoked");
+    db.memoized1()
+}
+
+fn memoized1(db: &dyn MemoizedVolatileContext) -> usize {
+    db.log().add("Memoized1 invoked");
+    let v = db.volatile();
+    v / 2
+}
+
+fn volatile(db: &dyn MemoizedVolatileContext) -> usize {
+    db.log().add("Volatile invoked");
+    db.salsa_runtime().report_untracked_read();
+    db.clock().increment()
+}
+
+#[test]
+fn volatile_x2() {
+    let query = TestContextImpl::default();
+
+    // Invoking volatile twice doesn't execute twice, because volatile
+    // queries are memoized by default.
+    query.volatile();
+    query.volatile();
+    query.assert_log(&["Volatile invoked"]);
+}
+
+/// Test that:
+///
+/// - On the first run of R0, we recompute everything.
+/// - On the second run of R1, we recompute nothing.
+/// - On the first run of R1, we recompute Memoized1 but not Memoized2 (since Memoized1 result
+///   did not change).
+/// - On the second run of R1, we recompute nothing.
+/// - On the first run of R2, we recompute everything (since Memoized1 result *did* change).
+#[test]
+fn revalidate() {
+    let mut query = TestContextImpl::default();
+
+    query.memoized2();
+    query.assert_log(&["Memoized2 invoked", "Memoized1 invoked", "Volatile invoked"]);
+
+    query.memoized2();
+    query.assert_log(&[]);
+
+    // Second generation: volatile will change (to 1) but memoized1
+    // will not (still 0, as 1/2 = 0)
+    query.salsa_runtime_mut().synthetic_write(Durability::LOW);
+    query.memoized2();
+    query.assert_log(&["Volatile invoked", "Memoized1 invoked"]);
+    query.memoized2();
+    query.assert_log(&[]);
+
+    // Third generation: volatile will change (to 2) and memoized1
+    // will too (to 1).  Therefore, after validating that Memoized1
+    // changed, we now invoke Memoized2.
+    query.salsa_runtime_mut().synthetic_write(Durability::LOW);
+
+    query.memoized2();
+    query.assert_log(&["Volatile invoked", "Memoized1 invoked", "Memoized2 invoked"]);
+
+    query.memoized2();
+    query.assert_log(&[]);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/interned.rs b/src/tools/rust-analyzer/crates/salsa/tests/interned.rs
new file mode 100644
index 00000000000..d097e41cfd6
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/interned.rs
@@ -0,0 +1,90 @@
+//! Test that you can implement a query using a `dyn Trait` setup.
+
+use salsa::InternId;
+
+#[salsa::database(InternStorage)]
+#[derive(Default)]
+struct Database {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for Database {}
+
+impl salsa::ParallelDatabase for Database {
+    fn snapshot(&self) -> salsa::Snapshot<Self> {
+        salsa::Snapshot::new(Database { storage: self.storage.snapshot() })
+    }
+}
+
+#[salsa::query_group(InternStorage)]
+trait Intern {
+    #[salsa::interned]
+    fn intern1(&self, x: String) -> InternId;
+
+    #[salsa::interned]
+    fn intern2(&self, x: String, y: String) -> InternId;
+
+    #[salsa::interned]
+    fn intern_key(&self, x: String) -> InternKey;
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+pub struct InternKey(InternId);
+
+impl salsa::InternKey for InternKey {
+    fn from_intern_id(v: InternId) -> Self {
+        InternKey(v)
+    }
+
+    fn as_intern_id(&self) -> InternId {
+        self.0
+    }
+}
+
+#[test]
+fn test_intern1() {
+    let db = Database::default();
+    let foo0 = db.intern1("foo".to_owned());
+    let bar0 = db.intern1("bar".to_owned());
+    let foo1 = db.intern1("foo".to_owned());
+    let bar1 = db.intern1("bar".to_owned());
+
+    assert_eq!(foo0, foo1);
+    assert_eq!(bar0, bar1);
+    assert_ne!(foo0, bar0);
+
+    assert_eq!("foo".to_owned(), db.lookup_intern1(foo0));
+    assert_eq!("bar".to_owned(), db.lookup_intern1(bar0));
+}
+
+#[test]
+fn test_intern2() {
+    let db = Database::default();
+    let foo0 = db.intern2("x".to_owned(), "foo".to_owned());
+    let bar0 = db.intern2("x".to_owned(), "bar".to_owned());
+    let foo1 = db.intern2("x".to_owned(), "foo".to_owned());
+    let bar1 = db.intern2("x".to_owned(), "bar".to_owned());
+
+    assert_eq!(foo0, foo1);
+    assert_eq!(bar0, bar1);
+    assert_ne!(foo0, bar0);
+
+    assert_eq!(("x".to_owned(), "foo".to_owned()), db.lookup_intern2(foo0));
+    assert_eq!(("x".to_owned(), "bar".to_owned()), db.lookup_intern2(bar0));
+}
+
+#[test]
+fn test_intern_key() {
+    let db = Database::default();
+    let foo0 = db.intern_key("foo".to_owned());
+    let bar0 = db.intern_key("bar".to_owned());
+    let foo1 = db.intern_key("foo".to_owned());
+    let bar1 = db.intern_key("bar".to_owned());
+
+    assert_eq!(foo0, foo1);
+    assert_eq!(bar0, bar1);
+    assert_ne!(foo0, bar0);
+
+    assert_eq!("foo".to_owned(), db.lookup_intern_key(foo0));
+    assert_eq!("bar".to_owned(), db.lookup_intern_key(bar0));
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/lru.rs b/src/tools/rust-analyzer/crates/salsa/tests/lru.rs
new file mode 100644
index 00000000000..3da8519b081
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/lru.rs
@@ -0,0 +1,102 @@
+//! Test setting LRU actually limits the number of things in the database;
+use std::sync::{
+    atomic::{AtomicUsize, Ordering},
+    Arc,
+};
+
+#[derive(Debug, PartialEq, Eq)]
+struct HotPotato(u32);
+
+static N_POTATOES: AtomicUsize = AtomicUsize::new(0);
+
+impl HotPotato {
+    fn new(id: u32) -> HotPotato {
+        N_POTATOES.fetch_add(1, Ordering::SeqCst);
+        HotPotato(id)
+    }
+}
+
+impl Drop for HotPotato {
+    fn drop(&mut self) {
+        N_POTATOES.fetch_sub(1, Ordering::SeqCst);
+    }
+}
+
+#[salsa::query_group(QueryGroupStorage)]
+trait QueryGroup: salsa::Database {
+    fn get(&self, x: u32) -> Arc<HotPotato>;
+    fn get_volatile(&self, x: u32) -> usize;
+}
+
+fn get(_db: &dyn QueryGroup, x: u32) -> Arc<HotPotato> {
+    Arc::new(HotPotato::new(x))
+}
+
+fn get_volatile(db: &dyn QueryGroup, _x: u32) -> usize {
+    static COUNTER: AtomicUsize = AtomicUsize::new(0);
+    db.salsa_runtime().report_untracked_read();
+    COUNTER.fetch_add(1, Ordering::SeqCst)
+}
+
+#[salsa::database(QueryGroupStorage)]
+#[derive(Default)]
+struct Database {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for Database {}
+
+#[test]
+fn lru_works() {
+    let mut db = Database::default();
+    GetQuery.in_db_mut(&mut db).set_lru_capacity(32);
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 0);
+
+    for i in 0..128u32 {
+        let p = db.get(i);
+        assert_eq!(p.0, i)
+    }
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
+
+    for i in 0..128u32 {
+        let p = db.get(i);
+        assert_eq!(p.0, i)
+    }
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
+
+    GetQuery.in_db_mut(&mut db).set_lru_capacity(32);
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
+
+    GetQuery.in_db_mut(&mut db).set_lru_capacity(64);
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 32);
+    for i in 0..128u32 {
+        let p = db.get(i);
+        assert_eq!(p.0, i)
+    }
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 64);
+
+    // Special case: setting capacity to zero disables LRU
+    GetQuery.in_db_mut(&mut db).set_lru_capacity(0);
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 64);
+    for i in 0..128u32 {
+        let p = db.get(i);
+        assert_eq!(p.0, i)
+    }
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 128);
+
+    drop(db);
+    assert_eq!(N_POTATOES.load(Ordering::SeqCst), 0);
+}
+
+#[test]
+fn lru_doesnt_break_volatile_queries() {
+    let mut db = Database::default();
+    GetVolatileQuery.in_db_mut(&mut db).set_lru_capacity(32);
+    // Here, we check that we execute each volatile query at most once, despite
+    // LRU. That does mean that we have more values in DB than the LRU capacity,
+    // but it's much better than inconsistent results from volatile queries!
+    for i in (0..3).flat_map(|_| 0..128usize) {
+        let x = db.get_volatile(i as u32);
+        assert_eq!(x, i)
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/macros.rs b/src/tools/rust-analyzer/crates/salsa/tests/macros.rs
new file mode 100644
index 00000000000..3d818e53c8e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/macros.rs
@@ -0,0 +1,11 @@
+#[salsa::query_group(MyStruct)]
+trait MyDatabase: salsa::Database {
+    #[salsa::invoke(another_module::another_name)]
+    fn my_query(&self, key: ()) -> ();
+}
+
+mod another_module {
+    pub(crate) fn another_name(_: &dyn crate::MyDatabase, (): ()) {}
+}
+
+fn main() {}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/no_send_sync.rs b/src/tools/rust-analyzer/crates/salsa/tests/no_send_sync.rs
new file mode 100644
index 00000000000..2a25c437c3e
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/no_send_sync.rs
@@ -0,0 +1,31 @@
+use std::rc::Rc;
+
+#[salsa::query_group(NoSendSyncStorage)]
+trait NoSendSyncDatabase: salsa::Database {
+    fn no_send_sync_value(&self, key: bool) -> Rc<bool>;
+    fn no_send_sync_key(&self, key: Rc<bool>) -> bool;
+}
+
+fn no_send_sync_value(_db: &dyn NoSendSyncDatabase, key: bool) -> Rc<bool> {
+    Rc::new(key)
+}
+
+fn no_send_sync_key(_db: &dyn NoSendSyncDatabase, key: Rc<bool>) -> bool {
+    *key
+}
+
+#[salsa::database(NoSendSyncStorage)]
+#[derive(Default)]
+struct DatabaseImpl {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DatabaseImpl {}
+
+#[test]
+fn no_send_sync() {
+    let db = DatabaseImpl::default();
+
+    assert_eq!(db.no_send_sync_value(true), Rc::new(true));
+    assert!(!db.no_send_sync_key(Rc::new(false)));
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs
new file mode 100644
index 00000000000..5d0e4866442
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/on_demand_inputs.rs
@@ -0,0 +1,147 @@
+//! Test that "on-demand" input pattern works.
+//!
+//! On-demand inputs are inputs computed lazily on the fly. They are simulated
+//! via a b query with zero inputs, which uses `add_synthetic_read` to
+//! tweak durability and `invalidate` to clear the input.
+
+#![allow(clippy::disallowed_types, clippy::type_complexity)]
+
+use std::{cell::RefCell, collections::HashMap, rc::Rc};
+
+use salsa::{Database as _, Durability, EventKind};
+
+#[salsa::query_group(QueryGroupStorage)]
+trait QueryGroup: salsa::Database + AsRef<HashMap<u32, u32>> {
+    fn a(&self, x: u32) -> u32;
+    fn b(&self, x: u32) -> u32;
+    fn c(&self, x: u32) -> u32;
+}
+
+fn a(db: &dyn QueryGroup, x: u32) -> u32 {
+    let durability = if x % 2 == 0 { Durability::LOW } else { Durability::HIGH };
+    db.salsa_runtime().report_synthetic_read(durability);
+    let external_state: &HashMap<u32, u32> = db.as_ref();
+    external_state[&x]
+}
+
+fn b(db: &dyn QueryGroup, x: u32) -> u32 {
+    db.a(x)
+}
+
+fn c(db: &dyn QueryGroup, x: u32) -> u32 {
+    db.b(x)
+}
+
+#[salsa::database(QueryGroupStorage)]
+#[derive(Default)]
+struct Database {
+    storage: salsa::Storage<Self>,
+    external_state: HashMap<u32, u32>,
+    on_event: Option<Box<dyn Fn(&Database, salsa::Event)>>,
+}
+
+impl salsa::Database for Database {
+    fn salsa_event(&self, event: salsa::Event) {
+        if let Some(cb) = &self.on_event {
+            cb(self, event)
+        }
+    }
+}
+
+impl AsRef<HashMap<u32, u32>> for Database {
+    fn as_ref(&self) -> &HashMap<u32, u32> {
+        &self.external_state
+    }
+}
+
+#[test]
+fn on_demand_input_works() {
+    let mut db = Database::default();
+
+    db.external_state.insert(1, 10);
+    assert_eq!(db.b(1), 10);
+    assert_eq!(db.a(1), 10);
+
+    // We changed external state, but haven't signaled about this yet,
+    // so we expect to see the old answer
+    db.external_state.insert(1, 92);
+    assert_eq!(db.b(1), 10);
+    assert_eq!(db.a(1), 10);
+
+    AQuery.in_db_mut(&mut db).invalidate(&1);
+    assert_eq!(db.b(1), 92);
+    assert_eq!(db.a(1), 92);
+
+    // Downstream queries should also be rerun if we call `a` first.
+    db.external_state.insert(1, 50);
+    AQuery.in_db_mut(&mut db).invalidate(&1);
+    assert_eq!(db.a(1), 50);
+    assert_eq!(db.b(1), 50);
+}
+
+#[test]
+fn on_demand_input_durability() {
+    let mut db = Database::default();
+
+    let events = Rc::new(RefCell::new(vec![]));
+    db.on_event = Some(Box::new({
+        let events = events.clone();
+        move |db, event| {
+            if let EventKind::WillCheckCancellation = event.kind {
+                // these events are not interesting
+            } else {
+                events.borrow_mut().push(format!("{:?}", event.debug(db)))
+            }
+        }
+    }));
+
+    events.replace(vec![]);
+    db.external_state.insert(1, 10);
+    db.external_state.insert(2, 20);
+    assert_eq!(db.b(1), 10);
+    assert_eq!(db.b(2), 20);
+    expect_test::expect![[r#"
+        RefCell {
+            value: [
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: b(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: b(2) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }",
+            ],
+        }
+    "#]].assert_debug_eq(&events);
+
+    db.salsa_runtime_mut().synthetic_write(Durability::LOW);
+    events.replace(vec![]);
+    assert_eq!(db.c(1), 10);
+    assert_eq!(db.c(2), 20);
+    // Re-execute `a(2)` because that has low durability, but not `a(1)`
+    expect_test::expect![[r#"
+        RefCell {
+            value: [
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: c(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: b(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: c(2) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: b(2) } }",
+            ],
+        }
+    "#]].assert_debug_eq(&events);
+
+    db.salsa_runtime_mut().synthetic_write(Durability::HIGH);
+    events.replace(vec![]);
+    assert_eq!(db.c(1), 10);
+    assert_eq!(db.c(2), 20);
+    // Re-execute both `a(1)` and `a(2)`, but we don't re-execute any `b` queries as the
+    // result didn't actually change.
+    expect_test::expect![[r#"
+        RefCell {
+            value: [
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: c(1) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: WillExecute { database_key: a(2) } }",
+                "Event { runtime_id: RuntimeId { counter: 0 }, kind: DidValidateMemoizedValue { database_key: c(2) } }",
+            ],
+        }
+    "#]].assert_debug_eq(&events);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/panic_safely.rs b/src/tools/rust-analyzer/crates/salsa/tests/panic_safely.rs
new file mode 100644
index 00000000000..c11ae9c2144
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/panic_safely.rs
@@ -0,0 +1,93 @@
+use salsa::{Database, ParallelDatabase, Snapshot};
+use std::panic::{self, AssertUnwindSafe};
+use std::sync::atomic::{AtomicU32, Ordering::SeqCst};
+
+#[salsa::query_group(PanicSafelyStruct)]
+trait PanicSafelyDatabase: salsa::Database {
+    #[salsa::input]
+    fn one(&self) -> usize;
+
+    fn panic_safely(&self) -> ();
+
+    fn outer(&self) -> ();
+}
+
+fn panic_safely(db: &dyn PanicSafelyDatabase) {
+    assert_eq!(db.one(), 1);
+}
+
+static OUTER_CALLS: AtomicU32 = AtomicU32::new(0);
+
+fn outer(db: &dyn PanicSafelyDatabase) {
+    OUTER_CALLS.fetch_add(1, SeqCst);
+    db.panic_safely();
+}
+
+#[salsa::database(PanicSafelyStruct)]
+#[derive(Default)]
+struct DatabaseStruct {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DatabaseStruct {}
+
+impl salsa::ParallelDatabase for DatabaseStruct {
+    fn snapshot(&self) -> Snapshot<Self> {
+        Snapshot::new(DatabaseStruct { storage: self.storage.snapshot() })
+    }
+}
+
+#[test]
+fn should_panic_safely() {
+    let mut db = DatabaseStruct::default();
+    db.set_one(0);
+
+    // Invoke `db.panic_safely() without having set `db.one`. `db.one` will
+    // return 0 and we should catch the panic.
+    let result = panic::catch_unwind(AssertUnwindSafe({
+        let db = db.snapshot();
+        move || db.panic_safely()
+    }));
+    assert!(result.is_err());
+
+    // Set `db.one` to 1 and assert ok
+    db.set_one(1);
+    let result = panic::catch_unwind(AssertUnwindSafe(|| db.panic_safely()));
+    assert!(result.is_ok());
+
+    // Check, that memoized outer is not invalidated by a panic
+    {
+        assert_eq!(OUTER_CALLS.load(SeqCst), 0);
+        db.outer();
+        assert_eq!(OUTER_CALLS.load(SeqCst), 1);
+
+        db.set_one(0);
+        let result = panic::catch_unwind(AssertUnwindSafe(|| db.outer()));
+        assert!(result.is_err());
+        assert_eq!(OUTER_CALLS.load(SeqCst), 1);
+
+        db.set_one(1);
+        db.outer();
+        assert_eq!(OUTER_CALLS.load(SeqCst), 2);
+    }
+}
+
+#[test]
+fn storages_are_unwind_safe() {
+    fn check_unwind_safe<T: std::panic::UnwindSafe>() {}
+    check_unwind_safe::<&DatabaseStruct>();
+}
+
+#[test]
+fn panics_clear_query_stack() {
+    let db = DatabaseStruct::default();
+
+    // Invoke `db.panic_if_not_one() without having set `db.input`. `db.input`
+    // will default to 0 and we should catch the panic.
+    let result = panic::catch_unwind(AssertUnwindSafe(|| db.panic_safely()));
+    assert!(result.is_err());
+
+    // The database has been poisoned and any attempt to increment the
+    // revision should panic.
+    assert_eq!(db.salsa_runtime().active_query(), None);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/cancellation.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/cancellation.rs
new file mode 100644
index 00000000000..9a92e5cc1ff
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/cancellation.rs
@@ -0,0 +1,132 @@
+use crate::setup::{CancellationFlag, Knobs, ParDatabase, ParDatabaseImpl, WithValue};
+use salsa::{Cancelled, ParallelDatabase};
+
+macro_rules! assert_cancelled {
+    ($thread:expr) => {
+        match $thread.join() {
+            Ok(value) => panic!("expected cancellation, got {:?}", value),
+            Err(payload) => match payload.downcast::<Cancelled>() {
+                Ok(_) => {}
+                Err(payload) => ::std::panic::resume_unwind(payload),
+            },
+        }
+    };
+}
+
+/// Add test where a call to `sum` is cancelled by a simultaneous
+/// write. Check that we recompute the result in next revision, even
+/// though none of the inputs have changed.
+#[test]
+fn in_par_get_set_cancellation_immediate() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+    db.set_input('d', 0);
+
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            // This will not return until it sees cancellation is
+            // signaled.
+            db.knobs().sum_signal_on_entry.with_value(1, || {
+                db.knobs()
+                    .sum_wait_for_cancellation
+                    .with_value(CancellationFlag::Panic, || db.sum("abc"))
+            })
+        }
+    });
+
+    // Wait until we have entered `sum` in the other thread.
+    db.wait_for(1);
+
+    // Try to set the input. This will signal cancellation.
+    db.set_input('d', 1000);
+
+    // This should re-compute the value (even though no input has changed).
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.sum("abc")
+    });
+
+    assert_eq!(db.sum("d"), 1000);
+    assert_cancelled!(thread1);
+    assert_eq!(thread2.join().unwrap(), 111);
+}
+
+/// Here, we check that `sum`'s cancellation is propagated
+/// to `sum2` properly.
+#[test]
+fn in_par_get_set_cancellation_transitive() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+    db.set_input('d', 0);
+
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            // This will not return until it sees cancellation is
+            // signaled.
+            db.knobs().sum_signal_on_entry.with_value(1, || {
+                db.knobs()
+                    .sum_wait_for_cancellation
+                    .with_value(CancellationFlag::Panic, || db.sum2("abc"))
+            })
+        }
+    });
+
+    // Wait until we have entered `sum` in the other thread.
+    db.wait_for(1);
+
+    // Try to set the input. This will signal cancellation.
+    db.set_input('d', 1000);
+
+    // This should re-compute the value (even though no input has changed).
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.sum2("abc")
+    });
+
+    assert_eq!(db.sum2("d"), 1000);
+    assert_cancelled!(thread1);
+    assert_eq!(thread2.join().unwrap(), 111);
+}
+
+/// https://github.com/salsa-rs/salsa/issues/66
+#[test]
+fn no_back_dating_in_cancellation() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 1);
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            // Here we compute a long-chain of queries,
+            // but the last one gets cancelled.
+            db.knobs().sum_signal_on_entry.with_value(1, || {
+                db.knobs()
+                    .sum_wait_for_cancellation
+                    .with_value(CancellationFlag::Panic, || db.sum3("a"))
+            })
+        }
+    });
+
+    db.wait_for(1);
+
+    // Set unrelated input to bump revision
+    db.set_input('b', 2);
+
+    // Here we should recompuet the whole chain again, clearing the cancellation
+    // state. If we get `usize::max()` here, it is a bug!
+    assert_eq!(db.sum3("a"), 1);
+
+    assert_cancelled!(thread1);
+
+    db.set_input('a', 3);
+    db.set_input('a', 4);
+    assert_eq!(db.sum3("ab"), 6);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/frozen.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/frozen.rs
new file mode 100644
index 00000000000..5359a8820e2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/frozen.rs
@@ -0,0 +1,57 @@
+use crate::setup::{ParDatabase, ParDatabaseImpl};
+use crate::signal::Signal;
+use salsa::{Database, ParallelDatabase};
+use std::{
+    panic::{catch_unwind, AssertUnwindSafe},
+    sync::Arc,
+};
+
+/// Add test where a call to `sum` is cancelled by a simultaneous
+/// write. Check that we recompute the result in next revision, even
+/// though none of the inputs have changed.
+#[test]
+fn in_par_get_set_cancellation() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 1);
+
+    let signal = Arc::new(Signal::default());
+
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        let signal = signal.clone();
+        move || {
+            // Check that cancellation flag is not yet set, because
+            // `set` cannot have been called yet.
+            catch_unwind(AssertUnwindSafe(|| db.unwind_if_cancelled())).unwrap();
+
+            // Signal other thread to proceed.
+            signal.signal(1);
+
+            // Wait for other thread to signal cancellation
+            catch_unwind(AssertUnwindSafe(|| loop {
+                db.unwind_if_cancelled();
+                std::thread::yield_now();
+            }))
+            .unwrap_err();
+        }
+    });
+
+    let thread2 = std::thread::spawn({
+        move || {
+            // Wait until thread 1 has asserted that they are not cancelled
+            // before we invoke `set.`
+            signal.wait_for(1);
+
+            // This will block until thread1 drops the revision lock.
+            db.set_input('a', 2);
+
+            db.input('a')
+        }
+    });
+
+    thread1.join().unwrap();
+
+    let c = thread2.join().unwrap();
+    assert_eq!(c, 2);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/independent.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/independent.rs
new file mode 100644
index 00000000000..bd6ba3bf931
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/independent.rs
@@ -0,0 +1,29 @@
+use crate::setup::{ParDatabase, ParDatabaseImpl};
+use salsa::ParallelDatabase;
+
+/// Test two `sum` queries (on distinct keys) executing in different
+/// threads. Really just a test that `snapshot` etc compiles.
+#[test]
+fn in_par_two_independent_queries() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+    db.set_input('d', 200);
+    db.set_input('e', 20);
+    db.set_input('f', 2);
+
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.sum("abc")
+    });
+
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.sum("def")
+    });
+
+    assert_eq!(thread1.join().unwrap(), 111);
+    assert_eq!(thread2.join().unwrap(), 222);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/main.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/main.rs
new file mode 100644
index 00000000000..31c0da18375
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/main.rs
@@ -0,0 +1,13 @@
+mod setup;
+
+mod cancellation;
+mod frozen;
+mod independent;
+mod parallel_cycle_all_recover;
+mod parallel_cycle_mid_recover;
+mod parallel_cycle_none_recover;
+mod parallel_cycle_one_recovers;
+mod race;
+mod signal;
+mod stress;
+mod true_parallel;
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs
new file mode 100644
index 00000000000..cee51b4db75
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_all_recover.rs
@@ -0,0 +1,110 @@
+//! Test for cycle recover spread across two threads.
+//! See `../cycles.rs` for a complete listing of cycle tests,
+//! both intra and cross thread.
+
+use crate::setup::{Knobs, ParDatabaseImpl};
+use salsa::ParallelDatabase;
+use test_log::test;
+
+// Recover cycle test:
+//
+// The pattern is as follows.
+//
+// Thread A                   Thread B
+// --------                   --------
+// a1                         b1
+// |                          wait for stage 1 (blocks)
+// signal stage 1             |
+// wait for stage 2 (blocks)  (unblocked)
+// |                          signal stage 2
+// (unblocked)                wait for stage 3 (blocks)
+// a2                         |
+// b1 (blocks -> stage 3)     |
+// |                          (unblocked)
+// |                          b2
+// |                          a1 (cycle detected, recovers)
+// |                          b2 completes, recovers
+// |                          b1 completes, recovers
+// a2 sees cycle, recovers
+// a1 completes, recovers
+
+#[test]
+fn parallel_cycle_all_recover() {
+    let db = ParDatabaseImpl::default();
+    db.knobs().signal_on_will_block.set(3);
+
+    let thread_a = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.a1(1)
+    });
+
+    let thread_b = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.b1(1)
+    });
+
+    assert_eq!(thread_a.join().unwrap(), 11);
+    assert_eq!(thread_b.join().unwrap(), 21);
+}
+
+#[salsa::query_group(ParallelCycleAllRecover)]
+pub(crate) trait TestDatabase: Knobs {
+    #[salsa::cycle(recover_a1)]
+    fn a1(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover_a2)]
+    fn a2(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover_b1)]
+    fn b1(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover_b2)]
+    fn b2(&self, key: i32) -> i32;
+}
+
+fn recover_a1(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_a1");
+    key * 10 + 1
+}
+
+fn recover_a2(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_a2");
+    key * 10 + 2
+}
+
+fn recover_b1(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_b1");
+    key * 20 + 1
+}
+
+fn recover_b2(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_b2");
+    key * 20 + 2
+}
+
+fn a1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.signal(1);
+    db.wait_for(2);
+
+    db.a2(key)
+}
+
+fn a2(db: &dyn TestDatabase, key: i32) -> i32 {
+    db.b1(key)
+}
+
+fn b1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.wait_for(1);
+    db.signal(2);
+
+    // Wait for thread A to block on this thread
+    db.wait_for(3);
+
+    db.b2(key)
+}
+
+fn b2(db: &dyn TestDatabase, key: i32) -> i32 {
+    db.a1(key)
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs
new file mode 100644
index 00000000000..f78c05c5593
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_mid_recover.rs
@@ -0,0 +1,110 @@
+//! Test for cycle recover spread across two threads.
+//! See `../cycles.rs` for a complete listing of cycle tests,
+//! both intra and cross thread.
+
+use crate::setup::{Knobs, ParDatabaseImpl};
+use salsa::ParallelDatabase;
+use test_log::test;
+
+// Recover cycle test:
+//
+// The pattern is as follows.
+//
+// Thread A                   Thread B
+// --------                   --------
+// a1                         b1
+// |                          wait for stage 1 (blocks)
+// signal stage 1             |
+// wait for stage 2 (blocks)  (unblocked)
+// |                          |
+// |                          b2
+// |                          b3
+// |                          a1 (blocks -> stage 2)
+// (unblocked)                |
+// a2 (cycle detected)        |
+//                            b3 recovers
+//                            b2 resumes
+//                            b1 panics because bug
+
+#[test]
+fn parallel_cycle_mid_recovers() {
+    let db = ParDatabaseImpl::default();
+    db.knobs().signal_on_will_block.set(2);
+
+    let thread_a = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.a1(1)
+    });
+
+    let thread_b = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.b1(1)
+    });
+
+    // We expect that the recovery function yields
+    // `1 * 20 + 2`, which is returned (and forwarded)
+    // to b1, and from there to a2 and a1.
+    assert_eq!(thread_a.join().unwrap(), 22);
+    assert_eq!(thread_b.join().unwrap(), 22);
+}
+
+#[salsa::query_group(ParallelCycleMidRecovers)]
+pub(crate) trait TestDatabase: Knobs {
+    fn a1(&self, key: i32) -> i32;
+
+    fn a2(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover_b1)]
+    fn b1(&self, key: i32) -> i32;
+
+    fn b2(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover_b3)]
+    fn b3(&self, key: i32) -> i32;
+}
+
+fn recover_b1(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_b1");
+    key * 20 + 2
+}
+
+fn recover_b3(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover_b1");
+    key * 200 + 2
+}
+
+fn a1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // tell thread b we have started
+    db.signal(1);
+
+    // wait for thread b to block on a1
+    db.wait_for(2);
+
+    db.a2(key)
+}
+
+fn a2(db: &dyn TestDatabase, key: i32) -> i32 {
+    // create the cycle
+    db.b1(key)
+}
+
+fn b1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // wait for thread a to have started
+    db.wait_for(1);
+
+    db.b2(key);
+
+    0
+}
+
+fn b2(db: &dyn TestDatabase, key: i32) -> i32 {
+    // will encounter a cycle but recover
+    db.b3(key);
+    db.b1(key); // hasn't recovered yet
+    0
+}
+
+fn b3(db: &dyn TestDatabase, key: i32) -> i32 {
+    // will block on thread a, signaling stage 2
+    db.a1(key)
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs
new file mode 100644
index 00000000000..35fe3791182
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_none_recover.rs
@@ -0,0 +1,69 @@
+//! Test a cycle where no queries recover that occurs across threads.
+//! See the `../cycles.rs` for a complete listing of cycle tests,
+//! both intra and cross thread.
+
+use crate::setup::{Knobs, ParDatabaseImpl};
+use expect_test::expect;
+use salsa::ParallelDatabase;
+use test_log::test;
+
+#[test]
+fn parallel_cycle_none_recover() {
+    let db = ParDatabaseImpl::default();
+    db.knobs().signal_on_will_block.set(3);
+
+    let thread_a = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.a(-1)
+    });
+
+    let thread_b = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.b(-1)
+    });
+
+    // We expect B to panic because it detects a cycle (it is the one that calls A, ultimately).
+    // Right now, it panics with a string.
+    let err_b = thread_b.join().unwrap_err();
+    if let Some(c) = err_b.downcast_ref::<salsa::Cycle>() {
+        expect![[r#"
+            [
+                "a(-1)",
+                "b(-1)",
+            ]
+        "#]]
+        .assert_debug_eq(&c.unexpected_participants(&db));
+    } else {
+        panic!("b failed in an unexpected way: {:?}", err_b);
+    }
+
+    // We expect A to propagate a panic, which causes us to use the sentinel
+    // type `Canceled`.
+    assert!(thread_a.join().unwrap_err().downcast_ref::<salsa::Cycle>().is_some());
+}
+
+#[salsa::query_group(ParallelCycleNoneRecover)]
+pub(crate) trait TestDatabase: Knobs {
+    fn a(&self, key: i32) -> i32;
+    fn b(&self, key: i32) -> i32;
+}
+
+fn a(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.signal(1);
+    db.wait_for(2);
+
+    db.b(key)
+}
+
+fn b(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.wait_for(1);
+    db.signal(2);
+
+    // Wait for thread A to block on this thread
+    db.wait_for(3);
+
+    // Now try to execute A
+    db.a(key)
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs
new file mode 100644
index 00000000000..7d3944714ae
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/parallel_cycle_one_recovers.rs
@@ -0,0 +1,95 @@
+//! Test for cycle recover spread across two threads.
+//! See `../cycles.rs` for a complete listing of cycle tests,
+//! both intra and cross thread.
+
+use crate::setup::{Knobs, ParDatabaseImpl};
+use salsa::ParallelDatabase;
+use test_log::test;
+
+// Recover cycle test:
+//
+// The pattern is as follows.
+//
+// Thread A                   Thread B
+// --------                   --------
+// a1                         b1
+// |                          wait for stage 1 (blocks)
+// signal stage 1             |
+// wait for stage 2 (blocks)  (unblocked)
+// |                          signal stage 2
+// (unblocked)                wait for stage 3 (blocks)
+// a2                         |
+// b1 (blocks -> stage 3)     |
+// |                          (unblocked)
+// |                          b2
+// |                          a1 (cycle detected)
+// a2 recovery fn executes    |
+// a1 completes normally      |
+//                            b2 completes, recovers
+//                            b1 completes, recovers
+
+#[test]
+fn parallel_cycle_one_recovers() {
+    let db = ParDatabaseImpl::default();
+    db.knobs().signal_on_will_block.set(3);
+
+    let thread_a = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.a1(1)
+    });
+
+    let thread_b = std::thread::spawn({
+        let db = db.snapshot();
+        move || db.b1(1)
+    });
+
+    // We expect that the recovery function yields
+    // `1 * 20 + 2`, which is returned (and forwarded)
+    // to b1, and from there to a2 and a1.
+    assert_eq!(thread_a.join().unwrap(), 22);
+    assert_eq!(thread_b.join().unwrap(), 22);
+}
+
+#[salsa::query_group(ParallelCycleOneRecovers)]
+pub(crate) trait TestDatabase: Knobs {
+    fn a1(&self, key: i32) -> i32;
+
+    #[salsa::cycle(recover)]
+    fn a2(&self, key: i32) -> i32;
+
+    fn b1(&self, key: i32) -> i32;
+
+    fn b2(&self, key: i32) -> i32;
+}
+
+fn recover(_db: &dyn TestDatabase, _cycle: &salsa::Cycle, key: &i32) -> i32 {
+    tracing::debug!("recover");
+    key * 20 + 2
+}
+
+fn a1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.signal(1);
+    db.wait_for(2);
+
+    db.a2(key)
+}
+
+fn a2(db: &dyn TestDatabase, key: i32) -> i32 {
+    db.b1(key)
+}
+
+fn b1(db: &dyn TestDatabase, key: i32) -> i32 {
+    // Wait to create the cycle until both threads have entered
+    db.wait_for(1);
+    db.signal(2);
+
+    // Wait for thread A to block on this thread
+    db.wait_for(3);
+
+    db.b2(key)
+}
+
+fn b2(db: &dyn TestDatabase, key: i32) -> i32 {
+    db.a1(key)
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs
new file mode 100644
index 00000000000..e875de998f8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/race.rs
@@ -0,0 +1,37 @@
+use std::panic::AssertUnwindSafe;
+
+use crate::setup::{ParDatabase, ParDatabaseImpl};
+use salsa::{Cancelled, ParallelDatabase};
+
+/// Test where a read and a set are racing with one another.
+/// Should be atomic.
+#[test]
+fn in_par_get_set_race() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || Cancelled::catch(AssertUnwindSafe(|| db.sum("abc")))
+    });
+
+    let thread2 = std::thread::spawn(move || {
+        db.set_input('a', 1000);
+        db.sum("a")
+    });
+
+    // If the 1st thread runs first, you get 111, otherwise you get
+    // 1011; if they run concurrently and the 1st thread observes the
+    // cancellation, it'll unwind.
+    let result1 = thread1.join().unwrap();
+    if let Ok(value1) = result1 {
+        assert!(value1 == 111 || value1 == 1011, "illegal result {}", value1);
+    }
+
+    // thread2 can not observe a cancellation because it performs a
+    // database write before running any other queries.
+    assert_eq!(thread2.join().unwrap(), 1000);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/setup.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/setup.rs
new file mode 100644
index 00000000000..0a35902b435
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/setup.rs
@@ -0,0 +1,197 @@
+use crate::signal::Signal;
+use salsa::Database;
+use salsa::ParallelDatabase;
+use salsa::Snapshot;
+use std::sync::Arc;
+use std::{
+    cell::Cell,
+    panic::{catch_unwind, resume_unwind, AssertUnwindSafe},
+};
+
+#[salsa::query_group(Par)]
+pub(crate) trait ParDatabase: Knobs {
+    #[salsa::input]
+    fn input(&self, key: char) -> usize;
+
+    fn sum(&self, key: &'static str) -> usize;
+
+    /// Invokes `sum`
+    fn sum2(&self, key: &'static str) -> usize;
+
+    /// Invokes `sum` but doesn't really care about the result.
+    fn sum2_drop_sum(&self, key: &'static str) -> usize;
+
+    /// Invokes `sum2`
+    fn sum3(&self, key: &'static str) -> usize;
+
+    /// Invokes `sum2_drop_sum`
+    fn sum3_drop_sum(&self, key: &'static str) -> usize;
+}
+
+/// Various "knobs" and utilities used by tests to force
+/// a certain behavior.
+pub(crate) trait Knobs {
+    fn knobs(&self) -> &KnobsStruct;
+
+    fn signal(&self, stage: usize);
+
+    fn wait_for(&self, stage: usize);
+}
+
+pub(crate) trait WithValue<T> {
+    fn with_value<R>(&self, value: T, closure: impl FnOnce() -> R) -> R;
+}
+
+impl<T> WithValue<T> for Cell<T> {
+    fn with_value<R>(&self, value: T, closure: impl FnOnce() -> R) -> R {
+        let old_value = self.replace(value);
+
+        let result = catch_unwind(AssertUnwindSafe(closure));
+
+        self.set(old_value);
+
+        match result {
+            Ok(r) => r,
+            Err(payload) => resume_unwind(payload),
+        }
+    }
+}
+
+#[derive(Default, Clone, Copy, PartialEq, Eq)]
+pub(crate) enum CancellationFlag {
+    #[default]
+    Down,
+    Panic,
+}
+
+/// Various "knobs" that can be used to customize how the queries
+/// behave on one specific thread. Note that this state is
+/// intentionally thread-local (apart from `signal`).
+#[derive(Clone, Default)]
+pub(crate) struct KnobsStruct {
+    /// A kind of flexible barrier used to coordinate execution across
+    /// threads to ensure we reach various weird states.
+    pub(crate) signal: Arc<Signal>,
+
+    /// When this database is about to block, send a signal.
+    pub(crate) signal_on_will_block: Cell<usize>,
+
+    /// Invocations of `sum` will signal this stage on entry.
+    pub(crate) sum_signal_on_entry: Cell<usize>,
+
+    /// Invocations of `sum` will wait for this stage on entry.
+    pub(crate) sum_wait_for_on_entry: Cell<usize>,
+
+    /// If true, invocations of `sum` will panic before they exit.
+    pub(crate) sum_should_panic: Cell<bool>,
+
+    /// If true, invocations of `sum` will wait for cancellation before
+    /// they exit.
+    pub(crate) sum_wait_for_cancellation: Cell<CancellationFlag>,
+
+    /// Invocations of `sum` will wait for this stage prior to exiting.
+    pub(crate) sum_wait_for_on_exit: Cell<usize>,
+
+    /// Invocations of `sum` will signal this stage prior to exiting.
+    pub(crate) sum_signal_on_exit: Cell<usize>,
+
+    /// Invocations of `sum3_drop_sum` will panic unconditionally
+    pub(crate) sum3_drop_sum_should_panic: Cell<bool>,
+}
+
+fn sum(db: &dyn ParDatabase, key: &'static str) -> usize {
+    let mut sum = 0;
+
+    db.signal(db.knobs().sum_signal_on_entry.get());
+
+    db.wait_for(db.knobs().sum_wait_for_on_entry.get());
+
+    if db.knobs().sum_should_panic.get() {
+        panic!("query set to panic before exit")
+    }
+
+    for ch in key.chars() {
+        sum += db.input(ch);
+    }
+
+    match db.knobs().sum_wait_for_cancellation.get() {
+        CancellationFlag::Down => (),
+        CancellationFlag::Panic => {
+            tracing::debug!("waiting for cancellation");
+            loop {
+                db.unwind_if_cancelled();
+                std::thread::yield_now();
+            }
+        }
+    }
+
+    db.wait_for(db.knobs().sum_wait_for_on_exit.get());
+
+    db.signal(db.knobs().sum_signal_on_exit.get());
+
+    sum
+}
+
+fn sum2(db: &dyn ParDatabase, key: &'static str) -> usize {
+    db.sum(key)
+}
+
+fn sum2_drop_sum(db: &dyn ParDatabase, key: &'static str) -> usize {
+    let _ = db.sum(key);
+    22
+}
+
+fn sum3(db: &dyn ParDatabase, key: &'static str) -> usize {
+    db.sum2(key)
+}
+
+fn sum3_drop_sum(db: &dyn ParDatabase, key: &'static str) -> usize {
+    if db.knobs().sum3_drop_sum_should_panic.get() {
+        panic!("sum3_drop_sum executed")
+    }
+    db.sum2_drop_sum(key)
+}
+
+#[salsa::database(
+    Par,
+    crate::parallel_cycle_all_recover::ParallelCycleAllRecover,
+    crate::parallel_cycle_none_recover::ParallelCycleNoneRecover,
+    crate::parallel_cycle_mid_recover::ParallelCycleMidRecovers,
+    crate::parallel_cycle_one_recovers::ParallelCycleOneRecovers
+)]
+#[derive(Default)]
+pub(crate) struct ParDatabaseImpl {
+    storage: salsa::Storage<Self>,
+    knobs: KnobsStruct,
+}
+
+impl Database for ParDatabaseImpl {
+    fn salsa_event(&self, event: salsa::Event) {
+        if let salsa::EventKind::WillBlockOn { .. } = event.kind {
+            self.signal(self.knobs().signal_on_will_block.get());
+        }
+    }
+}
+
+impl ParallelDatabase for ParDatabaseImpl {
+    fn snapshot(&self) -> Snapshot<Self> {
+        Snapshot::new(ParDatabaseImpl {
+            storage: self.storage.snapshot(),
+            knobs: self.knobs.clone(),
+        })
+    }
+}
+
+impl Knobs for ParDatabaseImpl {
+    fn knobs(&self) -> &KnobsStruct {
+        &self.knobs
+    }
+
+    fn signal(&self, stage: usize) {
+        self.knobs.signal.signal(stage);
+    }
+
+    fn wait_for(&self, stage: usize) {
+        self.knobs.signal.wait_for(stage);
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/signal.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/signal.rs
new file mode 100644
index 00000000000..0af7b66e482
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/signal.rs
@@ -0,0 +1,40 @@
+use parking_lot::{Condvar, Mutex};
+
+#[derive(Default)]
+pub(crate) struct Signal {
+    value: Mutex<usize>,
+    cond_var: Condvar,
+}
+
+impl Signal {
+    pub(crate) fn signal(&self, stage: usize) {
+        tracing::debug!("signal({})", stage);
+
+        // This check avoids acquiring the lock for things that will
+        // clearly be a no-op. Not *necessary* but helps to ensure we
+        // are more likely to encounter weird race conditions;
+        // otherwise calls to `sum` will tend to be unnecessarily
+        // synchronous.
+        if stage > 0 {
+            let mut v = self.value.lock();
+            if stage > *v {
+                *v = stage;
+                self.cond_var.notify_all();
+            }
+        }
+    }
+
+    /// Waits until the given condition is true; the fn is invoked
+    /// with the current stage.
+    pub(crate) fn wait_for(&self, stage: usize) {
+        tracing::debug!("wait_for({})", stage);
+
+        // As above, avoid lock if clearly a no-op.
+        if stage > 0 {
+            let mut v = self.value.lock();
+            while *v < stage {
+                self.cond_var.wait(&mut v);
+            }
+        }
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/stress.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/stress.rs
new file mode 100644
index 00000000000..2fa317b2b90
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/stress.rs
@@ -0,0 +1,168 @@
+use rand::seq::SliceRandom;
+use rand::Rng;
+
+use salsa::ParallelDatabase;
+use salsa::Snapshot;
+use salsa::{Cancelled, Database};
+
+// Number of operations a reader performs
+const N_MUTATOR_OPS: usize = 100;
+const N_READER_OPS: usize = 100;
+
+#[salsa::query_group(Stress)]
+trait StressDatabase: salsa::Database {
+    #[salsa::input]
+    fn a(&self, key: usize) -> usize;
+
+    fn b(&self, key: usize) -> usize;
+
+    fn c(&self, key: usize) -> usize;
+}
+
+fn b(db: &dyn StressDatabase, key: usize) -> usize {
+    db.unwind_if_cancelled();
+    db.a(key)
+}
+
+fn c(db: &dyn StressDatabase, key: usize) -> usize {
+    db.b(key)
+}
+
+#[salsa::database(Stress)]
+#[derive(Default)]
+struct StressDatabaseImpl {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for StressDatabaseImpl {}
+
+impl salsa::ParallelDatabase for StressDatabaseImpl {
+    fn snapshot(&self) -> Snapshot<StressDatabaseImpl> {
+        Snapshot::new(StressDatabaseImpl { storage: self.storage.snapshot() })
+    }
+}
+
+#[derive(Clone, Copy, Debug)]
+enum Query {
+    A,
+    B,
+    C,
+}
+
+enum MutatorOp {
+    WriteOp(WriteOp),
+    LaunchReader { ops: Vec<ReadOp>, check_cancellation: bool },
+}
+
+#[derive(Debug)]
+enum WriteOp {
+    SetA(usize, usize),
+}
+
+#[derive(Debug)]
+enum ReadOp {
+    Get(Query, usize),
+}
+
+impl rand::distributions::Distribution<Query> for rand::distributions::Standard {
+    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> Query {
+        *[Query::A, Query::B, Query::C].choose(rng).unwrap()
+    }
+}
+
+impl rand::distributions::Distribution<MutatorOp> for rand::distributions::Standard {
+    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> MutatorOp {
+        if rng.gen_bool(0.5) {
+            MutatorOp::WriteOp(rng.gen())
+        } else {
+            MutatorOp::LaunchReader {
+                ops: (0..N_READER_OPS).map(|_| rng.gen()).collect(),
+                check_cancellation: rng.gen(),
+            }
+        }
+    }
+}
+
+impl rand::distributions::Distribution<WriteOp> for rand::distributions::Standard {
+    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> WriteOp {
+        let key = rng.gen::<usize>() % 10;
+        let value = rng.gen::<usize>() % 10;
+        WriteOp::SetA(key, value)
+    }
+}
+
+impl rand::distributions::Distribution<ReadOp> for rand::distributions::Standard {
+    fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> ReadOp {
+        let query = rng.gen::<Query>();
+        let key = rng.gen::<usize>() % 10;
+        ReadOp::Get(query, key)
+    }
+}
+
+fn db_reader_thread(db: &StressDatabaseImpl, ops: Vec<ReadOp>, check_cancellation: bool) {
+    for op in ops {
+        if check_cancellation {
+            db.unwind_if_cancelled();
+        }
+        op.execute(db);
+    }
+}
+
+impl WriteOp {
+    fn execute(self, db: &mut StressDatabaseImpl) {
+        match self {
+            WriteOp::SetA(key, value) => {
+                db.set_a(key, value);
+            }
+        }
+    }
+}
+
+impl ReadOp {
+    fn execute(self, db: &StressDatabaseImpl) {
+        match self {
+            ReadOp::Get(query, key) => match query {
+                Query::A => {
+                    db.a(key);
+                }
+                Query::B => {
+                    let _ = db.b(key);
+                }
+                Query::C => {
+                    let _ = db.c(key);
+                }
+            },
+        }
+    }
+}
+
+#[test]
+fn stress_test() {
+    let mut db = StressDatabaseImpl::default();
+    for i in 0..10 {
+        db.set_a(i, i);
+    }
+
+    let mut rng = rand::thread_rng();
+
+    // generate the ops that the mutator thread will perform
+    let write_ops: Vec<MutatorOp> = (0..N_MUTATOR_OPS).map(|_| rng.gen()).collect();
+
+    // execute the "main thread", which sometimes snapshots off other threads
+    let mut all_threads = vec![];
+    for op in write_ops {
+        match op {
+            MutatorOp::WriteOp(w) => w.execute(&mut db),
+            MutatorOp::LaunchReader { ops, check_cancellation } => {
+                all_threads.push(std::thread::spawn({
+                    let db = db.snapshot();
+                    move || Cancelled::catch(|| db_reader_thread(&db, ops, check_cancellation))
+                }))
+            }
+        }
+    }
+
+    for thread in all_threads {
+        thread.join().unwrap().ok();
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/parallel/true_parallel.rs b/src/tools/rust-analyzer/crates/salsa/tests/parallel/true_parallel.rs
new file mode 100644
index 00000000000..d0e58efd1ac
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/parallel/true_parallel.rs
@@ -0,0 +1,125 @@
+use crate::setup::{Knobs, ParDatabase, ParDatabaseImpl, WithValue};
+use salsa::ParallelDatabase;
+use std::panic::{self, AssertUnwindSafe};
+
+/// Test where two threads are executing sum. We show that they can
+/// both be executing sum in parallel by having thread1 wait for
+/// thread2 to send a signal before it leaves (similarly, thread2
+/// waits for thread1 to send a signal before it enters).
+#[test]
+fn true_parallel_different_keys() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+
+    // Thread 1 will signal stage 1 when it enters and wait for stage 2.
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            let v = db
+                .knobs()
+                .sum_signal_on_entry
+                .with_value(1, || db.knobs().sum_wait_for_on_exit.with_value(2, || db.sum("a")));
+            v
+        }
+    });
+
+    // Thread 2 will wait_for stage 1 when it enters and signal stage 2
+    // when it leaves.
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            let v = db
+                .knobs()
+                .sum_wait_for_on_entry
+                .with_value(1, || db.knobs().sum_signal_on_exit.with_value(2, || db.sum("b")));
+            v
+        }
+    });
+
+    assert_eq!(thread1.join().unwrap(), 100);
+    assert_eq!(thread2.join().unwrap(), 10);
+}
+
+/// Add a test that tries to trigger a conflict, where we fetch
+/// `sum("abc")` from two threads simultaneously, and of them
+/// therefore has to block.
+#[test]
+fn true_parallel_same_keys() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 100);
+    db.set_input('b', 10);
+    db.set_input('c', 1);
+
+    // Thread 1 will wait_for a barrier in the start of `sum`
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            let v = db
+                .knobs()
+                .sum_signal_on_entry
+                .with_value(1, || db.knobs().sum_wait_for_on_entry.with_value(2, || db.sum("abc")));
+            v
+        }
+    });
+
+    // Thread 2 will wait until Thread 1 has entered sum and then --
+    // once it has set itself to block -- signal Thread 1 to
+    // continue. This way, we test out the mechanism of one thread
+    // blocking on another.
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            db.knobs().signal.wait_for(1);
+            db.knobs().signal_on_will_block.set(2);
+            db.sum("abc")
+        }
+    });
+
+    assert_eq!(thread1.join().unwrap(), 111);
+    assert_eq!(thread2.join().unwrap(), 111);
+}
+
+/// Add a test that tries to trigger a conflict, where we fetch `sum("a")`
+/// from two threads simultaneously. After `thread2` begins blocking,
+/// we force `thread1` to panic and should see that propagate to `thread2`.
+#[test]
+fn true_parallel_propagate_panic() {
+    let mut db = ParDatabaseImpl::default();
+
+    db.set_input('a', 1);
+
+    // `thread1` will wait_for a barrier in the start of `sum`. Once it can
+    // continue, it will panic.
+    let thread1 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            let v = db.knobs().sum_signal_on_entry.with_value(1, || {
+                db.knobs()
+                    .sum_wait_for_on_entry
+                    .with_value(2, || db.knobs().sum_should_panic.with_value(true, || db.sum("a")))
+            });
+            v
+        }
+    });
+
+    // `thread2` will wait until `thread1` has entered sum and then -- once it
+    // has set itself to block -- signal `thread1` to continue.
+    let thread2 = std::thread::spawn({
+        let db = db.snapshot();
+        move || {
+            db.knobs().signal.wait_for(1);
+            db.knobs().signal_on_will_block.set(2);
+            db.sum("a")
+        }
+    });
+
+    let result1 = panic::catch_unwind(AssertUnwindSafe(|| thread1.join().unwrap()));
+    let result2 = panic::catch_unwind(AssertUnwindSafe(|| thread2.join().unwrap()));
+
+    assert!(result1.is_err());
+    assert!(result2.is_err());
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/implementation.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/implementation.rs
new file mode 100644
index 00000000000..2843660f154
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/implementation.rs
@@ -0,0 +1,19 @@
+use crate::queries;
+use std::cell::Cell;
+
+#[salsa::database(queries::GroupStruct)]
+#[derive(Default)]
+pub(crate) struct DatabaseImpl {
+    storage: salsa::Storage<Self>,
+    counter: Cell<usize>,
+}
+
+impl queries::Counter for DatabaseImpl {
+    fn increment(&self) -> usize {
+        let v = self.counter.get();
+        self.counter.set(v + 1);
+        v
+    }
+}
+
+impl salsa::Database for DatabaseImpl {}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/main.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/main.rs
new file mode 100644
index 00000000000..e92c61740e0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/main.rs
@@ -0,0 +1,5 @@
+mod implementation;
+mod queries;
+mod tests;
+
+fn main() {}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/queries.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/queries.rs
new file mode 100644
index 00000000000..0847fadefb0
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/queries.rs
@@ -0,0 +1,22 @@
+pub(crate) trait Counter: salsa::Database {
+    fn increment(&self) -> usize;
+}
+
+#[salsa::query_group(GroupStruct)]
+pub(crate) trait Database: Counter {
+    fn memoized(&self) -> usize;
+    fn volatile(&self) -> usize;
+}
+
+/// Because this query is memoized, we only increment the counter
+/// the first time it is invoked.
+fn memoized(db: &dyn Database) -> usize {
+    db.volatile()
+}
+
+/// Because this query is volatile, each time it is invoked,
+/// we will increment the counter.
+fn volatile(db: &dyn Database) -> usize {
+    db.salsa_runtime().report_untracked_read();
+    db.increment()
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs
new file mode 100644
index 00000000000..f75c7c142fe
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/storage_varieties/tests.rs
@@ -0,0 +1,49 @@
+#![cfg(test)]
+
+use crate::implementation::DatabaseImpl;
+use crate::queries::Database;
+use salsa::Database as _Database;
+use salsa::Durability;
+
+#[test]
+fn memoized_twice() {
+    let db = DatabaseImpl::default();
+    let v1 = db.memoized();
+    let v2 = db.memoized();
+    assert_eq!(v1, v2);
+}
+
+#[test]
+fn volatile_twice() {
+    let mut db = DatabaseImpl::default();
+    let v1 = db.volatile();
+    let v2 = db.volatile(); // volatiles are cached, so 2nd read returns the same
+    assert_eq!(v1, v2);
+
+    db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches
+
+    let v3 = db.volatile(); // will re-increment the counter
+    let v4 = db.volatile(); // second call will be cached
+    assert_eq!(v1 + 1, v3);
+    assert_eq!(v3, v4);
+}
+
+#[test]
+fn intermingled() {
+    let mut db = DatabaseImpl::default();
+    let v1 = db.volatile();
+    let v2 = db.memoized();
+    let v3 = db.volatile(); // cached
+    let v4 = db.memoized(); // cached
+
+    assert_eq!(v1, v2);
+    assert_eq!(v1, v3);
+    assert_eq!(v2, v4);
+
+    db.salsa_runtime_mut().synthetic_write(Durability::LOW); // clears volatile caches
+
+    let v5 = db.memoized(); // re-executes volatile, caches new result
+    let v6 = db.memoized(); // re-use cached result
+    assert_eq!(v4 + 1, v5);
+    assert_eq!(v5, v6);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/transparent.rs b/src/tools/rust-analyzer/crates/salsa/tests/transparent.rs
new file mode 100644
index 00000000000..2e6dd4267b2
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/transparent.rs
@@ -0,0 +1,39 @@
+//! Test that transparent (uncached) queries work
+
+#[salsa::query_group(QueryGroupStorage)]
+trait QueryGroup {
+    #[salsa::input]
+    fn input(&self, x: u32) -> u32;
+    #[salsa::transparent]
+    fn wrap(&self, x: u32) -> u32;
+    fn get(&self, x: u32) -> u32;
+}
+
+fn wrap(db: &dyn QueryGroup, x: u32) -> u32 {
+    db.input(x)
+}
+
+fn get(db: &dyn QueryGroup, x: u32) -> u32 {
+    db.wrap(x)
+}
+
+#[salsa::database(QueryGroupStorage)]
+#[derive(Default)]
+struct Database {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for Database {}
+
+#[test]
+fn transparent_queries_work() {
+    let mut db = Database::default();
+
+    db.set_input(1, 10);
+    assert_eq!(db.get(1), 10);
+    assert_eq!(db.get(1), 10);
+
+    db.set_input(1, 92);
+    assert_eq!(db.get(1), 92);
+    assert_eq!(db.get(1), 92);
+}
diff --git a/src/tools/rust-analyzer/crates/salsa/tests/variadic.rs b/src/tools/rust-analyzer/crates/salsa/tests/variadic.rs
new file mode 100644
index 00000000000..cb857844eb7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/salsa/tests/variadic.rs
@@ -0,0 +1,51 @@
+#[salsa::query_group(HelloWorld)]
+trait HelloWorldDatabase: salsa::Database {
+    #[salsa::input]
+    fn input(&self, a: u32, b: u32) -> u32;
+
+    fn none(&self) -> u32;
+
+    fn one(&self, k: u32) -> u32;
+
+    fn two(&self, a: u32, b: u32) -> u32;
+
+    fn trailing(&self, a: u32, b: u32) -> u32;
+}
+
+fn none(_db: &dyn HelloWorldDatabase) -> u32 {
+    22
+}
+
+fn one(_db: &dyn HelloWorldDatabase, k: u32) -> u32 {
+    k * 2
+}
+
+fn two(_db: &dyn HelloWorldDatabase, a: u32, b: u32) -> u32 {
+    a * b
+}
+
+fn trailing(_db: &dyn HelloWorldDatabase, a: u32, b: u32) -> u32 {
+    a - b
+}
+
+#[salsa::database(HelloWorld)]
+#[derive(Default)]
+struct DatabaseStruct {
+    storage: salsa::Storage<Self>,
+}
+
+impl salsa::Database for DatabaseStruct {}
+
+#[test]
+fn execute() {
+    let mut db = DatabaseStruct::default();
+
+    // test what happens with inputs:
+    db.set_input(1, 2, 3);
+    assert_eq!(db.input(1, 2), 3);
+
+    assert_eq!(db.none(), 22);
+    assert_eq!(db.one(11), 22);
+    assert_eq!(db.two(11, 2), 22);
+    assert_eq!(db.trailing(24, 2), 22);
+}
diff --git a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs
index 18fa77fd974..295b716b4e9 100644
--- a/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/sourcegen/src/lib.rs
@@ -69,7 +69,7 @@ impl CommentBlock {
                 panic!("Use plain (non-doc) comments with tags like {tag}:\n    {first}");
             }
 
-            block.id = id.trim().to_string();
+            block.id = id.trim().to_owned();
             true
         });
         blocks
@@ -93,7 +93,7 @@ impl CommentBlock {
                     if let Some(' ') = contents.chars().next() {
                         contents = &contents[1..];
                     }
-                    block.contents.push(contents.to_string());
+                    block.contents.push(contents.to_owned());
                 }
                 None => {
                     if !block.contents.is_empty() {
@@ -167,6 +167,7 @@ pub fn add_preamble(generator: &'static str, mut text: String) -> String {
 
 /// Checks that the `file` has the specified `contents`. If that is not the
 /// case, updates the file and then fails the test.
+#[allow(clippy::print_stderr)]
 pub fn ensure_file_contents(file: &Path, contents: &str) {
     if let Ok(old_contents) = fs::read_to_string(file) {
         if normalize_newlines(&old_contents) == normalize_newlines(contents) {
diff --git a/src/tools/rust-analyzer/crates/span/Cargo.toml b/src/tools/rust-analyzer/crates/span/Cargo.toml
index a4abba29bb9..7093f3a691e 100644
--- a/src/tools/rust-analyzer/crates/span/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/span/Cargo.toml
@@ -11,7 +11,7 @@ authors.workspace = true
 
 [dependencies]
 la-arena.workspace = true
-rust-analyzer-salsa.workspace = true
+salsa.workspace = true
 
 
 # local deps
diff --git a/src/tools/rust-analyzer/crates/span/src/lib.rs b/src/tools/rust-analyzer/crates/span/src/lib.rs
index 6796dc41886..7763d75cc92 100644
--- a/src/tools/rust-analyzer/crates/span/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/span/src/lib.rs
@@ -68,26 +68,9 @@ impl fmt::Display for Span {
     }
 }
 
-#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub struct SyntaxContextId(InternId);
 
-impl fmt::Debug for SyntaxContextId {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        if *self == Self::SELF_REF {
-            f.debug_tuple("SyntaxContextId")
-                .field(&{
-                    #[derive(Debug)]
-                    #[allow(non_camel_case_types)]
-                    struct SELF_REF;
-                    SELF_REF
-                })
-                .finish()
-        } else {
-            f.debug_tuple("SyntaxContextId").field(&self.0).finish()
-        }
-    }
-}
-
 impl salsa::InternKey for SyntaxContextId {
     fn from_intern_id(v: salsa::InternId) -> Self {
         SyntaxContextId(v)
@@ -106,10 +89,6 @@ impl fmt::Display for SyntaxContextId {
 // inherent trait impls please tyvm
 impl SyntaxContextId {
     pub const ROOT: Self = SyntaxContextId(unsafe { InternId::new_unchecked(0) });
-    // veykril(HACK): FIXME salsa doesn't allow us fetching the id of the current input to be allocated so
-    // we need a special value that behaves as the current context.
-    pub const SELF_REF: Self =
-        SyntaxContextId(unsafe { InternId::new_unchecked(InternId::MAX - 1) });
 
     pub fn is_root(self) -> bool {
         self == Self::ROOT
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index 2e3f9113b06..6cca1163353 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -29,4 +29,4 @@ winapi = { version = "0.3.9", features = ["winerror"] }
 # default = [ "backtrace" ]
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
index 9990f8b0860..899cd8ac6bb 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/anymap.rs
@@ -54,12 +54,13 @@ use core::any::{Any, TypeId};
 use core::hash::BuildHasherDefault;
 use core::marker::PhantomData;
 
-use ::std::collections::hash_map::{self, HashMap};
+use ::std::collections::hash_map;
 
 /// Raw access to the underlying `HashMap`.
 ///
 /// This alias is provided for convenience because of the ugly third generic parameter.
-pub type RawMap<A> = HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>;
+#[allow(clippy::disallowed_types)] // Uses a custom hasher
+pub type RawMap<A> = hash_map::HashMap<TypeId, Box<A>, BuildHasherDefault<TypeIdHasher>>;
 
 /// A collection containing zero or one values for any given type and allowing convenient,
 /// type-safe access to those values.
diff --git a/src/tools/rust-analyzer/crates/stdx/src/lib.rs b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
index 07b78272281..9a9ebae74e8 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/lib.rs
@@ -23,12 +23,14 @@ pub fn is_ci() -> bool {
 }
 
 #[must_use]
+#[allow(clippy::print_stderr)]
 pub fn timeit(label: &'static str) -> impl Drop {
     let start = Instant::now();
     defer(move || eprintln!("{}: {:.2?}", label, start.elapsed()))
 }
 
 /// Prints backtrace to stderr, useful for debugging.
+#[allow(clippy::print_stderr)]
 pub fn print_backtrace() {
     #[cfg(feature = "backtrace")]
     eprintln!("{:?}", backtrace::Backtrace::new());
diff --git a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
index c3e8813b0e8..cf3d85b4da3 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/panic_context.rs
@@ -18,6 +18,7 @@ pub struct PanicContext {
 }
 
 impl PanicContext {
+    #[allow(clippy::print_stderr)]
     fn init() {
         let default_hook = panic::take_hook();
         let hook = move |panic_info: &panic::PanicInfo<'_>| {
@@ -43,7 +44,7 @@ impl Drop for PanicContext {
 
 fn with_ctx(f: impl FnOnce(&mut Vec<String>)) {
     thread_local! {
-        static CTX: RefCell<Vec<String>> = RefCell::new(Vec::new());
+        static CTX: RefCell<Vec<String>> = const { RefCell::new(Vec::new()) };
     }
     CTX.with(|ctx| f(&mut ctx.borrow_mut()));
 }
diff --git a/src/tools/rust-analyzer/crates/stdx/src/rand.rs b/src/tools/rust-analyzer/crates/stdx/src/rand.rs
index 64aa57eae09..115a073dab3 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/rand.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/rand.rs
@@ -14,8 +14,7 @@ pub fn shuffle<T>(slice: &mut [T], mut rand_index: impl FnMut(usize) -> usize) {
 }
 
 pub fn seed() -> u64 {
-    use std::collections::hash_map::RandomState;
     use std::hash::{BuildHasher, Hasher};
-
-    RandomState::new().build_hasher().finish()
+    #[allow(clippy::disallowed_types)]
+    std::collections::hash_map::RandomState::new().build_hasher().finish()
 }
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
index c9944b75b09..bc9c54d0b73 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/edit_in_place.rs
@@ -627,6 +627,8 @@ impl ast::Impl {
 }
 
 impl ast::AssocItemList {
+    /// Adds a new associated item after all of the existing associated items.
+    ///
     /// Attention! This function does align the first line of `item` with respect to `self`,
     /// but it does _not_ change indentation of other lines (if any).
     pub fn add_item(&self, item: ast::AssocItem) {
@@ -650,6 +652,46 @@ impl ast::AssocItemList {
         ];
         ted::insert_all(position, elements);
     }
+
+    /// Adds a new associated item at the start of the associated item list.
+    ///
+    /// Attention! This function does align the first line of `item` with respect to `self`,
+    /// but it does _not_ change indentation of other lines (if any).
+    pub fn add_item_at_start(&self, item: ast::AssocItem) {
+        match self.assoc_items().next() {
+            Some(first_item) => {
+                let indent = IndentLevel::from_node(first_item.syntax());
+                let before = Position::before(first_item.syntax());
+
+                ted::insert_all(
+                    before,
+                    vec![
+                        item.syntax().clone().into(),
+                        make::tokens::whitespace(&format!("\n\n{indent}")).into(),
+                    ],
+                )
+            }
+            None => {
+                let (indent, position, whitespace) = match self.l_curly_token() {
+                    Some(l_curly) => {
+                        normalize_ws_between_braces(self.syntax());
+                        (IndentLevel::from_token(&l_curly) + 1, Position::after(&l_curly), "\n")
+                    }
+                    None => (IndentLevel::single(), Position::first_child_of(self.syntax()), ""),
+                };
+
+                let mut elements = vec![];
+
+                // Avoid pushing an empty whitespace token
+                if !indent.is_zero() || !whitespace.is_empty() {
+                    elements.push(make::tokens::whitespace(&format!("{whitespace}{indent}")).into())
+                }
+                elements.push(item.syntax().clone().into());
+
+                ted::insert_all(position, elements)
+            }
+        };
+    }
 }
 
 impl ast::Fn {
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
index d5eda8f15e4..120d801c8d1 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -68,6 +68,9 @@ pub mod ext {
     pub fn expr_ty_new(ty: &ast::Type) -> ast::Expr {
         expr_from_text(&format!("{ty}::new()"))
     }
+    pub fn expr_self() -> ast::Expr {
+        expr_from_text("self")
+    }
 
     pub fn zero_number() -> ast::Expr {
         expr_from_text("0")
@@ -236,24 +239,21 @@ fn merge_where_clause(
 
 pub fn impl_(
     generic_params: Option<ast::GenericParamList>,
-    generic_args: Option<ast::GenericParamList>,
+    generic_args: Option<ast::GenericArgList>,
     path_type: ast::Type,
     where_clause: Option<ast::WhereClause>,
     body: Option<Vec<either::Either<ast::Attr, ast::AssocItem>>>,
 ) -> ast::Impl {
-    let (gen_params, tr_gen_args) = match (generic_params, generic_args) {
-        (None, None) => (String::new(), String::new()),
-        (None, Some(args)) => (String::new(), args.to_generic_args().to_string()),
-        (Some(params), None) => (params.to_string(), params.to_generic_args().to_string()),
-        (Some(params), Some(args)) => match merge_gen_params(Some(params.clone()), Some(args)) {
-            Some(merged) => (params.to_string(), merged.to_generic_args().to_string()),
-            None => (params.to_string(), String::new()),
-        },
-    };
+    let gen_args = generic_args.map_or_else(String::new, |it| it.to_string());
+
+    let gen_params = generic_params.map_or_else(String::new, |it| it.to_string());
+
+    let body_newline =
+        if where_clause.is_some() && body.is_none() { "\n".to_owned() } else { String::new() };
 
     let where_clause = match where_clause {
-        Some(pr) => pr.to_string(),
-        None => " ".to_string(),
+        Some(pr) => format!("\n{pr}\n"),
+        None => " ".to_owned(),
     };
 
     let body = match body {
@@ -261,7 +261,9 @@ pub fn impl_(
         None => String::new(),
     };
 
-    ast_from_text(&format!("impl{gen_params} {path_type}{tr_gen_args}{where_clause}{{{}}}", body))
+    ast_from_text(&format!(
+        "impl{gen_params} {path_type}{gen_args}{where_clause}{{{body_newline}{body}}}"
+    ))
 }
 
 pub fn impl_trait(
@@ -282,22 +284,27 @@ pub fn impl_trait(
     let trait_gen_args = trait_gen_args.map(|args| args.to_string()).unwrap_or_default();
     let type_gen_args = type_gen_args.map(|args| args.to_string()).unwrap_or_default();
 
-    let gen_params = match merge_gen_params(trait_gen_params, type_gen_params) {
-        Some(pars) => pars.to_string(),
-        None => String::new(),
-    };
+    let gen_params = merge_gen_params(trait_gen_params, type_gen_params)
+        .map_or_else(String::new, |it| it.to_string());
 
     let is_negative = if is_negative { "! " } else { "" };
 
+    let body_newline =
+        if (ty_where_clause.is_some() || trait_where_clause.is_some()) && body.is_none() {
+            "\n".to_owned()
+        } else {
+            String::new()
+        };
+
     let where_clause = merge_where_clause(ty_where_clause, trait_where_clause)
-        .map_or_else(|| " ".to_string(), |wc| format!("\n{}\n", wc));
+        .map_or_else(|| " ".to_owned(), |wc| format!("\n{}\n", wc));
 
     let body = match body {
         Some(bd) => bd.iter().map(|elem| elem.to_string()).join(""),
         None => String::new(),
     };
 
-    ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{{{}}}" , body))
+    ast_from_text(&format!("{is_unsafe}impl{gen_params} {is_negative}{path_type}{trait_gen_args} for {ty}{type_gen_args}{where_clause}{{{body_newline}{body}}}"))
 }
 
 pub fn impl_trait_type(bounds: ast::TypeBoundList) -> ast::ImplTraitType {
@@ -371,7 +378,7 @@ pub fn use_tree(
     alias: Option<ast::Rename>,
     add_star: bool,
 ) -> ast::UseTree {
-    let mut buf = "use ".to_string();
+    let mut buf = "use ".to_owned();
     buf += &path.syntax().to_string();
     if let Some(use_tree_list) = use_tree_list {
         format_to!(buf, "::{use_tree_list}");
@@ -437,7 +444,7 @@ pub fn block_expr(
     stmts: impl IntoIterator<Item = ast::Stmt>,
     tail_expr: Option<ast::Expr>,
 ) -> ast::BlockExpr {
-    let mut buf = "{\n".to_string();
+    let mut buf = "{\n".to_owned();
     for stmt in stmts.into_iter() {
         format_to!(buf, "    {stmt}\n");
     }
@@ -452,7 +459,7 @@ pub fn async_move_block_expr(
     stmts: impl IntoIterator<Item = ast::Stmt>,
     tail_expr: Option<ast::Expr>,
 ) -> ast::BlockExpr {
-    let mut buf = "async move {\n".to_string();
+    let mut buf = "async move {\n".to_owned();
     for stmt in stmts.into_iter() {
         format_to!(buf, "    {stmt}\n");
     }
@@ -475,7 +482,7 @@ pub fn hacky_block_expr(
     elements: impl IntoIterator<Item = crate::SyntaxElement>,
     tail_expr: Option<ast::Expr>,
 ) -> ast::BlockExpr {
-    let mut buf = "{\n".to_string();
+    let mut buf = "{\n".to_owned();
     for node_or_token in elements.into_iter() {
         match node_or_token {
             rowan::NodeOrToken::Node(n) => format_to!(buf, "    {n}\n"),
@@ -903,7 +910,12 @@ pub fn trait_(
     ast_from_text(&text)
 }
 
-pub fn type_bound(bound: &str) -> ast::TypeBound {
+// FIXME: remove when no one depends on `generate_impl_text_inner`
+pub fn type_bound_text(bound: &str) -> ast::TypeBound {
+    ast_from_text(&format!("fn f<T: {bound}>() {{ }}"))
+}
+
+pub fn type_bound(bound: ast::Type) -> ast::TypeBound {
     ast_from_text(&format!("fn f<T: {bound}>() {{ }}"))
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
index 239a89f9b2d..28738671790 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/fuzz.rs
@@ -34,7 +34,7 @@ impl CheckReparse {
         let mut lines = data.lines();
         let delete_start = usize::from_str(lines.next()?).ok()? + PREFIX.len();
         let delete_len = usize::from_str(lines.next()?).ok()?;
-        let insert = lines.next()?.to_string();
+        let insert = lines.next()?.to_owned();
         let text = lines.collect::<Vec<_>>().join("\n");
         let text = format!("{PREFIX}{text}{SUFFIX}");
         text.get(delete_start..delete_start.checked_add(delete_len)?)?; // make sure delete is a valid range
@@ -46,6 +46,7 @@ impl CheckReparse {
         Some(CheckReparse { text, edit, edited_text })
     }
 
+    #[allow(clippy::print_stderr)]
     pub fn run(&self) {
         let parse = SourceFile::parse(&self.text);
         let new_parse = parse.reparse(&self.edit);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/lib.rs b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
index 62a0261d7a4..960889b7421 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/lib.rs
@@ -432,7 +432,7 @@ fn api_walkthrough() {
             WalkEvent::Enter(node) => {
                 let text = match &node {
                     NodeOrToken::Node(it) => it.text().to_string(),
-                    NodeOrToken::Token(it) => it.text().to_string(),
+                    NodeOrToken::Token(it) => it.text().to_owned(),
                 };
                 format_to!(buf, "{:indent$}{:?} {:?}\n", " ", text, node.kind(), indent = indent);
                 indent += 2;
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
index 047e670c9f4..1250b5274c1 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing.rs
@@ -28,7 +28,7 @@ pub(crate) fn build_tree(
         parser::StrStep::Enter { kind } => builder.start_node(kind),
         parser::StrStep::Exit => builder.finish_node(),
         parser::StrStep::Error { msg, pos } => {
-            builder.error(msg.to_string(), pos.try_into().unwrap())
+            builder.error(msg.to_owned(), pos.try_into().unwrap())
         }
     });
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
index 0ddc641711f..14715b57253 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/parsing/reparsing.rs
@@ -105,7 +105,7 @@ fn get_text_after_edit(element: SyntaxElement, edit: &Indel) -> String {
     let edit = Indel::replace(edit.delete - element.text_range().start(), edit.insert.clone());
 
     let mut text = match element {
-        NodeOrToken::Token(token) => token.text().to_string(),
+        NodeOrToken::Token(token) => token.text().to_owned(),
         NodeOrToken::Node(node) => node.text().to_string(),
     };
     edit.apply(&mut text);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs
index b716d367066..fb8aee9c3b0 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ptr.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ptr.rs
@@ -36,7 +36,7 @@ impl<N: AstNode + std::fmt::Debug> std::fmt::Debug for AstPtr<N> {
 impl<N: AstNode> Copy for AstPtr<N> {}
 impl<N: AstNode> Clone for AstPtr<N> {
     fn clone(&self) -> AstPtr<N> {
-        AstPtr { raw: self.raw, _ty: PhantomData }
+        *self
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index c2e921e4b6f..2fd7a473498 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -3,14 +3,12 @@
 //! Specifically, it generates the `SyntaxKind` enum and a number of newtype
 //! wrappers around `SyntaxNode` which implement `syntax::AstNode`.
 
-use std::{
-    collections::{BTreeSet, HashSet},
-    fmt::Write,
-};
+use std::{collections::BTreeSet, fmt::Write};
 
 use itertools::Itertools;
 use proc_macro2::{Punct, Spacing};
 use quote::{format_ident, quote};
+use rustc_hash::FxHashSet;
 use ungrammar::{Grammar, Rule};
 
 use crate::tests::ast_src::{
@@ -278,7 +276,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
             }
         });
 
-    let defined_nodes: HashSet<_> = node_names.collect();
+    let defined_nodes: FxHashSet<_> = node_names.collect();
 
     for node in kinds
         .nodes
@@ -575,7 +573,7 @@ fn lower(grammar: &Grammar) -> AstSrc {
         tokens:
             "Whitespace Comment String ByteString CString IntNumber FloatNumber Char Byte Ident"
                 .split_ascii_whitespace()
-                .map(|it| it.to_string())
+                .map(|it| it.to_owned())
                 .collect::<Vec<_>>(),
         ..Default::default()
     };
@@ -818,7 +816,7 @@ fn extract_struct_trait(node: &mut AstNodeSrc, trait_name: &str, methods: &[&str
         }
     }
     if to_remove.len() == methods.len() {
-        node.traits.push(trait_name.to_string());
+        node.traits.push(trait_name.to_owned());
         node.remove_field(to_remove);
     }
 }
diff --git a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
index b5ff7a1bf51..28e757e81bb 100644
--- a/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-fixture/src/lib.rs
@@ -260,7 +260,7 @@ impl ChangeFixture {
             file_id = FileId::from_raw(file_id.index() + 1);
 
             let mut fs = FileSet::default();
-            fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_string()));
+            fs.insert(core_file, VfsPath::new_virtual_path("/sysroot/core/lib.rs".to_owned()));
             roots.push(SourceRoot::new_library(fs));
 
             source_change.change_file(core_file, Some(mini_core.source_code().into()));
@@ -270,7 +270,7 @@ impl ChangeFixture {
             let core_crate = crate_graph.add_crate_root(
                 core_file,
                 Edition::Edition2021,
-                Some(CrateDisplayName::from_canonical_name("core".to_string())),
+                Some(CrateDisplayName::from_canonical_name("core".to_owned())),
                 None,
                 Default::default(),
                 Default::default(),
@@ -304,7 +304,7 @@ impl ChangeFixture {
             let mut fs = FileSet::default();
             fs.insert(
                 proc_lib_file,
-                VfsPath::new_virtual_path("/sysroot/proc_macros/lib.rs".to_string()),
+                VfsPath::new_virtual_path("/sysroot/proc_macros/lib.rs".to_owned()),
             );
             roots.push(SourceRoot::new_library(fs));
 
@@ -315,7 +315,7 @@ impl ChangeFixture {
             let proc_macros_crate = crate_graph.add_crate_root(
                 proc_lib_file,
                 Edition::Edition2021,
-                Some(CrateDisplayName::from_canonical_name("proc_macros".to_string())),
+                Some(CrateDisplayName::from_canonical_name("proc_macros".to_owned())),
                 None,
                 Default::default(),
                 Default::default(),
@@ -598,7 +598,7 @@ impl ProcMacroExpander for MirrorProcMacroExpander {
                 };
                 token_trees.push(tt);
             }
-            Subtree { delimiter: input.delimiter, token_trees }
+            Subtree { delimiter: input.delimiter, token_trees: token_trees.into_boxed_slice() }
         }
         Ok(traverse(input))
     }
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/bench_fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/bench_fixture.rs
index 9296fd2e683..d83f9576862 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/bench_fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/bench_fixture.rs
@@ -12,7 +12,7 @@ pub fn big_struct() -> String {
 }
 
 pub fn big_struct_n(n: u32) -> String {
-    let mut buf = "pub struct RegisterBlock {".to_string();
+    let mut buf = "pub struct RegisterBlock {".to_owned();
     for i in 0..n {
         format_to!(buf, "  /// Doc comment for {}.\n", i);
         format_to!(buf, "  pub s{}: S{},\n", i, i);
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
index 3f8b5a08969..595281336d5 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/fixture.rs
@@ -178,13 +178,13 @@ impl FixtureWithProjectMeta {
 
         if let Some(meta) = fixture.strip_prefix("//- toolchain:") {
             let (meta, remain) = meta.split_once('\n').unwrap();
-            toolchain = Some(meta.trim().to_string());
+            toolchain = Some(meta.trim().to_owned());
             fixture = remain;
         }
 
         if let Some(meta) = fixture.strip_prefix("//- proc_macros:") {
             let (meta, remain) = meta.split_once('\n').unwrap();
-            proc_macro_names = meta.split(',').map(|it| it.trim().to_string()).collect();
+            proc_macro_names = meta.split(',').map(|it| it.trim().to_owned()).collect();
             fixture = remain;
         }
 
@@ -234,7 +234,7 @@ impl FixtureWithProjectMeta {
         let meta = meta["//-".len()..].trim();
         let mut components = meta.split_ascii_whitespace();
 
-        let path = components.next().expect("fixture meta must start with a path").to_string();
+        let path = components.next().expect("fixture meta must start with a path").to_owned();
         assert!(path.starts_with('/'), "fixture path does not start with `/`: {path:?}");
 
         let mut krate = None;
@@ -246,7 +246,7 @@ impl FixtureWithProjectMeta {
         let mut introduce_new_source_root = None;
         let mut library = false;
         let mut target_data_layout = Some(
-            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_string(),
+            "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128".to_owned(),
         );
         for component in components {
             if component == "library" {
@@ -257,22 +257,22 @@ impl FixtureWithProjectMeta {
             let (key, value) =
                 component.split_once(':').unwrap_or_else(|| panic!("invalid meta line: {meta:?}"));
             match key {
-                "crate" => krate = Some(value.to_string()),
-                "deps" => deps = value.split(',').map(|it| it.to_string()).collect(),
+                "crate" => krate = Some(value.to_owned()),
+                "deps" => deps = value.split(',').map(|it| it.to_owned()).collect(),
                 "extern-prelude" => {
                     if value.is_empty() {
                         extern_prelude = Some(Vec::new());
                     } else {
                         extern_prelude =
-                            Some(value.split(',').map(|it| it.to_string()).collect::<Vec<_>>());
+                            Some(value.split(',').map(|it| it.to_owned()).collect::<Vec<_>>());
                     }
                 }
-                "edition" => edition = Some(value.to_string()),
+                "edition" => edition = Some(value.to_owned()),
                 "cfg" => {
                     for entry in value.split(',') {
                         match entry.split_once('=') {
-                            Some((k, v)) => cfgs.push((k.to_string(), Some(v.to_string()))),
-                            None => cfgs.push((entry.to_string(), None)),
+                            Some((k, v)) => cfgs.push((k.to_owned(), Some(v.to_owned()))),
+                            None => cfgs.push((entry.to_owned(), None)),
                         }
                     }
                 }
@@ -283,8 +283,8 @@ impl FixtureWithProjectMeta {
                         }
                     }
                 }
-                "new_source_root" => introduce_new_source_root = Some(value.to_string()),
-                "target_data_layout" => target_data_layout = Some(value.to_string()),
+                "new_source_root" => introduce_new_source_root = Some(value.to_owned()),
+                "target_data_layout" => target_data_layout = Some(value.to_owned()),
                 _ => panic!("bad component: {component:?}"),
             }
         }
@@ -381,7 +381,7 @@ impl MiniCore {
             let (flag, deps) = line.split_once(':').unwrap();
             let flag = flag.trim();
 
-            self.valid_flags.push(flag.to_string());
+            self.valid_flags.push(flag.to_owned());
             implications.extend(
                 iter::repeat(flag)
                     .zip(deps.split(", ").map(str::trim).filter(|dep| !dep.is_empty())),
@@ -401,7 +401,7 @@ impl MiniCore {
             let mut changed = false;
             for &(u, v) in &implications {
                 if self.has_flag(u) && !self.has_flag(v) {
-                    self.activated_flags.push(v.to_string());
+                    self.activated_flags.push(v.to_owned());
                     changed = true;
                 }
             }
@@ -486,9 +486,9 @@ fn parse_fixture_gets_full_meta() {
 mod m;
 "#,
         );
-    assert_eq!(toolchain, Some("nightly".to_string()));
-    assert_eq!(proc_macro_names, vec!["identity".to_string()]);
-    assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_string()]);
+    assert_eq!(toolchain, Some("nightly".to_owned()));
+    assert_eq!(proc_macro_names, vec!["identity".to_owned()]);
+    assert_eq!(mini_core.unwrap().activated_flags, vec!["coerce_unsized".to_owned()]);
     assert_eq!(1, parsed.len());
 
     let meta = &parsed[0];
diff --git a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
index e48b2731306..b750107803a 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/lib.rs
@@ -7,6 +7,7 @@
 //! * marks (see the eponymous module).
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(clippy::print_stderr)]
 
 mod assert_linear;
 pub mod bench_fixture;
@@ -163,7 +164,7 @@ pub fn extract_tags(mut text: &str, tag: &str) -> (Vec<(TextRange, Option<String
                 if text.starts_with(&open) {
                     let close_open = text.find('>').unwrap();
                     let attr = text[open.len()..close_open].trim();
-                    let attr = if attr.is_empty() { None } else { Some(attr.to_string()) };
+                    let attr = if attr.is_empty() { None } else { Some(attr.to_owned()) };
                     text = &text[close_open + '>'.len_utf8()..];
                     let from = TextSize::of(&res);
                     stack.push((from, attr));
@@ -325,7 +326,7 @@ fn extract_line_annotations(mut line: &str) -> Vec<LineAnnotation> {
             content = &content["file".len()..];
         }
 
-        let content = content.trim_start().to_string();
+        let content = content.trim_start().to_owned();
 
         let annotation = if continuation {
             LineAnnotation::Continuation { offset: range.end(), content }
@@ -424,7 +425,7 @@ pub fn format_diff(chunks: Vec<dissimilar::Chunk<'_>>) -> String {
 ///
 /// A benchmark test looks like this:
 ///
-/// ```
+/// ```ignore
 /// #[test]
 /// fn benchmark_foo() {
 ///     if skip_slow_tests() { return; }
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 9c25d88cb84..23a3a7e0afa 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -328,7 +328,6 @@ pub mod convert {
 }
 
 pub mod mem {
-    // region:drop
     // region:manually_drop
     #[lang = "manually_drop"]
     #[repr(transparent)]
@@ -353,6 +352,7 @@ pub mod mem {
 
     // endregion:manually_drop
 
+    // region:drop
     pub fn drop<T>(_x: T) {}
     pub const fn replace<T>(dest: &mut T, src: T) -> T {
         unsafe {
diff --git a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs b/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
index fb52a50f0b3..e2ff373c1ba 100644
--- a/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/text-edit/src/lib.rs
@@ -231,11 +231,11 @@ mod tests {
 
     #[test]
     fn test_apply() {
-        let mut text = "_11h1_2222_xx3333_4444_6666".to_string();
+        let mut text = "_11h1_2222_xx3333_4444_6666".to_owned();
         let mut builder = TextEditBuilder::default();
-        builder.replace(range(3, 4), "1".to_string());
+        builder.replace(range(3, 4), "1".to_owned());
         builder.delete(range(11, 13));
-        builder.insert(22.into(), "_5555".to_string());
+        builder.insert(22.into(), "_5555".to_owned());
 
         let text_edit = builder.finish();
         text_edit.apply(&mut text);
diff --git a/src/tools/rust-analyzer/crates/tt/src/buffer.rs b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
index cade2e9f67a..cd41af03c61 100644
--- a/src/tools/rust-analyzer/crates/tt/src/buffer.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/buffer.rs
@@ -106,7 +106,7 @@ impl<'t, Span> TokenBuffer<'t, Span> {
 
         for (child_idx, (subtree, tt)) in children {
             let idx = TokenBuffer::new_inner(
-                subtree.token_trees.as_slice(),
+                &*subtree.token_trees,
                 buffers,
                 Some(EntryPtr(EntryId(res), child_idx + 1)),
             );
diff --git a/src/tools/rust-analyzer/crates/tt/src/lib.rs b/src/tools/rust-analyzer/crates/tt/src/lib.rs
index b3b0eeda75a..9004bff53a8 100644
--- a/src/tools/rust-analyzer/crates/tt/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/tt/src/lib.rs
@@ -23,10 +23,10 @@ pub enum TokenTree<S> {
 }
 impl_from!(Leaf<S>, Subtree<S> for TokenTree);
 impl<S: Span> TokenTree<S> {
-    pub const fn empty(span: S) -> Self {
+    pub fn empty(span: S) -> Self {
         Self::Subtree(Subtree {
             delimiter: Delimiter::invisible_spanned(span),
-            token_trees: vec![],
+            token_trees: Box::new([]),
         })
     }
 
@@ -34,7 +34,7 @@ impl<S: Span> TokenTree<S> {
         match self {
             TokenTree::Leaf(_) => Subtree {
                 delimiter: Delimiter::invisible_delim_spanned(span),
-                token_trees: vec![self],
+                token_trees: Box::new([self]),
             },
             TokenTree::Subtree(s) => s,
         }
@@ -69,25 +69,35 @@ impl_from!(Literal<S>, Punct<S>, Ident<S> for Leaf);
 #[derive(Clone, PartialEq, Eq, Hash)]
 pub struct Subtree<S> {
     pub delimiter: Delimiter<S>,
-    pub token_trees: Vec<TokenTree<S>>,
+    pub token_trees: Box<[TokenTree<S>]>,
 }
 
 impl<S: Span> Subtree<S> {
-    pub const fn empty(span: DelimSpan<S>) -> Self {
-        Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: vec![] }
+    pub fn empty(span: DelimSpan<S>) -> Self {
+        Subtree { delimiter: Delimiter::invisible_delim_spanned(span), token_trees: Box::new([]) }
     }
 
-    pub fn visit_ids(&mut self, f: &mut impl FnMut(S) -> S) {
-        self.delimiter.open = f(self.delimiter.open);
-        self.delimiter.close = f(self.delimiter.close);
-        self.token_trees.iter_mut().for_each(|tt| match tt {
-            crate::TokenTree::Leaf(leaf) => match leaf {
-                crate::Leaf::Literal(it) => it.span = f(it.span),
-                crate::Leaf::Punct(it) => it.span = f(it.span),
-                crate::Leaf::Ident(it) => it.span = f(it.span),
-            },
-            crate::TokenTree::Subtree(s) => s.visit_ids(f),
-        })
+    /// This is slow, and should be avoided, as it will always reallocate!
+    pub fn push(&mut self, subtree: TokenTree<S>) {
+        let mut mutable_trees = std::mem::take(&mut self.token_trees).into_vec();
+
+        // Reserve exactly space for one element, to avoid `into_boxed_slice` having to reallocate again.
+        mutable_trees.reserve_exact(1);
+        mutable_trees.push(subtree);
+
+        self.token_trees = mutable_trees.into_boxed_slice();
+    }
+}
+
+#[derive(Clone, PartialEq, Eq, Hash)]
+pub struct SubtreeBuilder<S> {
+    pub delimiter: Delimiter<S>,
+    pub token_trees: Vec<TokenTree<S>>,
+}
+
+impl<S> SubtreeBuilder<S> {
+    pub fn build(self) -> Subtree<S> {
+        Subtree { delimiter: self.delimiter, token_trees: self.token_trees.into_boxed_slice() }
     }
 }
 
@@ -241,7 +251,7 @@ impl<S> fmt::Display for Subtree<S> {
         };
         f.write_str(l)?;
         let mut needs_space = false;
-        for tt in &self.token_trees {
+        for tt in self.token_trees.iter() {
             if needs_space {
                 f.write_str(" ")?;
             }
@@ -316,7 +326,7 @@ impl<S> Subtree<S> {
         let mut res = String::new();
         res.push_str(delim.0);
         let mut last = None;
-        for child in &self.token_trees {
+        for child in self.token_trees.iter() {
             let s = match child {
                 TokenTree::Leaf(it) => {
                     let s = match it {
@@ -326,11 +336,11 @@ impl<S> Subtree<S> {
                     };
                     match (it, last) {
                         (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => {
-                            " ".to_string() + &s
+                            " ".to_owned() + &s
                         }
                         (Leaf::Punct(_), Some(TokenTree::Leaf(Leaf::Punct(punct)))) => {
                             if punct.spacing == Spacing::Alone {
-                                " ".to_string() + &s
+                                " ".to_owned() + &s
                             } else {
                                 s
                             }
diff --git a/src/tools/rust-analyzer/crates/vfs/src/loader.rs b/src/tools/rust-analyzer/crates/vfs/src/loader.rs
index e49849d2307..c3d1ff7271a 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/loader.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/loader.rs
@@ -201,7 +201,7 @@ impl Directories {
 /// ```
 fn dirs(base: AbsPathBuf, exclude: &[&str]) -> Directories {
     let exclude = exclude.iter().map(|it| base.join(it)).collect::<Vec<_>>();
-    Directories { extensions: vec!["rs".to_string()], include: vec![base], exclude }
+    Directories { extensions: vec!["rs".to_owned()], include: vec![base], exclude }
 }
 
 impl fmt::Debug for Message {
diff --git a/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs b/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs
index 510e021e890..2d89362ee06 100644
--- a/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs
+++ b/src/tools/rust-analyzer/crates/vfs/src/vfs_path/tests.rs
@@ -2,29 +2,29 @@ use super::*;
 
 #[test]
 fn virtual_path_extensions() {
-    assert_eq!(VirtualPath("/".to_string()).name_and_extension(), None);
+    assert_eq!(VirtualPath("/".to_owned()).name_and_extension(), None);
     assert_eq!(
-        VirtualPath("/directory".to_string()).name_and_extension(),
+        VirtualPath("/directory".to_owned()).name_and_extension(),
         Some(("directory", None))
     );
     assert_eq!(
-        VirtualPath("/directory/".to_string()).name_and_extension(),
+        VirtualPath("/directory/".to_owned()).name_and_extension(),
         Some(("directory", None))
     );
     assert_eq!(
-        VirtualPath("/directory/file".to_string()).name_and_extension(),
+        VirtualPath("/directory/file".to_owned()).name_and_extension(),
         Some(("file", None))
     );
     assert_eq!(
-        VirtualPath("/directory/.file".to_string()).name_and_extension(),
+        VirtualPath("/directory/.file".to_owned()).name_and_extension(),
         Some((".file", None))
     );
     assert_eq!(
-        VirtualPath("/directory/.file.rs".to_string()).name_and_extension(),
+        VirtualPath("/directory/.file.rs".to_owned()).name_and_extension(),
         Some((".file", Some("rs")))
     );
     assert_eq!(
-        VirtualPath("/directory/file.rs".to_string()).name_and_extension(),
+        VirtualPath("/directory/file.rs".to_owned()).name_and_extension(),
         Some(("file", Some("rs")))
     );
 }
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index bc558c20247..f3100ee194e 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: dff0b009e82ef06a
+lsp/ext.rs hash: 8be79cc3b7f10ad7
 
 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:
@@ -445,6 +445,25 @@ Reloads project information (that is, re-executes `cargo metadata`).
 
 Rebuilds build scripts and proc-macros, and runs the build scripts to reseed the build data.
 
+## Unindexed Project
+
+**Experimental Client Capability:** `{ "unindexedProject": boolean }`
+
+**Method:** `rust-analyzer/unindexedProject`
+
+**Notification:**
+
+```typescript
+interface UnindexedProjectParams {
+    /// A list of documents that rust-analyzer has determined are not indexed.
+    textDocuments: lc.TextDocumentIdentifier[]
+}
+```
+
+This notification is sent from the server to the client. The client is expected
+to determine the appropriate owners of `textDocuments` and update `linkedProjects`
+if an owner can be determined successfully.
+
 ## Server Status
 
 **Experimental Client Capability:** `{ "serverStatusNotification": boolean }`
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index cfa7503d739..a86ef709411 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -251,6 +251,12 @@ Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets,
 
 Aliased as `"checkOnSave.targets"`.
 --
+[[rust-analyzer.check.workspace]]rust-analyzer.check.workspace (default: `true`)::
++
+--
+Whether `--workspace` should be passed to `cargo check`.
+If false, `-p <package>` will be passed instead.
+--
 [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 +
 --
@@ -745,6 +751,11 @@ Sets the LRU capacity of the specified queries.
 --
 Whether to show `can't find Cargo.toml` error message.
 --
+[[rust-analyzer.notifications.unindexedProject]]rust-analyzer.notifications.unindexedProject (default: `false`)::
++
+--
+Whether to send an UnindexedProject notification to the client.
+--
 [[rust-analyzer.numThreads]]rust-analyzer.numThreads (default: `null`)::
 +
 --
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 841e364ed84..b474471e5a4 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -803,6 +803,11 @@
                         }
                     ]
                 },
+                "rust-analyzer.check.workspace": {
+                    "markdownDescription": "Whether `--workspace` should be passed to `cargo check`.\nIf false, `-p <package>` will be passed instead.",
+                    "default": true,
+                    "type": "boolean"
+                },
                 "rust-analyzer.completion.autoimport.enable": {
                     "markdownDescription": "Toggles the additional completions that automatically add imports when completed.\nNote that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.",
                     "default": true,
@@ -1468,6 +1473,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.notifications.unindexedProject": {
+                    "markdownDescription": "Whether to send an UnindexedProject notification to the client.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.numThreads": {
                     "markdownDescription": "How many worker threads in the main loop. The default `null` means to pick automatically.",
                     "default": null,
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 55163241c2a..01a3aca1323 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -234,6 +234,23 @@ export class Ctx implements RustAnalyzerExtensionApi {
                     this.outputChannel!.show();
                 }),
             );
+            this.pushClientCleanup(
+                this._client.onNotification(ra.unindexedProject, async (params) => {
+                    if (this.config.discoverProjectRunner) {
+                        const command = `${this.config.discoverProjectRunner}.discoverWorkspaceCommand`;
+                        log.info(`running command: ${command}`);
+                        const uris = params.textDocuments.map((doc) =>
+                            vscode.Uri.parse(doc.uri, true),
+                        );
+                        const projects: JsonProject[] = await vscode.commands.executeCommand(
+                            command,
+                            uris,
+                        );
+                        this.setWorkspaces(projects);
+                        await this.notifyRustAnalyzer();
+                    }
+                }),
+            );
         }
         return this._client;
     }
diff --git a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
index f959a76639e..6c961f53e7e 100644
--- a/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
+++ b/src/tools/rust-analyzer/editors/code/src/lsp_ext.ts
@@ -220,3 +220,9 @@ export type RecursiveMemoryLayoutNode = {
 export type RecursiveMemoryLayout = {
     nodes: RecursiveMemoryLayoutNode[];
 };
+
+export const unindexedProject = new lc.NotificationType<UnindexedProjectParams>(
+    "rust-analyzer/unindexedProject",
+);
+
+export type UnindexedProjectParams = { textDocuments: lc.TextDocumentIdentifier[] };
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index c386b9e5d8f..0af58fd7812 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -207,7 +207,7 @@ function checkConflictingExtensions() {
     if (vscode.extensions.getExtension("panicbit.cargo")) {
         vscode.window
             .showWarningMessage(
-                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Cargo (panicbit.cargo) plugins enabled` +
+                `You have both the rust-analyzer (rust-lang.rust-analyzer) and Cargo (panicbit.cargo) plugins enabled, ` +
                     'you can disable it or set {"cargo.automaticCheck": false} in settings.json to avoid invoking cargo twice',
                 "Got it",
             )
diff --git a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
index d195bdd156b..abde5deda4c 100644
--- a/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/la-arena/src/lib.rs
@@ -70,7 +70,7 @@ impl<T> Ord for Idx<T> {
 
 impl<T> PartialOrd for Idx<T> {
     fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
-        self.raw.partial_cmp(&other.raw)
+        Some(self.cmp(other))
     }
 }
 
@@ -374,7 +374,7 @@ impl<T> Arena<T> {
     /// ```
     pub fn iter(
         &self,
-    ) -> impl Iterator<Item = (Idx<T>, &T)> + ExactSizeIterator + DoubleEndedIterator + Clone {
+    ) -> impl ExactSizeIterator<Item = (Idx<T>, &T)> + DoubleEndedIterator + Clone {
         self.data.iter().enumerate().map(|(idx, value)| (Idx::from_raw(RawIdx(idx as u32)), value))
     }
 
@@ -394,7 +394,7 @@ impl<T> Arena<T> {
     /// ```
     pub fn iter_mut(
         &mut self,
-    ) -> impl Iterator<Item = (Idx<T>, &mut T)> + ExactSizeIterator + DoubleEndedIterator {
+    ) -> impl ExactSizeIterator<Item = (Idx<T>, &mut T)> + DoubleEndedIterator {
         self.data
             .iter_mut()
             .enumerate()
@@ -414,7 +414,7 @@ impl<T> Arena<T> {
     /// assert_eq!(iterator.next(), Some(&40));
     /// assert_eq!(iterator.next(), Some(&60));
     /// ```
-    pub fn values(&self) -> impl Iterator<Item = &T> + ExactSizeIterator + DoubleEndedIterator {
+    pub fn values(&self) -> impl ExactSizeIterator<Item = &T> + DoubleEndedIterator {
         self.data.iter()
     }
 
@@ -432,9 +432,7 @@ impl<T> Arena<T> {
     ///
     /// assert_eq!(arena[idx1], 10);
     /// ```
-    pub fn values_mut(
-        &mut self,
-    ) -> impl Iterator<Item = &mut T> + ExactSizeIterator + DoubleEndedIterator {
+    pub fn values_mut(&mut self) -> impl ExactSizeIterator<Item = &mut T> + DoubleEndedIterator {
         self.data.iter_mut()
     }
 
diff --git a/src/tools/rust-analyzer/lib/la-arena/src/map.rs b/src/tools/rust-analyzer/lib/la-arena/src/map.rs
index c6a43d8f9a6..6e7528c4f7f 100644
--- a/src/tools/rust-analyzer/lib/la-arena/src/map.rs
+++ b/src/tools/rust-analyzer/lib/la-arena/src/map.rs
@@ -73,17 +73,17 @@ impl<T, V> ArenaMap<Idx<T>, V> {
     }
 
     /// Returns an iterator over the values in the map.
-    pub fn values(&self) -> impl Iterator<Item = &V> + DoubleEndedIterator {
+    pub fn values(&self) -> impl DoubleEndedIterator<Item = &V> {
         self.v.iter().filter_map(|o| o.as_ref())
     }
 
     /// Returns an iterator over mutable references to the values in the map.
-    pub fn values_mut(&mut self) -> impl Iterator<Item = &mut V> + DoubleEndedIterator {
+    pub fn values_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut V> {
         self.v.iter_mut().filter_map(|o| o.as_mut())
     }
 
     /// Returns an iterator over the arena indexes and values in the map.
-    pub fn iter(&self) -> impl Iterator<Item = (Idx<T>, &V)> + DoubleEndedIterator {
+    pub fn iter(&self) -> impl DoubleEndedIterator<Item = (Idx<T>, &V)> {
         self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
     }
 
diff --git a/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs b/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs
index 71f66254069..6ad144b85fe 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/examples/goto_def.rs
@@ -41,6 +41,9 @@
 //!
 //! {"jsonrpc": "2.0", "method": "exit", "params": null}
 //! ```
+
+#![allow(clippy::print_stderr)]
+
 use std::error::Error;
 
 use lsp_types::OneOf;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
index e476f8c2d13..5dc052b5875 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/lib.rs
@@ -5,6 +5,7 @@
 //! Run with `RUST_LOG=lsp_server=debug` to see all the messages.
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(clippy::print_stdout, clippy::disallowed_types)]
 
 mod error;
 mod msg;
@@ -359,12 +360,12 @@ impl Connection {
             }
             Err(RecvTimeoutError::Timeout) => {
                 return Err(ProtocolError::new(
-                    "timed out waiting for exit notification".to_string(),
+                    "timed out waiting for exit notification".to_owned(),
                 ))
             }
             Err(RecvTimeoutError::Disconnected) => {
                 return Err(ProtocolError::new(
-                    "channel disconnected waiting for exit notification".to_string(),
+                    "channel disconnected waiting for exit notification".to_owned(),
                 ))
             }
         }
@@ -405,7 +406,7 @@ mod tests {
     #[test]
     fn not_exit_notification() {
         let notification = crate::Notification {
-            method: Initialized::METHOD.to_string(),
+            method: Initialized::METHOD.to_owned(),
             params: to_value(InitializedParams {}).unwrap(),
         };
 
@@ -413,7 +414,7 @@ mod tests {
         let req_id = RequestId::from(234);
         let request = crate::Request {
             id: req_id.clone(),
-            method: Initialize::METHOD.to_string(),
+            method: Initialize::METHOD.to_owned(),
             params: params_as_value.clone(),
         };
 
@@ -426,7 +427,7 @@ mod tests {
     #[test]
     fn exit_notification() {
         let notification =
-            crate::Notification { method: Exit::METHOD.to_string(), params: to_value(()).unwrap() };
+            crate::Notification { method: Exit::METHOD.to_owned(), params: to_value(()).unwrap() };
         let notification_msg = Message::from(notification);
 
         initialize_start_test(TestCase {
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
index ba318dd1690..71e5933689a 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -269,7 +269,7 @@ fn read_msg_text(inp: &mut dyn BufRead) -> io::Result<Option<String>> {
             size = Some(header_value.parse::<usize>().map_err(invalid_data)?);
         }
     }
-    let size: usize = size.ok_or_else(|| invalid_data("no Content-Length".to_string()))?;
+    let size: usize = size.ok_or_else(|| invalid_data("no Content-Length".to_owned()))?;
     let mut buf = buf.into_bytes();
     buf.resize(size, 0);
     inp.read_exact(&mut buf)?;
diff --git a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs
index e5f19be20b0..7b47f5388b5 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/req_queue.rs
@@ -40,7 +40,7 @@ impl<I> Incoming<I> {
         let _data = self.complete(id.clone())?;
         let error = ResponseError {
             code: ErrorCode::RequestCanceled as i32,
-            message: "canceled by client".to_string(),
+            message: "canceled by client".to_owned(),
             data: None,
         };
         Some(Response { id, result: None, error: Some(error) })
diff --git a/src/tools/rust-analyzer/xtask/src/dist.rs b/src/tools/rust-analyzer/xtask/src/dist.rs
index 5a03c71b28a..7e54d19fe4d 100644
--- a/src/tools/rust-analyzer/xtask/src/dist.rs
+++ b/src/tools/rust-analyzer/xtask/src/dist.rs
@@ -34,7 +34,7 @@ impl flags::Dist {
                 format!("{VERSION_NIGHTLY}.{patch_version}")
             };
             dist_server(sh, &format!("{version}-standalone"), &target)?;
-            let release_tag = if stable { date_iso(sh)? } else { "nightly".to_string() };
+            let release_tag = if stable { date_iso(sh)? } else { "nightly".to_owned() };
             dist_client(sh, &version, &release_tag, &target)?;
         } else {
             dist_server(sh, "0.0.0-standalone", &target)?;
@@ -155,11 +155,11 @@ impl Target {
             Ok(target) => target,
             _ => {
                 if cfg!(target_os = "linux") {
-                    "x86_64-unknown-linux-gnu".to_string()
+                    "x86_64-unknown-linux-gnu".to_owned()
                 } else if cfg!(target_os = "windows") {
-                    "x86_64-pc-windows-msvc".to_string()
+                    "x86_64-pc-windows-msvc".to_owned()
                 } else if cfg!(target_os = "macos") {
-                    "x86_64-apple-darwin".to_string()
+                    "x86_64-apple-darwin".to_owned()
                 } else {
                     panic!("Unsupported OS, maybe try setting RA_TARGET")
                 }
diff --git a/src/tools/rust-analyzer/xtask/src/flags.rs b/src/tools/rust-analyzer/xtask/src/flags.rs
index 092ab8c593c..99bb12896f1 100644
--- a/src/tools/rust-analyzer/xtask/src/flags.rs
+++ b/src/tools/rust-analyzer/xtask/src/flags.rs
@@ -129,7 +129,7 @@ impl FromStr for MeasurementType {
             "webrender-2022" => Ok(Self::AnalyzeWebRender),
             "diesel-1.4.8" => Ok(Self::AnalyzeDiesel),
             "hyper-0.14.18" => Ok(Self::AnalyzeHyper),
-            _ => Err("Invalid option".to_string()),
+            _ => Err("Invalid option".to_owned()),
         }
     }
 }
diff --git a/src/tools/rust-analyzer/xtask/src/install.rs b/src/tools/rust-analyzer/xtask/src/install.rs
index e8c00c72e07..dadee204d1a 100644
--- a/src/tools/rust-analyzer/xtask/src/install.rs
+++ b/src/tools/rust-analyzer/xtask/src/install.rs
@@ -50,7 +50,7 @@ fn fix_path_for_mac(sh: &Shell) -> anyhow::Result<()> {
 
         [ROOT_DIR, &home_dir]
             .into_iter()
-            .map(|dir| dir.to_string() + COMMON_APP_PATH)
+            .map(|dir| dir.to_owned() + COMMON_APP_PATH)
             .map(PathBuf::from)
             .filter(|path| path.exists())
             .collect()
diff --git a/src/tools/rust-analyzer/xtask/src/main.rs b/src/tools/rust-analyzer/xtask/src/main.rs
index 2d40ceb737d..df4d9810e6f 100644
--- a/src/tools/rust-analyzer/xtask/src/main.rs
+++ b/src/tools/rust-analyzer/xtask/src/main.rs
@@ -9,6 +9,7 @@
 //! `.cargo/config`.
 
 #![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(clippy::print_stderr, clippy::print_stdout)]
 
 mod flags;
 
diff --git a/src/tools/rust-analyzer/xtask/src/metrics.rs b/src/tools/rust-analyzer/xtask/src/metrics.rs
index c05874a0cca..9bd3a661c24 100644
--- a/src/tools/rust-analyzer/xtask/src/metrics.rs
+++ b/src/tools/rust-analyzer/xtask/src/metrics.rs
@@ -194,12 +194,12 @@ impl Host {
             bail!("can only collect metrics on Linux ");
         }
 
-        let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
+        let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_owned();
 
         let cpu = read_field(sh, "/proc/cpuinfo", "model name")?
             .trim_start_matches(':')
             .trim()
-            .to_string();
+            .to_owned();
 
         let mem = read_field(sh, "/proc/meminfo", "MemTotal:")?;
 
@@ -210,7 +210,7 @@ impl Host {
 
             text.lines()
                 .find_map(|it| it.strip_prefix(field))
-                .map(|it| it.trim().to_string())
+                .map(|it| it.trim().to_owned())
                 .ok_or_else(|| format_err!("can't parse {}", path))
         }
     }
diff --git a/src/tools/rust-analyzer/xtask/src/release/changelog.rs b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
index 817863336dd..086a4d463ea 100644
--- a/src/tools/rust-analyzer/xtask/src/release/changelog.rs
+++ b/src/tools/rust-analyzer/xtask/src/release/changelog.rs
@@ -183,5 +183,5 @@ fn parse_title_line(s: &str) -> PrInfo {
             return PrInfo { message, kind };
         }
     }
-    PrInfo { kind: PrKind::Other, message: Some(s.to_string()) }
+    PrInfo { kind: PrKind::Other, message: Some(s.to_owned()) }
 }
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index b9cf2617ba9..a380a20b1ac 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -9,6 +9,6 @@ clap = "4.0.32"
 env_logger = "0.10"
 
 [dependencies.mdbook]
-version = "0.4.28"
+version = "0.4.37"
 default-features = false
 features = ["search"]
diff --git a/src/tools/suggest-tests/src/dynamic_suggestions.rs b/src/tools/suggest-tests/src/dynamic_suggestions.rs
index 2b0213cdc22..f09720f1c91 100644
--- a/src/tools/suggest-tests/src/dynamic_suggestions.rs
+++ b/src/tools/suggest-tests/src/dynamic_suggestions.rs
@@ -4,20 +4,29 @@ use crate::Suggestion;
 
 type DynamicSuggestion = fn(&Path) -> Vec<Suggestion>;
 
-pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[|path: &Path| -> Vec<Suggestion> {
-    if path.starts_with("compiler/") || path.starts_with("library/") {
-        let path = path.components().take(2).collect::<Vec<_>>();
+pub(crate) const DYNAMIC_SUGGESTIONS: &[DynamicSuggestion] = &[
+    |path: &Path| -> Vec<Suggestion> {
+        if path.starts_with("compiler/") || path.starts_with("library/") {
+            let path = path.components().take(2).collect::<Vec<_>>();
 
-        vec![Suggestion::with_single_path(
-            "test",
-            None,
-            &format!(
-                "{}/{}",
-                path[0].as_os_str().to_str().unwrap(),
-                path[1].as_os_str().to_str().unwrap()
-            ),
-        )]
-    } else {
-        Vec::new()
-    }
-}];
+            vec![Suggestion::with_single_path(
+                "test",
+                None,
+                &format!(
+                    "{}/{}",
+                    path[0].as_os_str().to_str().unwrap(),
+                    path[1].as_os_str().to_str().unwrap()
+                ),
+            )]
+        } else {
+            Vec::new()
+        }
+    },
+    |path: &Path| -> Vec<Suggestion> {
+        if path.starts_with("compiler/rustc_pattern_analysis") {
+            vec![Suggestion::new("test", None, &["tests/ui", "--test-args", "pattern"])]
+        } else {
+            Vec::new()
+        }
+    },
+];
diff --git a/tests/codegen/comparison-operators-2-tuple.rs b/tests/codegen/comparison-operators-2-tuple.rs
index 7a2a3fc93f8..633cfe3a8ac 100644
--- a/tests/codegen/comparison-operators-2-tuple.rs
+++ b/tests/codegen/comparison-operators-2-tuple.rs
@@ -10,8 +10,10 @@ type TwoTuple = (i16, u16);
 //
 // The operators are all overridden directly, so should optimize easily.
 //
-// Yes, the `s[lg]t` is correct for the `[lg]e` version because it's only used
-// in the side of the select where we know the values are *not* equal.
+// slt-vs-sle and sgt-vs-sge don't matter because they're only used in the side
+// of the select where we know the values are not equal, and thus the tests
+// use a regex to allow either, since unimportant changes to the implementation
+// sometimes result in changing what LLVM decides to emit for this.
 //
 
 // CHECK-LABEL: @check_lt_direct
@@ -19,7 +21,7 @@ type TwoTuple = (i16, u16);
 #[no_mangle]
 pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool {
     // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
-    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]]
     // CHECK-DAG: %[[CMP1:.+]] = icmp ult i16 %[[A1]], %[[B1]]
     // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
     // CHECK: ret i1 %[[R]]
@@ -31,7 +33,7 @@ pub fn check_lt_direct(a: TwoTuple, b: TwoTuple) -> bool {
 #[no_mangle]
 pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool {
     // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
-    // CHECK-DAG: %[[CMP0:.+]] = icmp slt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{slt|sle}} i16 %[[A0]], %[[B0]]
     // CHECK-DAG: %[[CMP1:.+]] = icmp ule i16 %[[A1]], %[[B1]]
     // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
     // CHECK: ret i1 %[[R]]
@@ -43,7 +45,7 @@ pub fn check_le_direct(a: TwoTuple, b: TwoTuple) -> bool {
 #[no_mangle]
 pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool {
     // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
-    // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]]
     // CHECK-DAG: %[[CMP1:.+]] = icmp ugt i16 %[[A1]], %[[B1]]
     // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
     // CHECK: ret i1 %[[R]]
@@ -55,7 +57,7 @@ pub fn check_gt_direct(a: TwoTuple, b: TwoTuple) -> bool {
 #[no_mangle]
 pub fn check_ge_direct(a: TwoTuple, b: TwoTuple) -> bool {
     // CHECK-DAG: %[[EQ:.+]] = icmp eq i16 %[[A0]], %[[B0]]
-    // CHECK-DAG: %[[CMP0:.+]] = icmp sgt i16 %[[A0]], %[[B0]]
+    // CHECK-DAG: %[[CMP0:.+]] = icmp {{sgt|sge}} i16 %[[A0]], %[[B0]]
     // CHECK-DAG: %[[CMP1:.+]] = icmp uge i16 %[[A1]], %[[B1]]
     // CHECK: %[[R:.+]] = select i1 %[[EQ]], i1 %[[CMP1]], i1 %[[CMP0]]
     // CHECK: ret i1 %[[R]]
diff --git a/tests/incremental/delayed_span_bug.rs b/tests/incremental/delayed_span_bug.rs
index cc9831fff96..5c9d3c2c1d5 100644
--- a/tests/incremental/delayed_span_bug.rs
+++ b/tests/incremental/delayed_span_bug.rs
@@ -1,8 +1,8 @@
 // revisions: cfail1 cfail2
 // should-ice
-// error-pattern: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
+// error-pattern: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
 
 #![feature(rustc_attrs)]
 
-#[rustc_error(span_delayed_bug_from_inside_query)]
+#[rustc_error(delayed_bug_from_inside_query)]
 fn main() {}
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
index 7df4eb49260..21a9f6f8721 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-abort.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
 
-fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
     let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
 
     bb0: {
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
index 7df4eb49260..21a9f6f8721 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.panic-unwind.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move
 
-fn main::{closure#0}::{closure#0}(_1: {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
     let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
 
     bb0: {
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir
index 517b8d0dd88..1cfb6c2f3ea 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-abort.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
 
-fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+fn main::{closure#0}::{closure#0}(_1: &mut {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
     debug a => _2;
     debug b => ((*_1).0: i32);
     let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
diff --git a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir
index 517b8d0dd88..1cfb6c2f3ea 100644
--- a/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir
+++ b/tests/mir-opt/async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.panic-unwind.mir
@@ -1,6 +1,6 @@
 // MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
 
-fn main::{closure#0}::{closure#0}(_1: &mut {coroutine-closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
+fn main::{closure#0}::{closure#0}(_1: &mut {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
     debug a => _2;
     debug b => ((*_1).0: i32);
     let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
diff --git a/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs b/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs
new file mode 100644
index 00000000000..45e04a70c09
--- /dev/null
+++ b/tests/rustdoc-ui/normalize-in-inlined-type-alias.rs
@@ -0,0 +1,14 @@
+// check-pass
+// compile-flags: -Znormalize-docs
+
+trait Woo<T> {
+    type Assoc;
+}
+
+impl<T> Woo<T> for () {
+    type Assoc = ();
+}
+
+type Alias<P> = <() as Woo<P>>::Assoc;
+
+pub fn hello<S>() -> Alias<S> {}
diff --git a/tests/ui/async-await/async-closures/auxiliary/foreign.rs b/tests/ui/async-await/async-closures/auxiliary/foreign.rs
new file mode 100644
index 00000000000..e11dfc22213
--- /dev/null
+++ b/tests/ui/async-await/async-closures/auxiliary/foreign.rs
@@ -0,0 +1,7 @@
+// edition:2021
+
+#![feature(async_closure)]
+
+pub fn closure() -> impl async Fn() {
+    async || { /* Don't really need to do anything here. */ }
+}
diff --git a/tests/ui/async-await/async-closures/foreign.rs b/tests/ui/async-await/async-closures/foreign.rs
new file mode 100644
index 00000000000..60fea909801
--- /dev/null
+++ b/tests/ui/async-await/async-closures/foreign.rs
@@ -0,0 +1,19 @@
+// aux-build:block-on.rs
+// aux-build:foreign.rs
+// edition:2021
+// build-pass
+
+#![feature(async_closure)]
+
+use std::future::Future;
+
+extern crate block_on;
+extern crate foreign;
+
+struct NoCopy;
+
+fn main() {
+    block_on::block_on(async {
+        foreign::closure()().await;
+    });
+}
diff --git a/tests/ui/async-await/async-closures/is-not-fn.rs b/tests/ui/async-await/async-closures/is-not-fn.rs
index 40b0febbf06..81666cada31 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.rs
+++ b/tests/ui/async-await/async-closures/is-not-fn.rs
@@ -5,5 +5,5 @@
 fn main() {
     fn needs_fn(x: impl FnOnce()) {}
     needs_fn(async || {});
-    //~^ ERROR expected `{coroutine-closure@is-not-fn.rs:7:14}` to be a closure that returns `()`
+    //~^ ERROR expected `{async closure@is-not-fn.rs:7:14}` to be a closure that returns `()`
 }
diff --git a/tests/ui/async-await/async-closures/is-not-fn.stderr b/tests/ui/async-await/async-closures/is-not-fn.stderr
index 6169cee85fd..130746ece67 100644
--- a/tests/ui/async-await/async-closures/is-not-fn.stderr
+++ b/tests/ui/async-await/async-closures/is-not-fn.stderr
@@ -1,4 +1,4 @@
-error[E0271]: expected `{coroutine-closure@is-not-fn.rs:7:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:7:23: 7:25}`
+error[E0271]: expected `{async closure@is-not-fn.rs:7:14}` to be a closure that returns `()`, but it returns `{async closure body@$DIR/is-not-fn.rs:7:23: 7:25}`
   --> $DIR/is-not-fn.rs:7:14
    |
 LL |     needs_fn(async || {});
diff --git a/tests/ui/async-await/async-closures/move-consuming-capture.stderr b/tests/ui/async-await/async-closures/move-consuming-capture.stderr
index 2c2a0d1162d..45c1eac8f8f 100644
--- a/tests/ui/async-await/async-closures/move-consuming-capture.stderr
+++ b/tests/ui/async-await/async-closures/move-consuming-capture.stderr
@@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x`
   --> $DIR/move-consuming-capture.rs:17:9
    |
 LL |         let x = async move || {
-   |             - move occurs because `x` has type `{coroutine-closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait
+   |             - move occurs because `x` has type `{async closure@$DIR/move-consuming-capture.rs:13:17: 13:30}`, which does not implement the `Copy` trait
 ...
 LL |         x().await;
    |         --- `x` moved due to this method call
diff --git a/tests/ui/coercion/type-errors.rs b/tests/ui/coercion/type-errors.rs
new file mode 100644
index 00000000000..a2f0e55f1b9
--- /dev/null
+++ b/tests/ui/coercion/type-errors.rs
@@ -0,0 +1,15 @@
+// Regression test for an ICE: https://github.com/rust-lang/rust/issues/120884
+// We still need to properly go through coercions between types with errors instead of
+// shortcutting and returning success, because we need the adjustments for building the MIR.
+
+pub fn has_error() -> TypeError {}
+//~^ ERROR cannot find type `TypeError` in this scope
+
+pub fn cast() -> *const u8 {
+    // Casting a function item to a data pointer in valid in HIR, but invalid in MIR.
+    // We need an adjustment (ReifyFnPointer) to insert a cast from the function item
+    // to a function pointer as a separate MIR statement.
+    has_error as *const u8
+}
+
+fn main() {}
diff --git a/tests/ui/coercion/type-errors.stderr b/tests/ui/coercion/type-errors.stderr
new file mode 100644
index 00000000000..489cd9ddf13
--- /dev/null
+++ b/tests/ui/coercion/type-errors.stderr
@@ -0,0 +1,9 @@
+error[E0412]: cannot find type `TypeError` in this scope
+  --> $DIR/type-errors.rs:5:23
+   |
+LL | pub fn has_error() -> TypeError {}
+   |                       ^^^^^^^^^ not found in this scope
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/coherence/coherence-impls-copy.stderr b/tests/ui/coherence/coherence-impls-copy.stderr
index 21dbc606321..2d2c5064043 100644
--- a/tests/ui/coherence/coherence-impls-copy.stderr
+++ b/tests/ui/coherence/coherence-impls-copy.stderr
@@ -30,6 +30,12 @@ LL | impl Copy for &'static [NotSync] {}
    |
    = note: define and implement a trait or new type instead
 
+error[E0206]: the trait `Copy` cannot be implemented for this type
+  --> $DIR/coherence-impls-copy.rs:21:15
+   |
+LL | impl Copy for &'static mut MyType {}
+   |               ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/coherence-impls-copy.rs:25:1
    |
@@ -41,6 +47,12 @@ LL | impl Copy for (MyType, MyType) {}
    |
    = note: define and implement a trait or new type instead
 
+error[E0206]: the trait `Copy` cannot be implemented for this type
+  --> $DIR/coherence-impls-copy.rs:25:15
+   |
+LL | impl Copy for (MyType, MyType) {}
+   |               ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
+
 error[E0117]: only traits defined in the current crate can be implemented for arbitrary types
   --> $DIR/coherence-impls-copy.rs:30:1
    |
@@ -53,18 +65,6 @@ LL | impl Copy for [MyType] {}
    = note: define and implement a trait or new type instead
 
 error[E0206]: the trait `Copy` cannot be implemented for this type
-  --> $DIR/coherence-impls-copy.rs:21:15
-   |
-LL | impl Copy for &'static mut MyType {}
-   |               ^^^^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` cannot be implemented for this type
-  --> $DIR/coherence-impls-copy.rs:25:15
-   |
-LL | impl Copy for (MyType, MyType) {}
-   |               ^^^^^^^^^^^^^^^^ type is not a structure or enumeration
-
-error[E0206]: the trait `Copy` cannot be implemented for this type
   --> $DIR/coherence-impls-copy.rs:30:15
    |
 LL | impl Copy for [MyType] {}
diff --git a/tests/ui/consts/cycle-static-promoted.rs b/tests/ui/consts/cycle-static-promoted.rs
new file mode 100644
index 00000000000..5838dc58a3a
--- /dev/null
+++ b/tests/ui/consts/cycle-static-promoted.rs
@@ -0,0 +1,12 @@
+// check-pass
+
+struct Value {
+    values: &'static [&'static Value],
+}
+
+// This `static` recursively points to itself through a promoted (the slice).
+static VALUE: Value = Value {
+    values: &[&VALUE],
+};
+
+fn main() {}
diff --git a/tests/ui/consts/issue-17718-const-bad-values.rs b/tests/ui/consts/issue-17718-const-bad-values.rs
index af50fed972d..2b593a192ee 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.rs
+++ b/tests/ui/consts/issue-17718-const-bad-values.rs
@@ -4,7 +4,6 @@ const C1: &'static mut [usize] = &mut [];
 static mut S: usize = 3;
 const C2: &'static mut usize = unsafe { &mut S };
 //~^ ERROR: referencing statics in constants
-//~| ERROR: referencing statics in constants
 //~| WARN mutable reference of mutable static is discouraged [static_mut_ref]
 
 fn main() {}
diff --git a/tests/ui/consts/issue-17718-const-bad-values.stderr b/tests/ui/consts/issue-17718-const-bad-values.stderr
index cda94490155..92bab1ab53e 100644
--- a/tests/ui/consts/issue-17718-const-bad-values.stderr
+++ b/tests/ui/consts/issue-17718-const-bad-values.stderr
@@ -31,20 +31,7 @@ LL | const C2: &'static mut usize = unsafe { &mut S };
    = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
    = help: to fix this, the value can be extracted to a `const` and then used.
 
-error[E0658]: referencing statics in constants is unstable
-  --> $DIR/issue-17718-const-bad-values.rs:5:46
-   |
-LL | const C2: &'static mut usize = unsafe { &mut S };
-   |                                              ^
-   |
-   = note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
-   = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
-   = help: to fix this, the value can be extracted to a `const` and then used.
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors; 1 warning emitted
+error: aborting due to 2 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0658, E0764.
 For more information about an error, try `rustc --explain E0658`.
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
index 35b9ed6735e..9e76b873858 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.32bit.stderr
@@ -50,11 +50,6 @@ help: skipping check for `const_refs_to_static` feature
 LL | const READ_MUT: u32 = unsafe { MUTABLE };
    |                                ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static.rs:18:32
-   |
-LL | const READ_MUT: u32 = unsafe { MUTABLE };
-   |                                ^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/const_refers_to_static.rs:24:18
    |
 LL |     unsafe { &*(&FOO as *const _ as *const usize) }
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
index 8511673b684..989d3c75cd6 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static.64bit.stderr
@@ -50,11 +50,6 @@ help: skipping check for `const_refs_to_static` feature
 LL | const READ_MUT: u32 = unsafe { MUTABLE };
    |                                ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static.rs:18:32
-   |
-LL | const READ_MUT: u32 = unsafe { MUTABLE };
-   |                                ^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/const_refers_to_static.rs:24:18
    |
 LL |     unsafe { &*(&FOO as *const _ as *const usize) }
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
index a2c9034c831..e280fe622ec 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.32bit.stderr
@@ -84,21 +84,6 @@ help: skipping check for `const_refs_to_static` feature
 LL |     unsafe { &static_cross_crate::ZERO }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:12:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:18:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO[0] }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:18:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO[0] }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/const_refers_to_static_cross_crate.rs:18:15
    |
 LL |     unsafe { &static_cross_crate::ZERO[0] }
@@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature
    |
 LL |         match static_cross_crate::OPT_ZERO {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 8 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
index 2b44a8b12fa..9bca60485c0 100644
--- a/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/const_refers_to_static_cross_crate.64bit.stderr
@@ -84,21 +84,6 @@ help: skipping check for `const_refs_to_static` feature
 LL |     unsafe { &static_cross_crate::ZERO }
    |               ^^^^^^^^^^^^^^^^^^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:12:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:18:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO[0] }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:18:15
-   |
-LL |     unsafe { &static_cross_crate::ZERO[0] }
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/const_refers_to_static_cross_crate.rs:18:15
    |
 LL |     unsafe { &static_cross_crate::ZERO[0] }
@@ -113,26 +98,6 @@ help: skipping check for `const_refs_to_static` feature
    |
 LL |         match static_cross_crate::OPT_ZERO {
    |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/const_refers_to_static_cross_crate.rs:28:15
-   |
-LL |         match static_cross_crate::OPT_ZERO {
-   |               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 error: aborting due to 8 previous errors; 2 warnings emitted
 
diff --git a/tests/ui/consts/miri_unleashed/extern-static.rs b/tests/ui/consts/miri_unleashed/extern-static.rs
new file mode 100644
index 00000000000..81176b3d4e9
--- /dev/null
+++ b/tests/ui/consts/miri_unleashed/extern-static.rs
@@ -0,0 +1,24 @@
+// compile-flags: -Zunleash-the-miri-inside-of-you
+#![feature(thread_local)]
+#![allow(static_mut_ref)]
+
+extern "C" {
+    static mut DATA: u8;
+}
+
+// Make sure we catch accessing extern static.
+static TEST_READ: () = {
+    unsafe { let _val = DATA; }
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE cannot access extern static
+};
+static TEST_WRITE: () = {
+    unsafe { DATA = 0; }
+    //~^ ERROR could not evaluate static initializer
+    //~| NOTE cannot access extern static
+};
+
+// Just creating a reference is fine, as long as we are not reading or writing.
+static TEST_REF: &u8 = unsafe { &DATA };
+
+fn main() {}
diff --git a/tests/ui/consts/miri_unleashed/extern-static.stderr b/tests/ui/consts/miri_unleashed/extern-static.stderr
new file mode 100644
index 00000000000..0979a5e4fb1
--- /dev/null
+++ b/tests/ui/consts/miri_unleashed/extern-static.stderr
@@ -0,0 +1,15 @@
+error[E0080]: could not evaluate static initializer
+  --> $DIR/extern-static.rs:11:25
+   |
+LL |     unsafe { let _val = DATA; }
+   |                         ^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA))
+
+error[E0080]: could not evaluate static initializer
+  --> $DIR/extern-static.rs:16:14
+   |
+LL |     unsafe { DATA = 0; }
+   |              ^^^^^^^^ cannot access extern static (DefId(0:4 ~ extern_static[c41e]::{extern#0}::DATA))
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0080`.
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
index b60f9a24f8c..401cf46710a 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.32bit.stderr
@@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                        ^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:32:40
-   |
-LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
-   |                                        ^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:32:35
    |
@@ -145,16 +140,6 @@ help: skipping check for `const_refs_to_static` feature
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:47:44
-   |
-LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
-   |                                            ^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:51:45
-   |
-LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
-   |                                             ^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/mutable_references_err.rs:51:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
diff --git a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
index 1e5d4bd890b..0eb01f5b773 100644
--- a/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
+++ b/tests/ui/consts/miri_unleashed/mutable_references_err.64bit.stderr
@@ -114,11 +114,6 @@ help: skipping check for `const_refs_to_static` feature
    |
 LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
    |                                        ^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:32:40
-   |
-LL | const SUBTLE: &mut i32 = unsafe { &mut FOO };
-   |                                        ^^^
 help: skipping check that does not even have a feature gate
   --> $DIR/mutable_references_err.rs:32:35
    |
@@ -145,16 +140,6 @@ help: skipping check for `const_refs_to_static` feature
 LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
    |                                            ^^^^^^^
 help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:47:44
-   |
-LL | const POINTS_TO_MUTABLE1: &i32 = unsafe { &MUTABLE };
-   |                                            ^^^^^^^
-help: skipping check for `const_refs_to_static` feature
-  --> $DIR/mutable_references_err.rs:51:45
-   |
-LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
-   |                                             ^^^^^^^^^^^
-help: skipping check for `const_refs_to_static` feature
   --> $DIR/mutable_references_err.rs:51:45
    |
 LL | const POINTS_TO_MUTABLE2: &i32 = unsafe { &*MUTABLE_REF };
diff --git a/tests/ui/consts/miri_unleashed/tls.rs b/tests/ui/consts/miri_unleashed/tls.rs
index d06d7cf19f7..7319a5135d3 100644
--- a/tests/ui/consts/miri_unleashed/tls.rs
+++ b/tests/ui/consts/miri_unleashed/tls.rs
@@ -14,6 +14,8 @@ static TEST_BAD: () = {
 };
 
 // Make sure we catch taking a reference to thread-local storage.
+// The actual pointer depends on the thread, so even just taking a reference already does not make
+// sense at compile-time.
 static TEST_BAD_REF: () = {
     unsafe { let _val = &A; }
     //~^ ERROR could not evaluate static initializer
diff --git a/tests/ui/consts/miri_unleashed/tls.stderr b/tests/ui/consts/miri_unleashed/tls.stderr
index ec24527d6c0..a00b7eb1312 100644
--- a/tests/ui/consts/miri_unleashed/tls.stderr
+++ b/tests/ui/consts/miri_unleashed/tls.stderr
@@ -5,7 +5,7 @@ LL |     unsafe { let _val = A; }
    |                         ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
 
 error[E0080]: could not evaluate static initializer
-  --> $DIR/tls.rs:18:26
+  --> $DIR/tls.rs:20:26
    |
 LL |     unsafe { let _val = &A; }
    |                          ^ cannot access thread local static (DefId(0:4 ~ tls[ca29]::A))
@@ -18,7 +18,7 @@ help: skipping check that does not even have a feature gate
 LL |     unsafe { let _val = A; }
    |                         ^
 help: skipping check that does not even have a feature gate
-  --> $DIR/tls.rs:18:26
+  --> $DIR/tls.rs:20:26
    |
 LL |     unsafe { let _val = &A; }
    |                          ^
diff --git a/tests/ui/error-codes/E0401.rs b/tests/ui/error-codes/E0401.rs
index 8f8d6b87ef2..a120198b728 100644
--- a/tests/ui/error-codes/E0401.rs
+++ b/tests/ui/error-codes/E0401.rs
@@ -9,8 +9,6 @@ fn foo<T>(x: T) {
            (y: T) { //~ ERROR E0401
     }
     bfnr(x);
-    //~^ ERROR type annotations needed
-    //~| ERROR type annotations needed
 }
 
 
diff --git a/tests/ui/error-codes/E0401.stderr b/tests/ui/error-codes/E0401.stderr
index 754867061c7..5d6878620c8 100644
--- a/tests/ui/error-codes/E0401.stderr
+++ b/tests/ui/error-codes/E0401.stderr
@@ -21,7 +21,7 @@ LL |            (y: T) {
    |                ^ use of generic parameter from outer item
 
 error[E0401]: can't use `Self` from outer item
-  --> $DIR/E0401.rs:24:25
+  --> $DIR/E0401.rs:22:25
    |
 LL | impl<T> Iterator for A<T> {
    | ---- `Self` type implicitly declared here, by this `impl`
@@ -32,45 +32,6 @@ LL |         fn helper(sel: &Self) -> u8 {
    |                         use of `Self` from outer item
    |                         refer to the type directly here instead
 
-error[E0283]: type annotations needed
-  --> $DIR/E0401.rs:11:5
-   |
-LL |     bfnr(x);
-   |     ^^^^ cannot infer type of the type parameter `V` declared on the function `bfnr`
-   |
-   = note: cannot satisfy `_: Baz<_>`
-note: required by a bound in `bfnr`
-  --> $DIR/E0401.rs:4:19
-   |
-LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |                   ^^^^^^ required by this bound in `bfnr`
-help: consider specifying the generic arguments
-   |
-LL |     bfnr::<U, V, W>(x);
-   |         +++++++++++
-
-error[E0283]: type annotations needed
-  --> $DIR/E0401.rs:11:5
-   |
-LL |     bfnr(x);
-   |     ^^^^ cannot infer type of the type parameter `W` declared on the function `bfnr`
-   |
-   = note: multiple `impl`s satisfying `_: Fn()` found in the following crates: `alloc`, `core`:
-           - impl<A, F> Fn<A> for &F
-             where A: Tuple, F: Fn<A>, F: ?Sized;
-           - impl<Args, F, A> Fn<Args> for Box<F, A>
-             where Args: Tuple, F: Fn<Args>, A: Allocator, F: ?Sized;
-note: required by a bound in `bfnr`
-  --> $DIR/E0401.rs:4:30
-   |
-LL |     fn bfnr<U, V: Baz<U>, W: Fn()>(y: T) {
-   |                              ^^^^ required by this bound in `bfnr`
-help: consider specifying the generic arguments
-   |
-LL |     bfnr::<U, V, W>(x);
-   |         +++++++++++
-
-error: aborting due to 5 previous errors
+error: aborting due to 3 previous errors
 
-Some errors have detailed explanations: E0283, E0401.
-For more information about an error, try `rustc --explain E0283`.
+For more information about this error, try `rustc --explain E0401`.
diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs b/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs
index c020bb37a99..008b754dc6c 100644
--- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs
+++ b/tests/ui/feature-gates/feature-gate-const-refs-to-static.rs
@@ -6,7 +6,6 @@ const C1_READ: () = {
     assert!(*C1 == 0);
 };
 const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) }; //~ERROR:  referencing statics in constants is unstable
-//~^ERROR:  referencing statics in constants is unstable
 
 fn main() {
 }
diff --git a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr b/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr
index f94cff5b550..5af48471250 100644
--- a/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr
+++ b/tests/ui/feature-gates/feature-gate-const-refs-to-static.stderr
@@ -22,19 +22,6 @@ LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
    = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
    = help: to fix this, the value can be extracted to a `const` and then used.
 
-error[E0658]: referencing statics in constants is unstable
-  --> $DIR/feature-gate-const-refs-to-static.rs:8:52
-   |
-LL | const C2: *const i32 = unsafe { std::ptr::addr_of!(S_MUT) };
-   |                                                    ^^^^^
-   |
-   = note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
-   = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
-   = help: to fix this, the value can be extracted to a `const` and then used.
-   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
-
-error: aborting due to 3 previous errors
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0658`.
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
new file mode 100644
index 00000000000..229a918cdd2
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.rs
@@ -0,0 +1,19 @@
+// compile-flags: -Znext-solver
+
+#![feature(lazy_type_alias)]
+//~^ WARN the feature `lazy_type_alias` is incomplete
+
+trait Foo {}
+
+type A<T: Foo> = T;
+
+struct W<T>(T);
+
+// For `W<A<usize>>` to be WF, `A<usize>: Sized` must hold. However, when assembling
+// alias bounds for `A<usize>`, we try to normalize it, but it doesn't hold because
+// `usize: Foo` doesn't hold. Therefore we ICE, because we don't expect to still
+// encounter weak types in `assemble_alias_bound_candidates_recur`.
+fn hello(_: W<A<usize>>) {}
+//~^ ERROR the type `W<A<usize>>` is not well-formed
+
+fn main() {}
diff --git a/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
new file mode 100644
index 00000000000..5df27ac3bc6
--- /dev/null
+++ b/tests/ui/impl-trait/in-trait/alias-bounds-when-not-wf.stderr
@@ -0,0 +1,17 @@
+warning: the feature `lazy_type_alias` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/alias-bounds-when-not-wf.rs:3:12
+   |
+LL | #![feature(lazy_type_alias)]
+   |            ^^^^^^^^^^^^^^^
+   |
+   = note: see issue #112792 <https://github.com/rust-lang/rust/issues/112792> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error: the type `W<A<usize>>` is not well-formed
+  --> $DIR/alias-bounds-when-not-wf.rs:16:13
+   |
+LL | fn hello(_: W<A<usize>>) {}
+   |             ^^^^^^^^^^^
+
+error: aborting due to 1 previous error; 1 warning emitted
+
diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs b/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
deleted file mode 100644
index 33113642023..00000000000
--- a/tests/ui/lint/large_assignments/box_rc_arc_allowed.rs
+++ /dev/null
@@ -1,29 +0,0 @@
-#![deny(large_assignments)]
-#![feature(large_assignments)]
-#![move_size_limit = "1000"]
-// build-fail
-// only-x86_64
-
-// edition:2018
-// compile-flags: -Zmir-opt-level=0
-
-use std::{sync::Arc, rc::Rc};
-
-fn main() {
-    let _ = Arc::new([0; 9999]); // OK!
-    let _ = Box::new([0; 9999]); // OK!
-    let _ = Rc::new([0; 9999]); // OK!
-    let _ = NotBox::new([0; 9999]); //~ ERROR large_assignments
-}
-
-struct NotBox {
-    data: [u8; 9999],
-}
-
-impl NotBox {
-    fn new(data: [u8; 9999]) -> Self {
-        Self {
-            data, //~ ERROR large_assignments
-        }
-    }
-}
diff --git a/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs
new file mode 100644
index 00000000000..866a4d10ff5
--- /dev/null
+++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.rs
@@ -0,0 +1,38 @@
+#![deny(large_assignments)]
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+// build-fail
+// only-64bit
+
+// edition:2018
+// compile-flags: -Zmir-opt-level=1
+
+use std::{sync::Arc, rc::Rc};
+
+fn main() {
+    let data = [0; 9999];
+
+    // Looking at --emit mir, we can see that all parameters below are passed by
+    // copy. But it requires at least mir-opt-level=1.
+    let _ = Arc::new(data); // OK!
+    let _ = Box::new(data); // OK!
+    let _ = Rc::new(data); // OK!
+
+    // Looking at --emit llvm-ir, we can see that a memcpy is involved in the
+    // parameter passing. So we want the lint to trigger here.
+    let _ = NotBox::new(data); //~ ERROR large_assignments
+}
+
+struct NotBox {
+    data: [u8; 9999],
+}
+
+impl NotBox {
+    fn new(data: [u8; 9999]) -> Self {
+        // Looking at --emit llvm-ir, we can see that a memcpy is involved.
+        // So we want the lint to trigger here.
+        Self { //~ ERROR large_assignments
+            data,
+        }
+    }
+}
diff --git a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr
index fefb3a9621b..6e42328a111 100644
--- a/tests/ui/lint/large_assignments/box_rc_arc_allowed.stderr
+++ b/tests/ui/lint/large_assignments/copy_into_box_rc_arc.stderr
@@ -1,21 +1,23 @@
 error: moving 9999 bytes
-  --> $DIR/box_rc_arc_allowed.rs:16:25
+  --> $DIR/copy_into_box_rc_arc.rs:23:25
    |
-LL |     let _ = NotBox::new([0; 9999]);
-   |                         ^^^^^^^^^ value moved from here
+LL |     let _ = NotBox::new(data);
+   |                         ^^^^ value moved from here
    |
    = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
 note: the lint level is defined here
-  --> $DIR/box_rc_arc_allowed.rs:1:9
+  --> $DIR/copy_into_box_rc_arc.rs:1:9
    |
 LL | #![deny(large_assignments)]
    |         ^^^^^^^^^^^^^^^^^
 
 error: moving 9999 bytes
-  --> $DIR/box_rc_arc_allowed.rs:26:13
+  --> $DIR/copy_into_box_rc_arc.rs:34:9
    |
-LL |             data,
-   |             ^^^^ value moved from here
+LL | /         Self {
+LL | |             data,
+LL | |         }
+   | |_________^ value moved from here
    |
    = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
 
diff --git a/tests/ui/lint/large_assignments/large_future.rs b/tests/ui/lint/large_assignments/large_future.rs
index 834746fa97e..a69ff356c6b 100644
--- a/tests/ui/lint/large_assignments/large_future.rs
+++ b/tests/ui/lint/large_assignments/large_future.rs
@@ -2,7 +2,7 @@
 #![cfg_attr(attribute, feature(large_assignments))]
 #![cfg_attr(attribute, move_size_limit = "1000")]
 // build-fail
-// only-x86_64
+// only-64bit
 // revisions: attribute option
 // [option]compile-flags: -Zmove-size-limit=1000
 
diff --git a/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs b/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs
new file mode 100644
index 00000000000..b7a70dfdda0
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_box_rc_arc.rs
@@ -0,0 +1,38 @@
+#![deny(large_assignments)]
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+// build-fail
+// only-64bit
+
+// edition:2018
+// compile-flags: -Zmir-opt-level=0
+
+use std::{sync::Arc, rc::Rc};
+
+fn main() {
+    // Looking at --emit mir, we can see that all parameters below are passed
+    // by move.
+    let _ = Arc::new([0; 9999]); // OK!
+    let _ = Box::new([0; 9999]); // OK!
+    let _ = Rc::new([0; 9999]); // OK!
+
+    // Looking at --emit llvm-ir, we can see that no memcpy is involved in the
+    // parameter passing. Instead, a pointer is passed. This is typically what
+    // we get when moving parameter into functions. So we don't want the lint to
+    // trigger here.
+    let _ = NotBox::new([0; 9999]); // OK (compare with copy_into_box_rc_arc.rs)
+}
+
+struct NotBox {
+    data: [u8; 9999],
+}
+
+impl NotBox {
+    fn new(data: [u8; 9999]) -> Self {
+        Self {
+            // Looking at --emit llvm-ir, we can see that a memcpy is involved.
+            // So we want the lint to trigger here.
+            data, //~ ERROR large_assignments
+        }
+    }
+}
diff --git a/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr
new file mode 100644
index 00000000000..a386de5e5e8
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_box_rc_arc.stderr
@@ -0,0 +1,15 @@
+error: moving 9999 bytes
+  --> $DIR/move_into_box_rc_arc.rs:35:13
+   |
+LL |             data,
+   |             ^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/move_into_box_rc_arc.rs:1:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/lint/large_assignments/move_into_fn.rs b/tests/ui/lint/large_assignments/move_into_fn.rs
new file mode 100644
index 00000000000..359705bfc03
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_fn.rs
@@ -0,0 +1,22 @@
+// build-fail
+
+#![feature(large_assignments)]
+#![move_size_limit = "1000"]
+#![deny(large_assignments)]
+#![allow(unused)]
+
+// Note: This type does not implement Copy.
+struct Data([u8; 9999]);
+
+fn main() {
+    // Looking at llvm-ir output, we can see a memcpy'd into Data, so we want
+    // the lint to trigger here.
+    let data = Data([100; 9999]); //~ ERROR large_assignments
+
+    // Looking at llvm-ir output, we can see that there is no memcpy involved in
+    // this function call. Instead, just a pointer is passed to the function. So
+    // the lint shall not trigger here.
+    take_data(data);
+}
+
+fn take_data(data: Data) {}
diff --git a/tests/ui/lint/large_assignments/move_into_fn.stderr b/tests/ui/lint/large_assignments/move_into_fn.stderr
new file mode 100644
index 00000000000..92a0489e472
--- /dev/null
+++ b/tests/ui/lint/large_assignments/move_into_fn.stderr
@@ -0,0 +1,15 @@
+error: moving 9999 bytes
+  --> $DIR/move_into_fn.rs:14:16
+   |
+LL |     let data = Data([100; 9999]);
+   |                ^^^^^^^^^^^^^^^^^ value moved from here
+   |
+   = note: The current maximum size is 1000, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
+note: the lint level is defined here
+  --> $DIR/move_into_fn.rs:5:9
+   |
+LL | #![deny(large_assignments)]
+   |         ^^^^^^^^^^^^^^^^^
+
+error: aborting due to 1 previous error
+
diff --git a/tests/ui/mir/inline-wrong-abi.rs b/tests/ui/mir/inline-wrong-abi.rs
new file mode 100644
index 00000000000..1f61a5dcfbe
--- /dev/null
+++ b/tests/ui/mir/inline-wrong-abi.rs
@@ -0,0 +1,32 @@
+// compile-flags: -Zpolymorphize=on -Zinline-mir=yes -Zmir-opt-level=0
+
+#![feature(fn_traits, unboxed_closures)]
+struct Foo<T>(T);
+
+impl<T: Copy> Fn<()> for Foo<T> {
+    extern "C" fn call(&self, _: ()) -> T {
+        //~^ ERROR method `call` has an incompatible type for trait
+        match *self {
+            Foo(t) => t,
+        }
+    }
+}
+
+impl<T: Copy> FnMut<()> for Foo<T> {
+    extern "rust-call" fn call_mut(&mut self, _: ()) -> T {
+        self.call(())
+    }
+}
+
+impl<T: Copy> FnOnce<()> for Foo<T> {
+    type Output = T;
+
+    extern "rust-call" fn call_once(self, _: ()) -> T {
+        self.call(())
+    }
+}
+
+fn main() {
+    let t: u8 = 1;
+    println!("{}", Foo(t)());
+}
diff --git a/tests/ui/mir/inline-wrong-abi.stderr b/tests/ui/mir/inline-wrong-abi.stderr
new file mode 100644
index 00000000000..e44899eb92a
--- /dev/null
+++ b/tests/ui/mir/inline-wrong-abi.stderr
@@ -0,0 +1,12 @@
+error[E0053]: method `call` has an incompatible type for trait
+  --> $DIR/inline-wrong-abi.rs:7:5
+   |
+LL |     extern "C" fn call(&self, _: ()) -> T {
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected "rust-call" fn, found "C" fn
+   |
+   = note: expected signature `extern "rust-call" fn(&Foo<_>, ()) -> _`
+              found signature `extern "C" fn(&Foo<_>, ()) -> _`
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0053`.
diff --git a/tests/ui/proc-macro/auxiliary/issue-118809.rs b/tests/ui/proc-macro/auxiliary/issue-118809.rs
new file mode 100644
index 00000000000..029b58c6d0c
--- /dev/null
+++ b/tests/ui/proc-macro/auxiliary/issue-118809.rs
@@ -0,0 +1,20 @@
+// force-host
+// no-prefer-dynamic
+
+#![crate_type = "proc-macro"]
+
+extern crate proc_macro;
+use proc_macro::TokenStream;
+
+#[proc_macro_derive(Deserialize)]
+pub fn deserialize_derive(input: TokenStream) -> TokenStream {
+    "impl Build {
+        fn deserialize() -> Option<u64> {
+            let x: Option<u32> = Some(0);
+            Some(x? + 1)
+        }
+    }
+    "
+    .parse()
+    .unwrap()
+}
diff --git a/tests/ui/proc-macro/issue-118809.rs b/tests/ui/proc-macro/issue-118809.rs
new file mode 100644
index 00000000000..732bf19c173
--- /dev/null
+++ b/tests/ui/proc-macro/issue-118809.rs
@@ -0,0 +1,10 @@
+// aux-build: issue-118809.rs
+
+#[macro_use]
+extern crate issue_118809;
+
+#[derive(Deserialize)] //~ ERROR mismatched types [E0308]
+pub struct Build {
+}
+
+fn main() {}
diff --git a/tests/ui/proc-macro/issue-118809.stderr b/tests/ui/proc-macro/issue-118809.stderr
new file mode 100644
index 00000000000..30b09fd4006
--- /dev/null
+++ b/tests/ui/proc-macro/issue-118809.stderr
@@ -0,0 +1,21 @@
+error[E0308]: mismatched types
+  --> $DIR/issue-118809.rs:6:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^
+   |          |
+   |          expected `u64`, found `u32`
+   |          arguments to this enum variant are incorrect
+   |
+help: the type constructed contains `u32` due to the type of the argument passed
+  --> $DIR/issue-118809.rs:6:10
+   |
+LL | #[derive(Deserialize)]
+   |          ^^^^^^^^^^^ this argument influences the type of `Some`
+note: tuple variant defined here
+  --> $SRC_DIR/core/src/option.rs:LL:COL
+   = note: this error originates in the derive macro `Deserialize` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
index dc4ec5d3ee2..ec9826819c0 100644
--- a/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
+++ b/tests/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr
@@ -18,16 +18,16 @@ help: use parentheses to call this function
 LL |     bar(foo());
    |            ++
 
-error[E0277]: `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
+error[E0277]: `{async closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:12:9
    |
 LL |     bar(async_closure);
-   |     --- ^^^^^^^^^^^^^ `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
+   |     --- ^^^^^^^^^^^^^ `{async closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}` is not a future
    |     |
    |     required by a bound introduced by this call
    |
-   = help: the trait `Future` is not implemented for `{coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}`
-   = note: {coroutine-closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited
+   = help: the trait `Future` is not implemented for `{async closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33}`
+   = note: {async closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:33} must be a future or must implement `IntoFuture` to be awaited
 note: required by a bound in `bar`
   --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
    |
diff --git a/tests/ui/thread-local/thread-local-static.rs b/tests/ui/thread-local/thread-local-static.rs
index 7b69ffed197..dac9259a6a6 100644
--- a/tests/ui/thread-local/thread-local-static.rs
+++ b/tests/ui/thread-local/thread-local-static.rs
@@ -12,7 +12,6 @@ const fn g(x: &mut [u32; 8]) {
     //~^^ ERROR thread-local statics cannot be accessed
     //~| ERROR mutable references are not allowed
     //~| ERROR use of mutable static is unsafe
-    //~| referencing statics
 }
 
 fn main() {}
diff --git a/tests/ui/thread-local/thread-local-static.stderr b/tests/ui/thread-local/thread-local-static.stderr
index d91742686c6..3dd1e2d4000 100644
--- a/tests/ui/thread-local/thread-local-static.stderr
+++ b/tests/ui/thread-local/thread-local-static.stderr
@@ -37,18 +37,6 @@ error[E0625]: thread-local statics cannot be accessed at compile-time
 LL |     std::mem::swap(x, &mut STATIC_VAR_2)
    |                            ^^^^^^^^^^^^
 
-error[E0658]: referencing statics in constant functions is unstable
-  --> $DIR/thread-local-static.rs:10:28
-   |
-LL |     std::mem::swap(x, &mut STATIC_VAR_2)
-   |                            ^^^^^^^^^^^^
-   |
-   = note: see issue #119618 <https://github.com/rust-lang/rust/issues/119618> for more information
-   = help: add `#![feature(const_refs_to_static)]` to the crate attributes to enable
-   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
-   = note: `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
-   = help: to fix this, the value can be extracted to a `const` and then used.
-
 error[E0658]: mutable references are not allowed in constant functions
   --> $DIR/thread-local-static.rs:10:23
    |
@@ -59,7 +47,7 @@ LL |     std::mem::swap(x, &mut STATIC_VAR_2)
    = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
-error: aborting due to 5 previous errors; 1 warning emitted
+error: aborting due to 4 previous errors; 1 warning emitted
 
 Some errors have detailed explanations: E0133, E0625, E0658.
 For more information about an error, try `rustc --explain E0133`.
diff --git a/tests/ui/trait-impl-bound-suggestions.fixed b/tests/ui/trait-impl-bound-suggestions.fixed
index 744e7bef04e..fb11286a175 100644
--- a/tests/ui/trait-impl-bound-suggestions.fixed
+++ b/tests/ui/trait-impl-bound-suggestions.fixed
@@ -17,4 +17,13 @@ trait InsufficientlyConstrainedGeneric<X=()> where X: std::marker::Copy {
     }
 }
 
+// Regression test for #120838
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where X: std::marker::Copy {
+    fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+        //~^ ERROR the trait bound `X: Copy` is not satisfied
+        ConstrainedStruct { x }
+    }
+}
+
 pub fn main() { }
diff --git a/tests/ui/trait-impl-bound-suggestions.rs b/tests/ui/trait-impl-bound-suggestions.rs
index bf75175179e..46130a5e766 100644
--- a/tests/ui/trait-impl-bound-suggestions.rs
+++ b/tests/ui/trait-impl-bound-suggestions.rs
@@ -17,4 +17,13 @@ trait InsufficientlyConstrainedGeneric<X=()> {
     }
 }
 
+// Regression test for #120838
+#[allow(dead_code)]
+trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where {
+    fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+        //~^ ERROR the trait bound `X: Copy` is not satisfied
+        ConstrainedStruct { x }
+    }
+}
+
 pub fn main() { }
diff --git a/tests/ui/trait-impl-bound-suggestions.stderr b/tests/ui/trait-impl-bound-suggestions.stderr
index c1f31e2b32e..9883c5bda01 100644
--- a/tests/ui/trait-impl-bound-suggestions.stderr
+++ b/tests/ui/trait-impl-bound-suggestions.stderr
@@ -14,6 +14,22 @@ help: consider further restricting type parameter `X`
 LL | trait InsufficientlyConstrainedGeneric<X=()> where X: std::marker::Copy {
    |                                              ++++++++++++++++++++++++++
 
-error: aborting due to 1 previous error
+error[E0277]: the trait bound `X: Copy` is not satisfied
+  --> $DIR/trait-impl-bound-suggestions.rs:23:52
+   |
+LL |     fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct<X> {
+   |                                                    ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X`
+   |
+note: required by a bound in `ConstrainedStruct`
+  --> $DIR/trait-impl-bound-suggestions.rs:8:29
+   |
+LL | struct ConstrainedStruct<X: Copy> {
+   |                             ^^^^ required by this bound in `ConstrainedStruct`
+help: consider further restricting type parameter `X`
+   |
+LL | trait InsufficientlyConstrainedGenericWithEmptyWhere<X=()> where X: std::marker::Copy {
+   |                                                                  ++++++++++++++++++++
+
+error: aborting due to 2 previous errors
 
 For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.rs b/tests/ui/treat-err-as-bug/span_delayed_bug.rs
index 8b9526bf3f9..1ea14aee6c4 100644
--- a/tests/ui/treat-err-as-bug/span_delayed_bug.rs
+++ b/tests/ui/treat-err-as-bug/span_delayed_bug.rs
@@ -1,12 +1,12 @@
 // compile-flags: -Ztreat-err-as-bug -Zeagerly-emit-delayed-bugs
 // failure-status: 101
 // error-pattern: aborting due to `-Z treat-err-as-bug=1`
-// error-pattern: [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
+// error-pattern: [trigger_delayed_bug] triggering a delayed bug for testing incremental
 // normalize-stderr-test "note: .*\n\n" -> ""
 // normalize-stderr-test "thread 'rustc' panicked.*:\n.*\n" -> ""
 // rustc-env:RUST_BACKTRACE=0
 
 #![feature(rustc_attrs)]
 
-#[rustc_error(span_delayed_bug_from_inside_query)]
+#[rustc_error(delayed_bug_from_inside_query)]
 fn main() {}
diff --git a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr
index a61ffaea8c2..f0e8cd0ddb9 100644
--- a/tests/ui/treat-err-as-bug/span_delayed_bug.stderr
+++ b/tests/ui/treat-err-as-bug/span_delayed_bug.stderr
@@ -1,4 +1,4 @@
-error: internal compiler error: delayed span bug triggered by #[rustc_error(span_delayed_bug_from_inside_query)]
+error: internal compiler error: delayed bug triggered by #[rustc_error(delayed_bug_from_inside_query)]
   --> $DIR/span_delayed_bug.rs:12:1
    |
 LL | fn main() {}
@@ -7,5 +7,5 @@ LL | fn main() {}
 error: the compiler unexpectedly panicked. this is a bug.
 
 query stack during panic:
-#0 [trigger_span_delayed_bug] triggering a span delayed bug for testing incremental
+#0 [trigger_delayed_bug] triggering a delayed bug for testing incremental
 end of query stack
diff --git a/tests/ui/typeck/issue-104510-ice.rs b/tests/ui/typeck/issue-104510-ice.rs
index 635cc8fad66..157bdf07e38 100644
--- a/tests/ui/typeck/issue-104510-ice.rs
+++ b/tests/ui/typeck/issue-104510-ice.rs
@@ -6,7 +6,7 @@ struct W<T: ?Sized>(Oops);
 
 unsafe fn test() {
     let j = W(());
-    let pointer = &j as *const _; //~ ERROR type annotations needed
+    let pointer = &j as *const _;
     core::arch::asm!(
         "nop",
         in("eax") pointer,
diff --git a/tests/ui/typeck/issue-104510-ice.stderr b/tests/ui/typeck/issue-104510-ice.stderr
index 774e5268184..143139b2c08 100644
--- a/tests/ui/typeck/issue-104510-ice.stderr
+++ b/tests/ui/typeck/issue-104510-ice.stderr
@@ -4,18 +4,6 @@ error[E0412]: cannot find type `Oops` in this scope
 LL | struct W<T: ?Sized>(Oops);
    |                     ^^^^ not found in this scope
 
-error[E0282]: type annotations needed for `*const W<T>`
-  --> $DIR/issue-104510-ice.rs:9:9
-   |
-LL |     let pointer = &j as *const _;
-   |         ^^^^^^^
-   |
-help: consider giving `pointer` an explicit type, where the type for type parameter `T` is specified
-   |
-LL |     let pointer: *const W<T> = &j as *const _;
-   |                +++++++++++++
-
-error: aborting due to 2 previous errors
+error: aborting due to 1 previous error
 
-Some errors have detailed explanations: E0282, E0412.
-For more information about an error, try `rustc --explain E0282`.
+For more information about this error, try `rustc --explain E0412`.
diff --git a/tests/ui/typeck/issue-116864.rs b/tests/ui/typeck/issue-116864.rs
new file mode 100644
index 00000000000..88c3f786608
--- /dev/null
+++ b/tests/ui/typeck/issue-116864.rs
@@ -0,0 +1,31 @@
+// compile-flags: -Znext-solver
+// check-pass
+// edition: 2021
+
+use std::future::Future;
+
+trait Baz {
+    type Param;
+}
+
+trait FnMutFut<P, R>: FnMut(P) -> Self::Future {
+    type Future: Future<Output = R>;
+}
+
+impl<P, F, FUT, R> FnMutFut<P, R> for F
+where
+    F: FnMut(P) -> FUT,
+    FUT: Future<Output = R>,
+{
+    type Future = FUT;
+}
+
+async fn foo<BAZ>(_: BAZ, mut cb: impl for<'any> FnMutFut<&'any BAZ::Param, ()>)
+where
+    BAZ: Baz<Param = i32>,
+{
+    cb(&1i32).await;
+}
+
+fn main() {
+}
diff --git a/triagebot.toml b/triagebot.toml
index ed2ea7798fd..383b89b18df 100644
--- a/triagebot.toml
+++ b/triagebot.toml
@@ -667,7 +667,6 @@ compiler = [
 ]
 libs = [
     "@cuviper",
-    "@joshtriplett",
     "@Mark-Simulacrum",
 ]
 bootstrap = [
@@ -833,7 +832,7 @@ project-stable-mir = [
 "/src/rustdoc-json-types" =                              ["rustdoc"]
 "/src/stage0.json" =                                     ["bootstrap"]
 "/tests/ui" =                                            ["compiler"]
-"/src/tools/cargo" =                                     ["@ehuss", "@joshtriplett"]
+"/src/tools/cargo" =                                     ["@ehuss"]
 "/src/tools/compiletest" =                               ["bootstrap", "@wesleywiser", "@oli-obk", "@compiler-errors"]
 "/src/tools/linkchecker" =                               ["@ehuss"]
 "/src/tools/rust-installer" =                            ["bootstrap"]