about summary refs log tree commit diff
diff options
context:
space:
mode:
authorThe Miri Cronjob Bot <miri@cron.bot>2025-01-30 05:06:57 +0000
committerThe Miri Cronjob Bot <miri@cron.bot>2025-01-30 05:06:57 +0000
commitb8ee38d3e87b3838ac8e8fac03bb724cce4ce392 (patch)
tree535079811289b859bf0f6eb1215e3681615c69ac
parent851ce41bc6fb207db4c4fb0ebbac971fa65eff3b (diff)
parentd78193381249740d769970d4ec453c5bc265f082 (diff)
downloadrust-b8ee38d3e87b3838ac8e8fac03bb724cce4ce392.tar.gz
rust-b8ee38d3e87b3838ac8e8fac03bb724cce4ce392.zip
Merge from rustc
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs36
-rw-r--r--compiler/rustc_ast/src/visit.rs25
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs10
-rw-r--r--compiler/rustc_ast_lowering/src/pat.rs33
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs22
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/item.rs28
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs25
-rw-r--r--compiler/rustc_borrowck/src/polonius/dump.rs245
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/gcc_util.rs50
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs5
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs56
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs4
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs6
-rw-r--r--compiler/rustc_hir/src/hir.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs3
-rw-r--r--compiler/rustc_hir/src/pat_util.rs5
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs14
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs11
-rw-r--r--compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs4
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs44
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs1
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs56
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs11
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs2
-rw-r--r--compiler/rustc_interface/messages.ftl5
-rw-r--r--compiler/rustc_interface/src/errors.rs9
-rw-r--r--compiler/rustc_interface/src/interface.rs2
-rw-r--r--compiler/rustc_interface/src/util.rs38
-rw-r--r--compiler/rustc_lint/src/builtin.rs8
-rw-r--r--compiler/rustc_lint/src/internal.rs10
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs8
-rw-r--r--compiler/rustc_lint/src/unused.rs35
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs2
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs12
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation.rs26
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs4
-rw-r--r--compiler/rustc_middle/src/query/mod.rs6
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs3
-rw-r--r--compiler/rustc_middle/src/ty/context.rs16
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs4
-rw-r--r--compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs2
-rw-r--r--compiler/rustc_middle/src/ty/vtable.rs6
-rw-r--r--compiler/rustc_mir_build/src/builder/matches/test.rs99
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs11
-rw-r--r--compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs63
-rw-r--r--compiler/rustc_parse_format/src/lib.rs41
-rw-r--r--compiler/rustc_parse_format/src/tests.rs18
-rw-r--r--compiler/rustc_passes/src/dead.rs18
-rw-r--r--compiler/rustc_passes/src/input_stats.rs1
-rw-r--r--compiler/rustc_resolve/src/def_collector.rs9
-rw-r--r--compiler/rustc_resolve/src/late.rs6
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs10
-rw-r--r--compiler/rustc_smir/src/rustc_smir/alloc.rs12
-rw-r--r--compiler/rustc_target/src/target_features.rs29
-rw-r--r--compiler/rustc_trait_selection/messages.ftl2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs39
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs1
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs4
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs36
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs2
-rw-r--r--compiler/rustc_type_ir/src/interner.rs10
-rw-r--r--library/core/src/macros/mod.rs11
-rw-r--r--library/std/src/io/pipe/tests.rs2
-rw-r--r--library/std/src/sys/pal/uefi/process.rs7
-rw-r--r--src/ci/docker/host-x86_64/mingw-check/Dockerfile5
-rw-r--r--src/ci/github-actions/jobs.yml4
m---------src/doc/book0
m---------src/doc/edition-guide0
m---------src/doc/nomicon0
m---------src/doc/reference0
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-example.rs2
-rw-r--r--src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs2
-rw-r--r--src/librustdoc/clean/utils.rs3
-rw-r--r--src/librustdoc/html/render/span_map.rs26
-rw-r--r--src/librustdoc/html/static/js/README.md10
-rw-r--r--src/librustdoc/html/static/js/externs.js270
-rw-r--r--src/librustdoc/html/static/js/main.js345
-rw-r--r--src/librustdoc/html/static/js/rustdoc.d.ts387
-rw-r--r--src/librustdoc/html/static/js/scrape-examples.js3
-rw-r--r--src/librustdoc/html/static/js/search.js1201
-rw-r--r--src/librustdoc/html/static/js/settings.js3
-rw-r--r--src/librustdoc/html/static/js/src-script.js3
-rw-r--r--src/librustdoc/html/static/js/storage.js98
-rw-r--r--src/librustdoc/html/static/js/tsconfig.json15
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/needless_match.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs5
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs25
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/mod.rs6
-rw-r--r--src/tools/miri/src/shims/alloc.rs19
-rw-r--r--src/tools/miri/src/shims/foreign_items.rs16
-rw-r--r--src/tools/miri/src/shims/unix/fs.rs1
-rw-r--r--src/tools/miri/src/shims/unix/linux/mem.rs10
-rw-r--r--src/tools/miri/src/shims/unix/mem.rs16
-rw-r--r--src/tools/miri/src/shims/windows/foreign_items.rs16
-rw-r--r--src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs4
-rw-r--r--src/tools/run-make-support/src/command.rs6
-rw-r--r--src/tools/run-make-support/src/external_deps/rustc.rs10
-rw-r--r--src/tools/rust-analyzer/Cargo.lock7
-rw-r--r--src/tools/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/find_path.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs2
-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.rs258
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs1
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs72
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs26
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/resolver.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs49
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/name.rs106
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs45
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs131
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs47
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs54
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs74
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/symbols.rs137
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_bool_then.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_variable.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs4
-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/move_to_mod_rs.rs4
-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/reorder_fields.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions.rs90
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs151
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/expr.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs72
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/config.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/item.rs19
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/lib.rs37
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render.rs28
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/const_.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/pattern.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/type_alias.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs21
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs35
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs17
-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.rs24
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs3
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/rename.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs10
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs83
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt33
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_fields.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/doc_links.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs104
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs85
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs77
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs301
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs17
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs73
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs29
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs49
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/rename.rs2
-rw-r--r--src/tools/rust-analyzer/crates/intern/Cargo.toml1
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol.rs37
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs10
-rw-r--r--src/tools/rust-analyzer/crates/load-cargo/src/lib.rs18
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs4
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/project_json.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs41
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs11
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs25
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs3
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/ext.rs1
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs135
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/make.rs12
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/src/minicore.rs17
-rw-r--r--src/tools/rust-analyzer/docs/dev/README.md18
-rw-r--r--src/tools/rust-analyzer/docs/dev/lsp-extensions.md2
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc10
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc90
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json20
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts9
-rw-r--r--src/tools/rust-analyzer/lib/lsp-server/src/msg.rs6
-rw-r--r--src/tools/rustbook/Cargo.lock52
-rw-r--r--src/tools/rustbook/Cargo.toml2
-rw-r--r--src/tools/rustfmt/src/items.rs17
-rw-r--r--src/tools/rustfmt/src/visitor.rs15
-rw-r--r--src/tools/tidy/src/allowed_run_make_makefiles.txt1
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs4
-rw-r--r--tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs8
-rw-r--r--tests/codegen/target-feature-overrides.rs8
-rw-r--r--tests/codegen/tied-features-strength.rs5
-rw-r--r--tests/crashes/131103.rs6
-rw-r--r--tests/mir-opt/pattern_types.main.PreCodegen.after.mir15
-rw-r--r--tests/mir-opt/pattern_types.rs12
-rw-r--r--tests/run-make/translation/Makefile78
-rw-r--r--tests/run-make/translation/rmake.rs194
-rw-r--r--tests/ui-fulldeps/codegen-backend/hotplug.rs4
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32e.stderr66
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32gc.stderr26
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32i.stderr34
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr30
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv64gc.stderr26
-rw-r--r--tests/ui/asm/riscv/bad-reg.riscv64imac.stderr34
-rw-r--r--tests/ui/asm/riscv/bad-reg.rs2
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.current.stderr (renamed from tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr)2
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.next.stderr14
-rw-r--r--tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs4
-rw-r--r--tests/ui/borrowck/issue-93093.rs2
-rw-r--r--tests/ui/borrowck/issue-93093.stderr2
-rw-r--r--tests/ui/borrowck/trait-impl-argument-difference-ice.stderr4
-rw-r--r--tests/ui/const-generics/bad-subst-const-kind.stderr2
-rw-r--r--tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr2
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.rs13
-rw-r--r--tests/ui/const-generics/issues/index_array_bad_type.stderr18
-rw-r--r--tests/ui/const-generics/transmute-fail.stderr4
-rw-r--r--tests/ui/const-generics/type_mismatch.stderr2
-rw-r--r--tests/ui/consts/bad-array-size-in-type-err.stderr4
-rw-r--r--tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs9
-rw-r--r--tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr59
-rw-r--r--tests/ui/did_you_mean/issue-38147-1.stderr2
-rw-r--r--tests/ui/did_you_mean/issue-39544.stderr6
-rw-r--r--tests/ui/generic-const-items/def-site-eval.fail.stderr11
-rw-r--r--tests/ui/generic-const-items/def-site-eval.rs16
-rw-r--r--tests/ui/generic-const-items/def-site-mono.rs13
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.rs2
-rw-r--r--tests/ui/lint/dead-code/lint-dead-code-1.stderr14
-rw-r--r--tests/ui/mut/mutable-class-fields-2.stderr2
-rw-r--r--tests/ui/pattern/issue-110508.rs8
-rw-r--r--tests/ui/sanitizer/asan_odr_windows.rs (renamed from tests/ui/asan-odr-win/asan_odr_windows.rs)0
-rw-r--r--tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs (renamed from tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs)0
-rw-r--r--tests/ui/suggestions/suggest-ref-mut.rs2
-rw-r--r--tests/ui/suggestions/suggest-ref-mut.stderr2
-rw-r--r--tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr7
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr2
-rw-r--r--tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr10
-rw-r--r--tests/ui/thir-print/thir-tree-match.stdout52
-rw-r--r--tests/ui/traits/const-traits/const-impl-trait.stderr16
-rw-r--r--tests/ui/typeck/issue-107775.stderr2
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr2
322 files changed, 5548 insertions, 3026 deletions
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 3459d39131a..7caf7c4c356 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -954,8 +954,14 @@ fn walk_coroutine_kind<T: MutVisitor>(vis: &mut T, coroutine_kind: &mut Coroutin
 
 fn walk_fn<T: MutVisitor>(vis: &mut T, kind: FnKind<'_>) {
     match kind {
-        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span }, _visibility, generics, body) => {
+        FnKind::Fn(
+            _ctxt,
+            _ident,
+            _vis,
+            Fn { defaultness, generics, body, sig: FnSig { header, decl, span } },
+        ) => {
             // Identifier and visibility are visited as a part of the item.
+            visit_defaultness(vis, defaultness);
             vis.visit_fn_header(header);
             vis.visit_generics(generics);
             vis.visit_fn_decl(decl);
@@ -1205,13 +1211,8 @@ impl WalkItemKind for ItemKind {
             ItemKind::Const(item) => {
                 visit_const_item(item, vis);
             }
-            ItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(vis, defaultness);
-                vis.visit_fn(
-                    FnKind::Fn(FnCtxt::Free, ident, sig, visibility, generics, body),
-                    span,
-                    id,
-                );
+            ItemKind::Fn(func) => {
+                vis.visit_fn(FnKind::Fn(FnCtxt::Free, ident, visibility, &mut *func), span, id);
             }
             ItemKind::Mod(safety, mod_kind) => {
                 visit_safety(vis, safety);
@@ -1329,10 +1330,9 @@ impl WalkItemKind for AssocItemKind {
             AssocItemKind::Const(item) => {
                 visit_const_item(item, visitor);
             }
-            AssocItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(visitor, defaultness);
+            AssocItemKind::Fn(func) => {
                 visitor.visit_fn(
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, visibility, generics, body),
+                    FnKind::Fn(FnCtxt::Assoc(ctxt), ident, visibility, &mut *func),
                     span,
                     id,
                 );
@@ -1476,10 +1476,9 @@ impl WalkItemKind for ForeignItemKind {
                 visitor.visit_ty(ty);
                 visit_opt(expr, |expr| visitor.visit_expr(expr));
             }
-            ForeignItemKind::Fn(box Fn { defaultness, generics, sig, body }) => {
-                visit_defaultness(visitor, defaultness);
+            ForeignItemKind::Fn(func) => {
                 visitor.visit_fn(
-                    FnKind::Fn(FnCtxt::Foreign, ident, sig, visibility, generics, body),
+                    FnKind::Fn(FnCtxt::Foreign, ident, visibility, &mut *func),
                     span,
                     id,
                 );
@@ -1965,14 +1964,7 @@ impl<N: DummyAstNode, T: DummyAstNode> DummyAstNode for crate::ast_traits::AstNo
 #[derive(Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(
-        FnCtxt,
-        &'a mut Ident,
-        &'a mut FnSig,
-        &'a mut Visibility,
-        &'a mut Generics,
-        &'a mut Option<P<Block>>,
-    ),
+    Fn(FnCtxt, &'a mut Ident, &'a mut Visibility, &'a mut Fn),
 
     /// E.g., `|x, y| body`.
     Closure(
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index 1d6d7330757..232fd546de9 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -65,7 +65,7 @@ impl BoundKind {
 #[derive(Copy, Clone, Debug)]
 pub enum FnKind<'a> {
     /// E.g., `fn foo()`, `fn foo(&self)`, or `extern "Abi" fn foo()`.
-    Fn(FnCtxt, &'a Ident, &'a FnSig, &'a Visibility, &'a Generics, &'a Option<P<Block>>),
+    Fn(FnCtxt, &'a Ident, &'a Visibility, &'a Fn),
 
     /// E.g., `|x, y| body`.
     Closure(&'a ClosureBinder, &'a Option<CoroutineKind>, &'a FnDecl, &'a Expr),
@@ -74,7 +74,7 @@ pub enum FnKind<'a> {
 impl<'a> FnKind<'a> {
     pub fn header(&self) -> Option<&'a FnHeader> {
         match *self {
-            FnKind::Fn(_, _, sig, _, _, _) => Some(&sig.header),
+            FnKind::Fn(_, _, _, Fn { sig, .. }) => Some(&sig.header),
             FnKind::Closure(..) => None,
         }
     }
@@ -88,7 +88,7 @@ impl<'a> FnKind<'a> {
 
     pub fn decl(&self) -> &'a FnDecl {
         match self {
-            FnKind::Fn(_, _, sig, _, _, _) => &sig.decl,
+            FnKind::Fn(_, _, _, Fn { sig, .. }) => &sig.decl,
             FnKind::Closure(_, _, decl, _) => decl,
         }
     }
@@ -374,8 +374,8 @@ impl WalkItemKind for ItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            ItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Free, ident, sig, vis, generics, body);
+            ItemKind::Fn(func) => {
+                let kind = FnKind::Fn(FnCtxt::Free, ident, vis, &*func);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ItemKind::Mod(_unsafety, mod_kind) => match mod_kind {
@@ -715,8 +715,8 @@ impl WalkItemKind for ForeignItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            ForeignItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Foreign, ident, sig, vis, generics, body);
+            ForeignItemKind::Fn(func) => {
+                let kind = FnKind::Fn(FnCtxt::Foreign, ident, vis, &*func);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             ForeignItemKind::TyAlias(box TyAlias {
@@ -858,7 +858,12 @@ pub fn walk_fn_decl<'a, V: Visitor<'a>>(
 
 pub fn walk_fn<'a, V: Visitor<'a>>(visitor: &mut V, kind: FnKind<'a>) -> V::Result {
     match kind {
-        FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body) => {
+        FnKind::Fn(
+            _ctxt,
+            _ident,
+            _vis,
+            Fn { defaultness: _, sig: FnSig { header, decl, span: _ }, generics, body },
+        ) => {
             // Identifier and visibility are visited as a part of the item.
             try_visit!(visitor.visit_fn_header(header));
             try_visit!(visitor.visit_generics(generics));
@@ -892,8 +897,8 @@ impl WalkItemKind for AssocItemKind {
                 try_visit!(visitor.visit_ty(ty));
                 visit_opt!(visitor, visit_expr, expr);
             }
-            AssocItemKind::Fn(box Fn { defaultness: _, generics, sig, body }) => {
-                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, sig, vis, generics, body);
+            AssocItemKind::Fn(func) => {
+                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), ident, vis, &*func);
                 try_visit!(visitor.visit_fn(kind, span, id));
             }
             AssocItemKind::Type(box TyAlias {
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index f31e2c65c79..1267281f73e 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -1391,7 +1391,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
                         None,
                     );
                     // Destructure like a unit struct.
-                    let unit_struct_pat = hir::PatKind::Path(qpath);
+                    let unit_struct_pat = hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
+                        kind: hir::PatExprKind::Path(qpath),
+                        hir_id: self.next_id(),
+                        span: self.lower_span(lhs.span),
+                    }));
                     return self.pat_without_dbm(lhs.span, unit_struct_pat);
                 }
             }
@@ -2125,7 +2129,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.arena.alloc(self.expr_call_mut(span, e, args))
     }
 
-    fn expr_call_lang_item_fn_mut(
+    pub(super) fn expr_call_lang_item_fn_mut(
         &mut self,
         span: Span,
         lang_item: hir::LangItem,
@@ -2135,7 +2139,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
         self.expr_call_mut(span, path, args)
     }
 
-    fn expr_call_lang_item_fn(
+    pub(super) fn expr_call_lang_item_fn(
         &mut self,
         span: Span,
         lang_item: hir::LangItem,
diff --git a/compiler/rustc_ast_lowering/src/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs
index 3c78ed0497d..cde8ddbfe03 100644
--- a/compiler/rustc_ast_lowering/src/pat.rs
+++ b/compiler/rustc_ast_lowering/src/pat.rs
@@ -69,7 +69,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                             ImplTraitContext::Disallowed(ImplTraitPosition::Path),
                             None,
                         );
-                        break hir::PatKind::Path(qpath);
+                        let kind = hir::PatExprKind::Path(qpath);
+                        let span = self.lower_span(pattern.span);
+                        let expr = hir::PatExpr { hir_id: pat_hir_id, span, kind };
+                        let expr = self.arena.alloc(expr);
+                        return hir::Pat {
+                            hir_id: self.next_id(),
+                            kind: hir::PatKind::Expr(expr),
+                            span,
+                            default_binding_modes: true,
+                        };
                     }
                     PatKind::Struct(qself, path, fields, etc) => {
                         let qpath = self.lower_qpath(
@@ -304,16 +313,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
                 )
             }
             Some(res) => {
-                let hir_id = self.next_id();
                 let res = self.lower_res(res);
-                hir::PatKind::Path(hir::QPath::Resolved(
-                    None,
-                    self.arena.alloc(hir::Path {
-                        span: self.lower_span(ident.span),
-                        res,
-                        segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), hir_id, res)],
-                    }),
-            ))
+                let span = self.lower_span(ident.span);
+                hir::PatKind::Expr(self.arena.alloc(hir::PatExpr {
+                    kind: hir::PatExprKind::Path(hir::QPath::Resolved(
+                        None,
+                        self.arena.alloc(hir::Path {
+                            span,
+                            res,
+                            segments: arena_vec![self; hir::PathSegment::new(self.lower_ident(ident), self.next_id(), res)],
+                        }),
+                    )),
+                    hir_id: self.next_id(),
+                    span,
+                }))
             }
         }
     }
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index 236ca7ba703..ea1f4a6559a 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -917,7 +917,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
             }
-            ItemKind::Fn(box Fn { defaultness, sig, generics, body }) => {
+            ItemKind::Fn(func @ box Fn { defaultness, generics: _, sig, body }) => {
                 self.check_defaultness(item.span, *defaultness);
 
                 let is_intrinsic =
@@ -947,7 +947,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
 
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind = FnKind::Fn(FnCtxt::Free, &item.ident, sig, &item.vis, generics, body);
+                let kind = FnKind::Fn(FnCtxt::Free, &item.ident, &item.vis, &*func);
                 self.visit_fn(kind, item.span, item.id);
                 walk_list!(self, visit_attribute, &item.attrs);
                 return; // Avoid visiting again.
@@ -1350,17 +1350,18 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
         if let FnKind::Fn(
             _,
             _,
-            FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
-            _,
-            _,
             _,
+            Fn {
+                sig: FnSig { header: FnHeader { ext: Extern::Implicit(extern_span), .. }, .. },
+                ..
+            },
         ) = fk
         {
             self.maybe_lint_missing_abi(*extern_span, id);
         }
 
         // Functions without bodies cannot have patterns.
-        if let FnKind::Fn(ctxt, _, sig, _, _, None) = fk {
+        if let FnKind::Fn(ctxt, _, _, Fn { body: None, sig, .. }) = fk {
             Self::check_decl_no_pat(&sig.decl, |span, ident, mut_ident| {
                 if mut_ident && matches!(ctxt, FnCtxt::Assoc(_)) {
                     if let Some(ident) = ident {
@@ -1394,7 +1395,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
                         .is_some();
 
         let disallowed = (!tilde_const_allowed).then(|| match fk {
-            FnKind::Fn(_, ident, _, _, _, _) => TildeConstReason::Function { ident: ident.span },
+            FnKind::Fn(_, ident, _, _) => TildeConstReason::Function { ident: ident.span },
             FnKind::Closure(..) => TildeConstReason::Closure,
         });
         self.with_tilde_const(disallowed, |this| visit::walk_fn(this, fk));
@@ -1470,15 +1471,14 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
             self.outer_trait_or_trait_impl.as_ref().and_then(TraitOrTraitImpl::constness).is_some();
 
         match &item.kind {
-            AssocItemKind::Fn(box Fn { sig, generics, body, .. })
+            AssocItemKind::Fn(func)
                 if parent_is_const
                     || ctxt == AssocCtxt::Trait
-                    || matches!(sig.header.constness, Const::Yes(_)) =>
+                    || matches!(func.sig.header.constness, Const::Yes(_)) =>
             {
                 self.visit_vis(&item.vis);
                 self.visit_ident(&item.ident);
-                let kind =
-                    FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, sig, &item.vis, generics, body);
+                let kind = FnKind::Fn(FnCtxt::Assoc(ctxt), &item.ident, &item.vis, &*func);
                 walk_list!(self, visit_attribute, &item.attrs);
                 self.visit_fn(kind, item.span, item.id);
             }
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
index 897c275d850..4cfcaa95233 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs
@@ -34,8 +34,8 @@ impl<'a> State<'a> {
         self.maybe_print_comment(span.lo());
         self.print_outer_attributes(attrs);
         match kind {
-            ast::ForeignItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            ast::ForeignItemKind::Fn(func) => {
+                self.print_fn_full(ident, vis, attrs, &*func);
             }
             ast::ForeignItemKind::Static(box ast::StaticItem { ty, mutability, expr, safety }) => {
                 self.print_item_const(
@@ -199,16 +199,8 @@ impl<'a> State<'a> {
                     *defaultness,
                 );
             }
-            ast::ItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(
-                    sig,
-                    item.ident,
-                    generics,
-                    &item.vis,
-                    *defaultness,
-                    body.as_deref(),
-                    &item.attrs,
-                );
+            ast::ItemKind::Fn(func) => {
+                self.print_fn_full(item.ident, &item.vis, &item.attrs, &*func);
             }
             ast::ItemKind::Mod(safety, mod_kind) => {
                 self.head(Self::to_string(|s| {
@@ -542,8 +534,8 @@ impl<'a> State<'a> {
         self.maybe_print_comment(span.lo());
         self.print_outer_attributes(attrs);
         match kind {
-            ast::AssocItemKind::Fn(box ast::Fn { defaultness, sig, generics, body }) => {
-                self.print_fn_full(sig, ident, generics, vis, *defaultness, body.as_deref(), attrs);
+            ast::AssocItemKind::Fn(func) => {
+                self.print_fn_full(ident, vis, attrs, &*func);
             }
             ast::AssocItemKind::Const(box ast::ConstItem { defaultness, generics, ty, expr }) => {
                 self.print_item_const(
@@ -653,19 +645,17 @@ impl<'a> State<'a> {
 
     fn print_fn_full(
         &mut self,
-        sig: &ast::FnSig,
         name: Ident,
-        generics: &ast::Generics,
         vis: &ast::Visibility,
-        defaultness: ast::Defaultness,
-        body: Option<&ast::Block>,
         attrs: &[ast::Attribute],
+        func: &ast::Fn,
     ) {
+        let ast::Fn { defaultness, generics, sig, body } = func;
         if body.is_some() {
             self.head("");
         }
         self.print_visibility(vis);
-        self.print_defaultness(defaultness);
+        self.print_defaultness(*defaultness);
         self.print_fn(&sig.decl, sig.header, Some(name), generics);
         if let Some(body) = body {
             self.nbsp();
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index a6ca038282d..e841a5e4c94 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1140,10 +1140,9 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
 
         let amp_mut_sugg = match *local_decl.local_info() {
             LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
-                let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
-                let additional =
-                    local_trait.map(|span| (span, suggest_ampmut_self(self.infcx.tcx, span)));
-                Some(AmpMutSugg { has_sugg: true, span: decl_span, suggestion, additional })
+                let (span, suggestion) = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                let additional = local_trait.map(|span| suggest_ampmut_self(self.infcx.tcx, span));
+                Some(AmpMutSugg { has_sugg: true, span, suggestion, additional })
             }
 
             LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
@@ -1202,10 +1201,11 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
                                     opt_ty_info: None,
                                     ..
                                 })) => {
-                                    let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
+                                    let (span, sugg) =
+                                        suggest_ampmut_self(self.infcx.tcx, decl_span);
                                     Some(AmpMutSugg {
                                         has_sugg: true,
-                                        span: decl_span,
+                                        span,
                                         suggestion: sugg,
                                         additional: None,
                                     })
@@ -1461,17 +1461,12 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
     }
 }
 
-fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
+fn suggest_ampmut_self(tcx: TyCtxt<'_>, span: Span) -> (Span, String) {
     match tcx.sess.source_map().span_to_snippet(span) {
-        Ok(snippet) => {
-            let lt_pos = snippet.find('\'');
-            if let Some(lt_pos) = lt_pos {
-                format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
-            } else {
-                "&mut self".to_string()
-            }
+        Ok(snippet) if snippet.ends_with("self") => {
+            (span.with_hi(span.hi() - BytePos(4)).shrink_to_hi(), "mut ".to_string())
         }
-        _ => "&mut self".to_string(),
+        _ => (span, "&mut self".to_string()),
     }
 }
 
diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs
index 40e801d0388..6d32ee17f4c 100644
--- a/compiler/rustc_borrowck/src/polonius/dump.rs
+++ b/compiler/rustc_borrowck/src/polonius/dump.rs
@@ -1,14 +1,20 @@
 use std::io;
 
+use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet};
+use rustc_index::IndexVec;
 use rustc_middle::mir::pretty::{
     PassWhere, PrettyPrintMirOptions, create_dump_file, dump_enabled, dump_mir_to_writer,
 };
-use rustc_middle::mir::{Body, ClosureRegionRequirements};
-use rustc_middle::ty::TyCtxt;
+use rustc_middle::mir::{Body, ClosureRegionRequirements, Location};
+use rustc_middle::ty::{RegionVid, TyCtxt};
+use rustc_mir_dataflow::points::PointIndex;
 use rustc_session::config::MirIncludeSpans;
 
 use crate::borrow_set::BorrowSet;
+use crate::constraints::OutlivesConstraint;
 use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
+use crate::region_infer::values::LivenessValues;
+use crate::type_check::Locations;
 use crate::{BorrowckInferCtxt, RegionInferenceContext};
 
 /// `-Zdump-mir=polonius` dumps MIR annotated with NLL and polonius specific information.
@@ -50,6 +56,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
 /// - the NLL MIR
 /// - the list of polonius localized constraints
 /// - a mermaid graph of the CFG
+/// - a mermaid graph of the NLL regions and the constraints between them
+/// - a mermaid graph of the NLL SCCs and the constraints between them
 fn emit_polonius_dump<'tcx>(
     tcx: TyCtxt<'tcx>,
     body: &Body<'tcx>,
@@ -68,25 +76,54 @@ fn emit_polonius_dump<'tcx>(
     // Section 1: the NLL + Polonius MIR.
     writeln!(out, "<div>")?;
     writeln!(out, "Raw MIR dump")?;
-    writeln!(out, "<code><pre>")?;
+    writeln!(out, "<pre><code>")?;
     emit_html_mir(
         tcx,
         body,
         regioncx,
         borrow_set,
-        localized_outlives_constraints,
+        &localized_outlives_constraints,
         closure_region_requirements,
         out,
     )?;
-    writeln!(out, "</pre></code>")?;
+    writeln!(out, "</code></pre>")?;
     writeln!(out, "</div>")?;
 
-    // Section 2: mermaid visualization of the CFG.
+    // Section 2: mermaid visualization of the polonius constraint graph.
+    writeln!(out, "<div>")?;
+    writeln!(out, "Polonius constraint graph")?;
+    writeln!(out, "<pre class='mermaid'>")?;
+    let edge_count = emit_mermaid_constraint_graph(
+        borrow_set,
+        regioncx.liveness_constraints(),
+        &localized_outlives_constraints,
+        out,
+    )?;
+    writeln!(out, "</pre>")?;
+    writeln!(out, "</div>")?;
+
+    // Section 3: mermaid visualization of the CFG.
     writeln!(out, "<div>")?;
     writeln!(out, "Control-flow graph")?;
-    writeln!(out, "<code><pre class='mermaid'>")?;
+    writeln!(out, "<pre class='mermaid'>")?;
     emit_mermaid_cfg(body, out)?;
-    writeln!(out, "</pre></code>")?;
+    writeln!(out, "</pre>")?;
+    writeln!(out, "</div>")?;
+
+    // Section 4: mermaid visualization of the NLL region graph.
+    writeln!(out, "<div>")?;
+    writeln!(out, "NLL regions")?;
+    writeln!(out, "<pre class='mermaid'>")?;
+    emit_mermaid_nll_regions(regioncx, out)?;
+    writeln!(out, "</pre>")?;
+    writeln!(out, "</div>")?;
+
+    // Section 5: mermaid visualization of the NLL SCC graph.
+    writeln!(out, "<div>")?;
+    writeln!(out, "NLL SCCs")?;
+    writeln!(out, "<pre class='mermaid'>")?;
+    emit_mermaid_nll_sccs(regioncx, out)?;
+    writeln!(out, "</pre>")?;
     writeln!(out, "</div>")?;
 
     // Finalize the dump with the HTML epilogue.
@@ -95,7 +132,11 @@ fn emit_polonius_dump<'tcx>(
         "<script src='https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.min.js'></script>"
     )?;
     writeln!(out, "<script>")?;
-    writeln!(out, "mermaid.initialize({{ startOnLoad: false, maxEdges: 100 }});")?;
+    writeln!(
+        out,
+        "mermaid.initialize({{ startOnLoad: false, maxEdges: {} }});",
+        edge_count.max(100),
+    )?;
     writeln!(out, "mermaid.run({{ querySelector: '.mermaid' }})")?;
     writeln!(out, "</script>")?;
     writeln!(out, "</body>")?;
@@ -110,7 +151,7 @@ fn emit_html_mir<'tcx>(
     body: &Body<'tcx>,
     regioncx: &RegionInferenceContext<'tcx>,
     borrow_set: &BorrowSet<'tcx>,
-    localized_outlives_constraints: LocalizedOutlivesConstraintSet,
+    localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
     closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
     out: &mut dyn io::Write,
 ) -> io::Result<()> {
@@ -138,7 +179,7 @@ fn emit_html_mir<'tcx>(
                 regioncx,
                 closure_region_requirements,
                 borrow_set,
-                &localized_outlives_constraints,
+                localized_outlives_constraints,
                 pass_where,
                 out,
             )
@@ -261,3 +302,185 @@ fn emit_mermaid_cfg(body: &Body<'_>, out: &mut dyn io::Write) -> io::Result<()>
 
     Ok(())
 }
+
+/// Emits a region's label: index, universe, external name.
+fn render_region(
+    region: RegionVid,
+    regioncx: &RegionInferenceContext<'_>,
+    out: &mut dyn io::Write,
+) -> io::Result<()> {
+    let def = regioncx.region_definition(region);
+    let universe = def.universe;
+
+    write!(out, "'{}", region.as_usize())?;
+    if !universe.is_root() {
+        write!(out, "/{universe:?}")?;
+    }
+    if let Some(name) = def.external_name.and_then(|e| e.get_name()) {
+        write!(out, " ({name})")?;
+    }
+    Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL regions and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_regions<'tcx>(
+    regioncx: &RegionInferenceContext<'tcx>,
+    out: &mut dyn io::Write,
+) -> io::Result<()> {
+    // The mermaid chart type: a top-down flowchart.
+    writeln!(out, "flowchart TD")?;
+
+    // Emit the region nodes.
+    for region in regioncx.var_infos.indices() {
+        write!(out, "{}[\"", region.as_usize())?;
+        render_region(region, regioncx, out)?;
+        writeln!(out, "\"]")?;
+    }
+
+    // Get a set of edges to check for the reverse edge being present.
+    let edges: FxHashSet<_> = regioncx.outlives_constraints().map(|c| (c.sup, c.sub)).collect();
+
+    // Order (and deduplicate) edges for traversal, to display them in a generally increasing order.
+    let constraint_key = |c: &OutlivesConstraint<'_>| {
+        let min = c.sup.min(c.sub);
+        let max = c.sup.max(c.sub);
+        (min, max)
+    };
+    let mut ordered_edges: Vec<_> = regioncx.outlives_constraints().collect();
+    ordered_edges.sort_by_key(|c| constraint_key(c));
+    ordered_edges.dedup_by_key(|c| constraint_key(c));
+
+    for outlives in ordered_edges {
+        // Source node.
+        write!(out, "{} ", outlives.sup.as_usize())?;
+
+        // The kind of arrow: bidirectional if the opposite edge exists in the set.
+        if edges.contains(&(outlives.sub, outlives.sup)) {
+            write!(out, "&lt;")?;
+        }
+        write!(out, "-- ")?;
+
+        // Edge label from its `Locations`.
+        match outlives.locations {
+            Locations::All(_) => write!(out, "All")?,
+            Locations::Single(location) => write!(out, "{:?}", location)?,
+        }
+
+        // Target node.
+        writeln!(out, " --> {}", outlives.sub.as_usize())?;
+    }
+    Ok(())
+}
+
+/// Emits a mermaid flowchart of the NLL SCCs and the outlives constraints between them, similar
+/// to the graphviz version.
+fn emit_mermaid_nll_sccs<'tcx>(
+    regioncx: &RegionInferenceContext<'tcx>,
+    out: &mut dyn io::Write,
+) -> io::Result<()> {
+    // The mermaid chart type: a top-down flowchart.
+    writeln!(out, "flowchart TD")?;
+
+    // Gather and emit the SCC nodes.
+    let mut nodes_per_scc: IndexVec<_, _> =
+        regioncx.constraint_sccs().all_sccs().map(|_| Vec::new()).collect();
+    for region in regioncx.var_infos.indices() {
+        let scc = regioncx.constraint_sccs().scc(region);
+        nodes_per_scc[scc].push(region);
+    }
+    for (scc, regions) in nodes_per_scc.iter_enumerated() {
+        // The node label: the regions contained in the SCC.
+        write!(out, "{scc}[\"SCC({scc}) = {{", scc = scc.as_usize())?;
+        for (idx, &region) in regions.iter().enumerate() {
+            render_region(region, regioncx, out)?;
+            if idx < regions.len() - 1 {
+                write!(out, ",")?;
+            }
+        }
+        writeln!(out, "}}\"]")?;
+    }
+
+    // Emit the edges between SCCs.
+    let edges = regioncx.constraint_sccs().all_sccs().flat_map(|source| {
+        regioncx.constraint_sccs().successors(source).iter().map(move |&target| (source, target))
+    });
+    for (source, target) in edges {
+        writeln!(out, "{} --> {}", source.as_usize(), target.as_usize())?;
+    }
+
+    Ok(())
+}
+
+/// Emits a mermaid flowchart of the polonius localized outlives constraints, with subgraphs per
+/// region, and loan introductions.
+fn emit_mermaid_constraint_graph<'tcx>(
+    borrow_set: &BorrowSet<'tcx>,
+    liveness: &LivenessValues,
+    localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
+    out: &mut dyn io::Write,
+) -> io::Result<usize> {
+    let location_name = |location: Location| {
+        // A MIR location looks like `bb5[2]`. As that is not a syntactically valid mermaid node id,
+        // transform it into `BB5_2`.
+        format!("BB{}_{}", location.block.index(), location.statement_index)
+    };
+    let region_name = |region: RegionVid| format!("'{}", region.index());
+    let node_name = |region: RegionVid, point: PointIndex| {
+        let location = liveness.location_from_point(point);
+        format!("{}_{}", region_name(region), location_name(location))
+    };
+
+    // The mermaid chart type: a top-down flowchart, which supports subgraphs.
+    writeln!(out, "flowchart TD")?;
+
+    // The loans subgraph: a node per loan.
+    writeln!(out, "    subgraph \"Loans\"")?;
+    for loan_idx in 0..borrow_set.len() {
+        writeln!(out, "        L{loan_idx}")?;
+    }
+    writeln!(out, "    end\n")?;
+
+    // And an edge from that loan node to where it enters the constraint graph.
+    for (loan_idx, loan) in borrow_set.iter_enumerated() {
+        writeln!(
+            out,
+            "    L{} --> {}_{}",
+            loan_idx.index(),
+            region_name(loan.region),
+            location_name(loan.reserve_location),
+        )?;
+    }
+    writeln!(out, "")?;
+
+    // The regions subgraphs containing the region/point nodes.
+    let mut points_per_region: FxIndexMap<RegionVid, FxIndexSet<PointIndex>> =
+        FxIndexMap::default();
+    for constraint in &localized_outlives_constraints.outlives {
+        points_per_region.entry(constraint.source).or_default().insert(constraint.from);
+        points_per_region.entry(constraint.target).or_default().insert(constraint.to);
+    }
+    for (region, points) in points_per_region {
+        writeln!(out, "    subgraph \"{}\"", region_name(region))?;
+        for point in points {
+            writeln!(out, "        {}", node_name(region, point))?;
+        }
+        writeln!(out, "    end\n")?;
+    }
+
+    // The constraint graph edges.
+    for constraint in &localized_outlives_constraints.outlives {
+        // FIXME: add killed loans and constraint kind as edge labels.
+        writeln!(
+            out,
+            "    {} --> {}",
+            node_name(constraint.source, constraint.from),
+            node_name(constraint.target, constraint.to),
+        )?;
+    }
+
+    // Return the number of edges: this is the biggest graph in the dump and its edge count will be
+    // mermaid's max edge count to support.
+    let edge_count = borrow_set.len() + localized_outlives_constraints.outlives.len();
+    Ok(edge_count)
+}
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 5062cf55bb9..eb5b345e49e 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -651,7 +651,7 @@ fn expand_preparsed_asm(
             .map(|span| template_span.from_inner(InnerSpan::new(span.start, span.end)));
         for piece in unverified_pieces {
             match piece {
-                parse::Piece::String(s) => {
+                parse::Piece::Lit(s) => {
                     template.push(ast::InlineAsmTemplatePiece::String(s.to_string().into()))
                 }
                 parse::Piece::NextArgument(arg) => {
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 5202fe26c40..a0ab6375a66 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -406,7 +406,7 @@ fn make_format_args(
 
     for piece in &pieces {
         match *piece {
-            parse::Piece::String(s) => {
+            parse::Piece::Lit(s) => {
                 unfinished_literal.push_str(s);
             }
             parse::Piece::NextArgument(box parse::Argument { position, position_span, format }) => {
diff --git a/compiler/rustc_codegen_gcc/src/gcc_util.rs b/compiler/rustc_codegen_gcc/src/gcc_util.rs
index 560aff43d65..4e8c8aaaf5c 100644
--- a/compiler/rustc_codegen_gcc/src/gcc_util.rs
+++ b/compiler/rustc_codegen_gcc/src/gcc_util.rs
@@ -1,10 +1,8 @@
-use std::iter::FromIterator;
-
 #[cfg(feature = "master")]
 use gccjit::Context;
 use rustc_codegen_ssa::codegen_attrs::check_tied_features;
 use rustc_codegen_ssa::errors::TargetFeatureDisableOrEnable;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+use rustc_data_structures::fx::FxHashMap;
 use rustc_data_structures::unord::UnordSet;
 use rustc_session::Session;
 use rustc_target::target_features::RUSTC_SPECIFIC_FEATURES;
@@ -45,12 +43,6 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
     let known_features = sess.target.rust_target_features();
     let mut featsmap = FxHashMap::default();
 
-    // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
-    // are disabled.
-    let abi_feature_constraints = sess.target.abi_required_features();
-    let abi_incompatible_set =
-        FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
-
     // Compute implied features
     let mut all_rust_features = vec![];
     for feature in sess.opts.cg.target_feature.split(',') {
@@ -117,51 +109,11 @@ pub(crate) fn global_gcc_features(sess: &Session, diagnostics: bool) -> Vec<Stri
                 }
             }
 
-            // Ensure that the features we enable/disable are compatible with the ABI.
-            if enable {
-                if abi_incompatible_set.contains(feature) {
-                    sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                        feature,
-                        enabled: "enabled",
-                        reason: "this feature is incompatible with the target ABI",
-                    });
-                }
-            } else {
-                // FIXME: we have to request implied features here since
-                // negative features do not handle implied features above.
-                for &required in abi_feature_constraints.required.iter() {
-                    let implied = sess.target.implied_target_features(std::iter::once(required));
-                    if implied.contains(feature) {
-                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                            feature,
-                            enabled: "disabled",
-                            reason: "this feature is required by the target ABI",
-                        });
-                    }
-                }
-            }
-
             // FIXME(nagisa): figure out how to not allocate a full hashset here.
             featsmap.insert(feature, enable);
         }
     }
 
-    // To be sure the ABI-relevant features are all in the right state, we explicitly
-    // (un)set them here. This means if the target spec sets those features wrong,
-    // we will silently correct them rather than silently producing wrong code.
-    // (The target sanity check tries to catch this, but we can't know which features are
-    // enabled in GCC by default so we can't be fully sure about that check.)
-    // We add these at the beginning of the list so that `-Ctarget-features` can
-    // still override it... that's unsound, but more compatible with past behavior.
-    all_rust_features.splice(
-        0..0,
-        abi_feature_constraints
-            .required
-            .iter()
-            .map(|&f| (true, f))
-            .chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
-    );
-
     // Translate this into GCC features.
     let feats =
         all_rust_features.iter().flat_map(|&(enable, feature)| {
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 38019faa7a9..ce88ac39021 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -493,9 +493,10 @@ fn target_features_cfg(
     sess.target
         .rust_target_features()
         .iter()
-        .filter(|&&(_, gate, _)| gate.in_cfg())
         .filter_map(|&(feature, gate, _)| {
-            if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
+            if allow_unstable
+                || (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
+            {
                 Some(feature)
             } else {
                 None
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index c3d7c217861..53611c746a7 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -319,7 +319,6 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
         sess.target
             .rust_target_features()
             .iter()
-            .filter(|(_, gate, _)| gate.in_cfg())
             .filter(|(feature, _, _)| {
                 // skip checking special features, as LLVM may not understand them
                 if RUSTC_SPECIAL_FEATURES.contains(feature) {
@@ -388,9 +387,13 @@ pub fn target_features_cfg(sess: &Session, allow_unstable: bool) -> Vec<Symbol>
     sess.target
         .rust_target_features()
         .iter()
-        .filter(|(_, gate, _)| gate.in_cfg())
         .filter_map(|(feature, gate, _)| {
-            if sess.is_nightly_build() || allow_unstable || gate.requires_nightly().is_none() {
+            // The `allow_unstable` set is used by rustc internally to determined which target
+            // features are truly available, so we want to return even perma-unstable "forbidden"
+            // features.
+            if allow_unstable
+                || (gate.in_cfg() && (sess.is_nightly_build() || gate.requires_nightly().is_none()))
+            {
                 Some(*feature)
             } else {
                 None
@@ -670,12 +673,6 @@ pub(crate) fn global_llvm_features(
         // Will only be filled when `diagnostics` is set!
         let mut featsmap = FxHashMap::default();
 
-        // Ensure that all ABI-required features are enabled, and the ABI-forbidden ones
-        // are disabled.
-        let abi_feature_constraints = sess.target.abi_required_features();
-        let abi_incompatible_set =
-            FxHashSet::from_iter(abi_feature_constraints.incompatible.iter().copied());
-
         // Compute implied features
         let mut all_rust_features = vec![];
         for feature in sess.opts.cg.target_feature.split(',') {
@@ -746,52 +743,11 @@ pub(crate) fn global_llvm_features(
                     }
                 }
 
-                // Ensure that the features we enable/disable are compatible with the ABI.
-                if enable {
-                    if abi_incompatible_set.contains(feature) {
-                        sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                            feature,
-                            enabled: "enabled",
-                            reason: "this feature is incompatible with the target ABI",
-                        });
-                    }
-                } else {
-                    // FIXME: we have to request implied features here since
-                    // negative features do not handle implied features above.
-                    for &required in abi_feature_constraints.required.iter() {
-                        let implied =
-                            sess.target.implied_target_features(std::iter::once(required));
-                        if implied.contains(feature) {
-                            sess.dcx().emit_warn(ForbiddenCTargetFeature {
-                                feature,
-                                enabled: "disabled",
-                                reason: "this feature is required by the target ABI",
-                            });
-                        }
-                    }
-                }
-
                 // FIXME(nagisa): figure out how to not allocate a full hashset here.
                 featsmap.insert(feature, enable);
             }
         }
 
-        // To be sure the ABI-relevant features are all in the right state, we explicitly
-        // (un)set them here. This means if the target spec sets those features wrong,
-        // we will silently correct them rather than silently producing wrong code.
-        // (The target sanity check tries to catch this, but we can't know which features are
-        // enabled in LLVM by default so we can't be fully sure about that check.)
-        // We add these at the beginning of the list so that `-Ctarget-features` can
-        // still override it... that's unsound, but more compatible with past behavior.
-        all_rust_features.splice(
-            0..0,
-            abi_feature_constraints
-                .required
-                .iter()
-                .map(|&f| (true, f))
-                .chain(abi_feature_constraints.incompatible.iter().map(|&f| (false, f))),
-        );
-
         // Translate this into LLVM features.
         let feats = all_rust_features
             .iter()
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index cfdfbdb7880..6a339d69542 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -21,9 +21,10 @@ use super::error::*;
 use crate::errors::{LongRunning, LongRunningWarn};
 use crate::fluent_generated as fluent;
 use crate::interpret::{
-    self, AllocId, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame, GlobalAlloc, ImmTy,
-    InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar, compile_time_machine, interp_ok,
-    throw_exhaust, throw_inval, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
+    self, AllocId, AllocInit, AllocRange, ConstAllocation, CtfeProvenance, FnArg, Frame,
+    GlobalAlloc, ImmTy, InterpCx, InterpResult, MPlaceTy, OpTy, RangeSet, Scalar,
+    compile_time_machine, interp_ok, throw_exhaust, throw_inval, throw_ub, throw_ub_custom,
+    throw_unsup, throw_unsup_format,
 };
 
 /// When hitting this many interpreted terminators we emit a deny by default lint
@@ -420,6 +421,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> {
                     Size::from_bytes(size),
                     align,
                     interpret::MemoryKind::Machine(MemoryKind::Heap),
+                    AllocInit::Uninit,
                 )?;
                 ecx.write_pointer(ptr, dest)?;
             }
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index 2772c94d52b..4f4b6785844 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -20,10 +20,10 @@ use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
 use tracing::{debug, instrument, trace};
 
 use super::{
-    AllocBytes, AllocId, AllocMap, AllocRange, Allocation, CheckAlignMsg, CheckInAllocMsg,
-    CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak, Misalignment, Pointer,
-    PointerArithmetic, Provenance, Scalar, alloc_range, err_ub, err_ub_custom, interp_ok, throw_ub,
-    throw_ub_custom, throw_unsup, throw_unsup_format,
+    AllocBytes, AllocId, AllocInit, AllocMap, AllocRange, Allocation, CheckAlignMsg,
+    CheckInAllocMsg, CtfeProvenance, GlobalAlloc, InterpCx, InterpResult, Machine, MayLeak,
+    Misalignment, Pointer, PointerArithmetic, Provenance, Scalar, alloc_range, err_ub,
+    err_ub_custom, interp_ok, throw_ub, throw_ub_custom, throw_unsup, throw_unsup_format,
 };
 use crate::fluent_generated as fluent;
 
@@ -230,11 +230,12 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         size: Size,
         align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        init: AllocInit,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let alloc = if M::PANIC_ON_ALLOC_FAIL {
-            Allocation::uninit(size, align)
+            Allocation::new(size, align, init)
         } else {
-            Allocation::try_uninit(size, align)?
+            Allocation::try_new(size, align, init)?
         };
         self.insert_allocation(alloc, kind)
     }
@@ -270,6 +271,8 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         M::adjust_alloc_root_pointer(self, Pointer::from(id), Some(kind))
     }
 
+    /// If this grows the allocation, `init_growth` determines
+    /// whether the additional space will be initialized.
     pub fn reallocate_ptr(
         &mut self,
         ptr: Pointer<Option<M::Provenance>>,
@@ -277,6 +280,7 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
         new_size: Size,
         new_align: Align,
         kind: MemoryKind<M::MemoryKind>,
+        init_growth: AllocInit,
     ) -> InterpResult<'tcx, Pointer<M::Provenance>> {
         let (alloc_id, offset, _prov) = self.ptr_get_alloc_id(ptr, 0)?;
         if offset.bytes() != 0 {
@@ -289,7 +293,10 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
 
         // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc".
         // This happens so rarely, the perf advantage is outweighed by the maintenance cost.
-        let new_ptr = self.allocate_ptr(new_size, new_align, kind)?;
+        // If requested, we zero-init the entire allocation, to ensure that a growing
+        // allocation has its new bytes properly set. For the part that is copied,
+        // `mem_copy` below will de-initialize things as necessary.
+        let new_ptr = self.allocate_ptr(new_size, new_align, kind, init_growth)?;
         let old_size = match old_size_and_align {
             Some((size, _align)) => size,
             None => self.get_alloc_raw(alloc_id)?.size(),
@@ -830,9 +837,11 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
     /// [`InterpCx::get_alloc_info`] if all you need to check is whether the kind is
     /// [`AllocKind::Dead`] because it doesn't have to look up the type and layout of statics.
     pub fn is_alloc_live(&self, id: AllocId) -> bool {
-        self.tcx.try_get_global_alloc(id).is_some()
-            || self.memory.alloc_map.contains_key_ref(&id)
+        self.memory.alloc_map.contains_key_ref(&id)
             || self.memory.extra_fn_ptr_map.contains_key(&id)
+            // We check `tcx` last as that has to acquire a lock in `many-seeds` mode.
+            // This also matches the order in `get_alloc_info`.
+            || self.tcx.try_get_global_alloc(id).is_some()
     }
 
     /// Obtain the size and alignment of an allocation, even if that allocation has
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index c97922ac132..f5d3de7b1b2 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -12,9 +12,9 @@ use rustc_middle::{bug, mir, span_bug};
 use tracing::{instrument, trace};
 
 use super::{
-    AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx, InterpResult,
-    Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer, Projectable, Provenance,
-    Scalar, alloc_range, interp_ok, mir_assign_valid_types,
+    AllocInit, AllocRef, AllocRefMut, CheckAlignMsg, CtfeProvenance, ImmTy, Immediate, InterpCx,
+    InterpResult, Machine, MemoryKind, Misalignment, OffsetMode, OpTy, Operand, Pointer,
+    Projectable, Provenance, Scalar, alloc_range, interp_ok, mir_assign_valid_types,
 };
 
 #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)]
@@ -983,7 +983,7 @@ where
         let Some((size, align)) = self.size_and_align_of(&meta, &layout)? else {
             span_bug!(self.cur_span(), "cannot allocate space for `extern` type, size is not known")
         };
-        let ptr = self.allocate_ptr(size, align, kind)?;
+        let ptr = self.allocate_ptr(size, align, kind, AllocInit::Uninit)?;
         interp_ok(self.ptr_with_meta_to_mplace(ptr.into(), meta, layout, /*unaligned*/ false))
     }
 
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index ecb7c3fc93c..eb98e3b5380 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -2,7 +2,7 @@ use std::ops::ControlFlow;
 
 use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir;
-use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer};
+use rustc_middle::mir::interpret::{AllocInit, Allocation, InterpResult, Pointer};
 use rustc_middle::ty::layout::TyAndLayout;
 use rustc_middle::ty::{
     self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor,
@@ -76,7 +76,7 @@ pub(crate) fn create_static_alloc<'tcx>(
     static_def_id: LocalDefId,
     layout: TyAndLayout<'tcx>,
 ) -> InterpResult<'tcx, MPlaceTy<'tcx>> {
-    let alloc = Allocation::try_uninit(layout.size, layout.align.abi)?;
+    let alloc = Allocation::try_new(layout.size, layout.align.abi, AllocInit::Uninit)?;
     let alloc_id = ecx.tcx.reserve_and_set_static_alloc(static_def_id.into());
     assert_eq!(ecx.machine.static_root_ids, None);
     ecx.machine.static_root_ids = Some((alloc_id, static_def_id));
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 20be2144609..c9d38a0f932 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -160,7 +160,7 @@ pub trait Callbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &interface::Compiler,
-        _queries: &ast::Crate,
+        _krate: &mut ast::Crate,
     ) -> Compilation {
         Compilation::Continue
     }
@@ -311,7 +311,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
 
         // Parse the crate root source code (doesn't parse submodules yet)
         // Everything else is parsed during macro expansion.
-        let krate = passes::parse(sess);
+        let mut krate = passes::parse(sess);
 
         // If pretty printing is requested: Figure out the representation, print it and exit
         if let Some(pp_mode) = sess.opts.pretty {
@@ -328,7 +328,7 @@ pub fn run_compiler(at_args: &[String], callbacks: &mut (dyn Callbacks + Send))
             return early_exit();
         }
 
-        if callbacks.after_crate_root_parsing(compiler, &krate) == Compilation::Stop {
+        if callbacks.after_crate_root_parsing(compiler, &mut krate) == Compilation::Stop {
             return early_exit();
         }
 
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index a396d705cbb..af2f86b67e0 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -1437,7 +1437,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => true,
+            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => true,
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_short_(it),
             Struct(_, fields, _) => fields.iter().all(|field| field.pat.walk_short_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().all(|p| p.walk_short_(it)),
@@ -1464,7 +1464,7 @@ impl<'hir> Pat<'hir> {
 
         use PatKind::*;
         match self.kind {
-            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Path(_) | Err(_) => {}
+            Wild | Never | Expr(_) | Range(..) | Binding(.., None) | Err(_) => {}
             Box(s) | Deref(s) | Ref(s, _) | Binding(.., Some(s)) | Guard(s, _) => s.walk_(it),
             Struct(_, fields, _) => fields.iter().for_each(|field| field.pat.walk_(it)),
             TupleStruct(_, s, _) | Tuple(s, _) | Or(s) => s.iter().for_each(|p| p.walk_(it)),
@@ -1618,9 +1618,6 @@ pub enum PatKind<'hir> {
     /// A never pattern `!`.
     Never,
 
-    /// A path pattern for a unit struct/variant or a (maybe-associated) constant.
-    Path(QPath<'hir>),
-
     /// A tuple pattern (e.g., `(a, b)`).
     /// If the `..` pattern fragment is present, then `Option<usize>` denotes its position.
     /// `0 <= position <= subpats.len()`
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index b0d80d0f809..31764ab1209 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -709,9 +709,6 @@ pub fn walk_pat<'v, V: Visitor<'v>>(visitor: &mut V, pattern: &'v Pat<'v>) -> V:
             try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
             walk_list!(visitor, visit_pat, children);
         }
-        PatKind::Path(ref qpath) => {
-            try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
-        }
         PatKind::Struct(ref qpath, fields, _) => {
             try_visit!(visitor.visit_qpath(qpath, pattern.hir_id, pattern.span));
             walk_list!(visitor, visit_pat_field, fields);
diff --git a/compiler/rustc_hir/src/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs
index bb853985c7d..8dd1e4e8292 100644
--- a/compiler/rustc_hir/src/pat_util.rs
+++ b/compiler/rustc_hir/src/pat_util.rs
@@ -105,7 +105,10 @@ impl hir::Pat<'_> {
         let mut variants = vec![];
         self.walk(|p| match &p.kind {
             PatKind::Or(_) => false,
-            PatKind::Path(hir::QPath::Resolved(_, path))
+            PatKind::Expr(hir::PatExpr {
+                kind: hir::PatExprKind::Path(hir::QPath::Resolved(_, path)),
+                ..
+            })
             | PatKind::TupleStruct(hir::QPath::Resolved(_, path), ..)
             | PatKind::Struct(hir::QPath::Resolved(_, path), ..) => {
                 if let Res::Def(DefKind::Variant | DefKind::Ctor(CtorOf::Variant, ..), id) =
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 69b4aa47eba..cc0b7fdd8dd 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -457,7 +457,7 @@ fn fn_sig_suggestion<'tcx>(
 
     let asyncness = if tcx.asyncness(assoc.def_id).is_async() {
         output = if let ty::Alias(_, alias_ty) = *output.kind() {
-            tcx.explicit_item_super_predicates(alias_ty.def_id)
+            tcx.explicit_item_self_bounds(alias_ty.def_id)
                 .iter_instantiated_copied(tcx, alias_ty.args)
                 .find_map(|(bound, _)| {
                     bound.as_projection_clause()?.no_bound_vars()?.term.as_type()
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index 83c69dc2ef4..d43c65c0023 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -703,7 +703,6 @@ fn resolve_local<'tcx>(
             | PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
             | PatKind::Wild
             | PatKind::Never
-            | PatKind::Path(_)
             | PatKind::Expr(_)
             | PatKind::Range(_, _, _)
             | PatKind::Err(_) => false,
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index 447050ea7d2..cad7b2a1e57 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -65,9 +65,9 @@ pub fn provide(providers: &mut Providers) {
         type_alias_is_lazy: type_of::type_alias_is_lazy,
         item_bounds: item_bounds::item_bounds,
         explicit_item_bounds: item_bounds::explicit_item_bounds,
-        item_super_predicates: item_bounds::item_super_predicates,
-        explicit_item_super_predicates: item_bounds::explicit_item_super_predicates,
-        item_non_self_assumptions: item_bounds::item_non_self_assumptions,
+        item_self_bounds: item_bounds::item_self_bounds,
+        explicit_item_self_bounds: item_bounds::explicit_item_self_bounds,
+        item_non_self_bounds: item_bounds::item_non_self_bounds,
         impl_super_outlives: item_bounds::impl_super_outlives,
         generics_of: generics_of::generics_of,
         predicates_of: predicates_of::predicates_of,
@@ -328,9 +328,9 @@ impl<'tcx> Visitor<'tcx> for CollectItemTypesVisitor<'tcx> {
         self.tcx.ensure().generics_of(def_id);
         self.tcx.ensure().predicates_of(def_id);
         self.tcx.ensure().explicit_item_bounds(def_id);
-        self.tcx.ensure().explicit_item_super_predicates(def_id);
+        self.tcx.ensure().explicit_item_self_bounds(def_id);
         self.tcx.ensure().item_bounds(def_id);
-        self.tcx.ensure().item_super_predicates(def_id);
+        self.tcx.ensure().item_self_bounds(def_id);
         if self.tcx.is_conditionally_const(def_id) {
             self.tcx.ensure().explicit_implied_const_bounds(def_id);
             self.tcx.ensure().const_conditions(def_id);
@@ -822,7 +822,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 
         hir::TraitItemKind::Type(_, Some(_)) => {
             tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_super_predicates(def_id);
+            tcx.ensure().item_self_bounds(def_id);
             tcx.ensure().type_of(def_id);
             // Account for `type T = _;`.
             let mut visitor = HirPlaceholderCollector::default();
@@ -839,7 +839,7 @@ fn lower_trait_item(tcx: TyCtxt<'_>, trait_item_id: hir::TraitItemId) {
 
         hir::TraitItemKind::Type(_, None) => {
             tcx.ensure().item_bounds(def_id);
-            tcx.ensure().item_super_predicates(def_id);
+            tcx.ensure().item_self_bounds(def_id);
             // #74612: Visit and try to find bad placeholders
             // even if there is no concrete type.
             let mut visitor = HirPlaceholderCollector::default();
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index d3ff1f7bebe..e37a11b6844 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -350,7 +350,7 @@ pub(super) fn explicit_item_bounds(
     explicit_item_bounds_with_filter(tcx, def_id, PredicateFilter::All)
 }
 
-pub(super) fn explicit_item_super_predicates(
+pub(super) fn explicit_item_self_bounds(
     tcx: TyCtxt<'_>,
     def_id: LocalDefId,
 ) -> ty::EarlyBinder<'_, &'_ [(ty::Clause<'_>, Span)]> {
@@ -434,11 +434,11 @@ pub(super) fn item_bounds(tcx: TyCtxt<'_>, def_id: DefId) -> ty::EarlyBinder<'_,
     })
 }
 
-pub(super) fn item_super_predicates(
+pub(super) fn item_self_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
-    tcx.explicit_item_super_predicates(def_id).map_bound(|bounds| {
+    tcx.explicit_item_self_bounds(def_id).map_bound(|bounds| {
         tcx.mk_clauses_from_iter(
             util::elaborate(tcx, bounds.iter().map(|&(bound, _span)| bound)).filter_only_self(),
         )
@@ -447,13 +447,12 @@ pub(super) fn item_super_predicates(
 
 /// This exists as an optimization to compute only the item bounds of the item
 /// that are not `Self` bounds.
-pub(super) fn item_non_self_assumptions(
+pub(super) fn item_non_self_bounds(
     tcx: TyCtxt<'_>,
     def_id: DefId,
 ) -> ty::EarlyBinder<'_, ty::Clauses<'_>> {
     let all_bounds: FxIndexSet<_> = tcx.item_bounds(def_id).skip_binder().iter().collect();
-    let own_bounds: FxIndexSet<_> =
-        tcx.item_super_predicates(def_id).skip_binder().iter().collect();
+    let own_bounds: FxIndexSet<_> = tcx.item_self_bounds(def_id).skip_binder().iter().collect();
     if all_bounds.len() == own_bounds.len() {
         ty::EarlyBinder::bind(ty::ListWithCachedTypeInfo::empty())
     } else {
diff --git a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
index 539c5f6a20a..44f7a035a10 100644
--- a/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
+++ b/compiler/rustc_hir_analysis/src/hir_ty_lowering/lint.rs
@@ -41,8 +41,8 @@ impl<'tcx> dyn HirTyLowerer<'tcx> + '_ {
                 kind: hir::ExprKind::Path(hir::QPath::TypeRelative(qself, _)),
                 ..
             })
-            | hir::Node::Pat(hir::Pat {
-                kind: hir::PatKind::Path(hir::QPath::TypeRelative(qself, _)),
+            | hir::Node::PatExpr(hir::PatExpr {
+                kind: hir::PatExprKind::Path(hir::QPath::TypeRelative(qself, _)),
                 ..
             }) if qself.hir_id == self_ty.hir_id => true,
             _ => false,
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index afc0f627f69..a91afa51230 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1906,9 +1906,6 @@ impl<'a> State<'a> {
                 }
                 self.pclose();
             }
-            PatKind::Path(ref qpath) => {
-                self.print_qpath(qpath, true);
-            }
             PatKind::Struct(ref qpath, fields, etc) => {
                 self.print_qpath(qpath, true);
                 self.nbsp();
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 4dcc83d0aef..62dfffb560b 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -308,7 +308,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     expected_ty,
                     closure_kind,
                     self.tcx
-                        .explicit_item_super_predicates(def_id)
+                        .explicit_item_self_bounds(def_id)
                         .iter_instantiated_copied(self.tcx, args)
                         .map(|(c, s)| (c.as_predicate(), s)),
                 ),
@@ -1019,7 +1019,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             }
             ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
                 .tcx
-                .explicit_item_super_predicates(def_id)
+                .explicit_item_self_bounds(def_id)
                 .iter_instantiated_copied(self.tcx, args)
                 .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?,
             ty::Error(_) => return Some(ret_ty),
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 47abba1cc29..153fd6001bb 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1847,30 +1847,26 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             fcx.probe(|_| {
                 let ocx = ObligationCtxt::new(fcx);
                 ocx.register_obligations(
-                    fcx.tcx.item_super_predicates(rpit_def_id).iter_identity().filter_map(
-                        |clause| {
-                            let predicate = clause
-                                .kind()
-                                .map_bound(|clause| match clause {
-                                    ty::ClauseKind::Trait(trait_pred) => Some(
-                                        ty::ClauseKind::Trait(trait_pred.with_self_ty(fcx.tcx, ty)),
-                                    ),
-                                    ty::ClauseKind::Projection(proj_pred) => {
-                                        Some(ty::ClauseKind::Projection(
-                                            proj_pred.with_self_ty(fcx.tcx, ty),
-                                        ))
-                                    }
-                                    _ => None,
-                                })
-                                .transpose()?;
-                            Some(Obligation::new(
-                                fcx.tcx,
-                                ObligationCause::dummy(),
-                                fcx.param_env,
-                                predicate,
-                            ))
-                        },
-                    ),
+                    fcx.tcx.item_self_bounds(rpit_def_id).iter_identity().filter_map(|clause| {
+                        let predicate = clause
+                            .kind()
+                            .map_bound(|clause| match clause {
+                                ty::ClauseKind::Trait(trait_pred) => Some(ty::ClauseKind::Trait(
+                                    trait_pred.with_self_ty(fcx.tcx, ty),
+                                )),
+                                ty::ClauseKind::Projection(proj_pred) => Some(
+                                    ty::ClauseKind::Projection(proj_pred.with_self_ty(fcx.tcx, ty)),
+                                ),
+                                _ => None,
+                            })
+                            .transpose()?;
+                        Some(Obligation::new(
+                            fcx.tcx,
+                            ObligationCause::dummy(),
+                            fcx.param_env,
+                            predicate,
+                        ))
+                    }),
                 );
                 ocx.select_where_possible().is_empty()
             })
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 1c828591bcb..f79667e59ba 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -480,7 +480,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             hir::PatKind::Binding(_, _, _, _)
             | hir::PatKind::Struct(_, _, _)
             | hir::PatKind::TupleStruct(_, _, _)
-            | hir::PatKind::Path(_)
             | hir::PatKind::Tuple(_, _)
             | hir::PatKind::Box(_)
             | hir::PatKind::Ref(_, _)
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index 1f48b703e4a..d37c68f82fb 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -11,10 +11,9 @@ use hir::def::DefKind;
 use hir::pat_util::EnumerateAndAdjustIterator as _;
 use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
 use rustc_data_structures::fx::FxIndexMap;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, Res};
 use rustc_hir::def_id::LocalDefId;
-use rustc_hir::{HirId, PatKind};
+use rustc_hir::{self as hir, HirId, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::place::ProjectionKind;
 // Export these here so that Clippy can use them.
@@ -564,11 +563,11 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                         // FIXME(never_patterns): does this do what I expect?
                         needs_to_be_read = true;
                     }
-                    PatKind::Path(qpath) => {
+                    PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, span }) => {
                         // A `Path` pattern is just a name like `Foo`. This is either a
                         // named constant or else it refers to an ADT variant
 
-                        let res = self.cx.typeck_results().qpath_res(qpath, pat.hir_id);
+                        let res = self.cx.typeck_results().qpath_res(qpath, *hir_id);
                         match res {
                             Res::Def(DefKind::Const, _) | Res::Def(DefKind::AssocConst, _) => {
                                 // Named constants have to be equated with the value
@@ -581,7 +580,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                                 // Otherwise, this is a struct/enum variant, and so it's
                                 // only a read if we need to read the discriminant.
                                 needs_to_be_read |=
-                                    self.is_multivariant_adt(place.place.ty(), pat.span);
+                                    self.is_multivariant_adt(place.place.ty(), *span);
                             }
                         }
                     }
@@ -1801,8 +1800,7 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
                 }
             }
 
-            PatKind::Path(_)
-            | PatKind::Binding(.., None)
+            PatKind::Binding(.., None)
             | PatKind::Expr(..)
             | PatKind::Range(..)
             | PatKind::Never
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 928010c03c2..aea2e0fd3a3 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -5,12 +5,12 @@ use hir::def_id::LocalDefId;
 use rustc_ast::util::parser::ExprPrecedence;
 use rustc_data_structures::packed::Pu128;
 use rustc_errors::{Applicability, Diag, MultiSpan};
-use rustc_hir as hir;
 use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
-    Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind, GenericBound, HirId,
-    Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicateKind, expr_needs_parens,
+    self as hir, Arm, CoroutineDesugaring, CoroutineKind, CoroutineSource, Expr, ExprKind,
+    GenericBound, HirId, Node, PatExpr, PatExprKind, Path, QPath, Stmt, StmtKind, TyKind,
+    WherePredicateKind, expr_needs_parens,
 };
 use rustc_hir_analysis::collect::suggest_impl_trait;
 use rustc_hir_analysis::hir_ty_lowering::HirTyLowerer;
@@ -1422,8 +1422,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // since the user probably just misunderstood how `let else`
         // and `&&` work together.
         if let Some((_, hir::Node::LetStmt(local))) = cond_parent
-            && let hir::PatKind::Path(qpath) | hir::PatKind::TupleStruct(qpath, _, _) =
-                &local.pat.kind
+            && let hir::PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+            | hir::PatKind::TupleStruct(qpath, _, _) = &local.pat.kind
             && let hir::QPath::Resolved(None, path) = qpath
             && let Some(did) = path
                 .res
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 5d4e67d1a0e..e4a6a0fedc5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -177,8 +177,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             })
             | hir::Node::Pat(&hir::Pat {
                 kind:
-                    hir::PatKind::Path(QPath::TypeRelative(rcvr, segment))
-                    | hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
+                    hir::PatKind::Struct(QPath::TypeRelative(rcvr, segment), ..)
                     | hir::PatKind::TupleStruct(QPath::TypeRelative(rcvr, segment), ..),
                 span,
                 ..
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index cbd1db2ca25..0aa2f1110fb 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -11,8 +11,8 @@ use rustc_errors::{
 use rustc_hir::def::{CtorKind, DefKind, Res};
 use rustc_hir::pat_util::EnumerateAndAdjustIterator;
 use rustc_hir::{
-    self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatKind,
-    expr_needs_parens,
+    self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
+    PatExprKind, PatKind, expr_needs_parens,
 };
 use rustc_infer::infer;
 use rustc_middle::traits::PatternOriginExpr;
@@ -312,9 +312,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     fn check_pat(&self, pat: &'tcx Pat<'tcx>, expected: Ty<'tcx>, pat_info: PatInfo<'_, 'tcx>) {
         let PatInfo { binding_mode, max_ref_mutbl, top_info: ti, current_depth, .. } = pat_info;
 
-        let path_res = match &pat.kind {
-            PatKind::Path(qpath) => {
-                Some(self.resolve_ty_and_res_fully_qualified_call(qpath, pat.hir_id, pat.span))
+        let path_res = match pat.kind {
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
+                Some(self.resolve_ty_and_res_fully_qualified_call(qpath, *hir_id, *span))
             }
             _ => None,
         };
@@ -333,6 +333,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::Wild | PatKind::Err(_) => expected,
             // We allow any type here; we ensure that the type is uninhabited during match checking.
             PatKind::Never => expected,
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref qpath), hir_id, span }) => {
+                let ty = self.check_pat_path(
+                    *hir_id,
+                    pat.hir_id,
+                    *span,
+                    qpath,
+                    path_res.unwrap(),
+                    expected,
+                    ti,
+                );
+                self.write_ty(*hir_id, ty);
+                ty
+            }
             PatKind::Expr(lt) => self.check_pat_lit(pat.span, lt, expected, ti),
             PatKind::Range(lhs, rhs, _) => self.check_pat_range(pat.span, lhs, rhs, expected, ti),
             PatKind::Binding(ba, var_id, ident, sub) => {
@@ -341,9 +354,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             PatKind::TupleStruct(ref qpath, subpats, ddpos) => {
                 self.check_pat_tuple_struct(pat, qpath, subpats, ddpos, expected, pat_info)
             }
-            PatKind::Path(ref qpath) => {
-                self.check_pat_path(pat.hir_id, pat.span, qpath, path_res.unwrap(), expected, ti)
-            }
             PatKind::Struct(ref qpath, fields, has_rest_pat) => {
                 self.check_pat_struct(pat, qpath, fields, has_rest_pat, expected, pat_info)
             }
@@ -456,16 +466,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             | PatKind::Slice(..) => AdjustMode::Peel,
             // A never pattern behaves somewhat like a literal or unit variant.
             PatKind::Never => AdjustMode::Peel,
-            // String and byte-string literals result in types `&str` and `&[u8]` respectively.
-            // All other literals result in non-reference types.
-            // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
-            //
-            // Call `resolve_vars_if_possible` here for inline const blocks.
-            PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
-                ty::Ref(..) => AdjustMode::Pass,
-                _ => AdjustMode::Peel,
-            },
-            PatKind::Path(_) => match opt_path_res.unwrap() {
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(_), .. }) => match opt_path_res.unwrap() {
                 // These constants can be of a reference type, e.g. `const X: &u8 = &0;`.
                 // Peeling the reference types too early will cause type checking failures.
                 // Although it would be possible to *also* peel the types of the constants too.
@@ -476,6 +477,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // a reference type wherefore peeling doesn't give up any expressiveness.
                 _ => AdjustMode::Peel,
             },
+
+            // String and byte-string literals result in types `&str` and `&[u8]` respectively.
+            // All other literals result in non-reference types.
+            // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo" {}`.
+            //
+            // Call `resolve_vars_if_possible` here for inline const blocks.
+            PatKind::Expr(lt) => match self.resolve_vars_if_possible(self.check_pat_expr_unadjusted(lt)).kind() {
+                ty::Ref(..) => AdjustMode::Pass,
+                _ => AdjustMode::Peel,
+            },
+
             // Ref patterns are complicated, we handle them in `check_pat_ref`.
             PatKind::Ref(..) => AdjustMode::Pass,
             // A `_` pattern works with any expected type, so there's no need to do anything.
@@ -1001,7 +1013,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         PatKind::Wild
                         | PatKind::Never
                         | PatKind::Binding(..)
-                        | PatKind::Path(..)
                         | PatKind::Box(..)
                         | PatKind::Deref(_)
                         | PatKind::Ref(..)
@@ -1139,7 +1150,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     fn check_pat_path(
         &self,
-        hir_id: HirId,
+        path_id: HirId,
+        pat_id_for_diag: HirId,
         span: Span,
         qpath: &hir::QPath<'_>,
         path_resolution: (Res, Option<LoweredTy<'tcx>>, &'tcx [hir::PathSegment<'tcx>]),
@@ -1193,11 +1205,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         // Type-check the path.
         let (pat_ty, pat_res) =
-            self.instantiate_value_path(segments, opt_ty, res, span, span, hir_id);
+            self.instantiate_value_path(segments, opt_ty, res, span, span, path_id);
         if let Err(err) =
             self.demand_suptype_with_origin(&self.pattern_cause(ti, span), expected, pat_ty)
         {
-            self.emit_bad_pat_path(err, hir_id, span, res, pat_res, pat_ty, segments);
+            self.emit_bad_pat_path(err, pat_id_for_diag, span, res, pat_res, pat_ty, segments);
         }
         pat_ty
     }
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index ba635071135..e1bd9ae2e67 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -1,6 +1,7 @@
 use rustc_errors::Applicability;
 use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::infer::InferOk;
+use rustc_infer::traits::{Obligation, ObligationCauseCode};
 use rustc_middle::span_bug;
 use rustc_middle::ty::adjustment::{
     Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, OverloadedDeref,
@@ -136,8 +137,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             let mut self_ty = adjusted_ty;
             if unsize {
                 // We only unsize arrays here.
-                if let ty::Array(element_ty, _) = adjusted_ty.kind() {
-                    self_ty = Ty::new_slice(self.tcx, *element_ty);
+                if let ty::Array(element_ty, ct) = *adjusted_ty.kind() {
+                    self.register_predicate(Obligation::new(
+                        self.tcx,
+                        self.cause(base_expr.span, ObligationCauseCode::ArrayLen(adjusted_ty)),
+                        self.param_env,
+                        ty::ClauseKind::ConstArgHasType(ct, self.tcx.types.usize),
+                    ));
+                    self_ty = Ty::new_slice(self.tcx, element_ty);
                 } else {
                     continue;
                 }
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 7a21c2883d1..d68f3639176 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -281,7 +281,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         alias_ty: ty::AliasTy<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_super_predicates(alias_ty.def_id);
+        let bounds = tcx.item_self_bounds(alias_ty.def_id);
         trace!("{:#?}", bounds.skip_binder());
         bounds
             .iter_instantiated(tcx, alias_ty.args)
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 47dfbc1d7fb..31123625369 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -1,3 +1,8 @@
+interface_abi_required_feature =
+    target feature `{$feature}` must be {$enabled} to ensure that the ABI of the current target can be implemented correctly
+    .note = this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
+interface_abi_required_feature_issue = for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
+
 interface_cant_emit_mir =
     could not emit MIR: {$error}
 
diff --git a/compiler/rustc_interface/src/errors.rs b/compiler/rustc_interface/src/errors.rs
index 939980a932f..b62950d6709 100644
--- a/compiler/rustc_interface/src/errors.rs
+++ b/compiler/rustc_interface/src/errors.rs
@@ -103,3 +103,12 @@ pub struct IgnoringOutDir;
 #[derive(Diagnostic)]
 #[diag(interface_multiple_output_types_to_stdout)]
 pub struct MultipleOutputTypesToStdout;
+
+#[derive(Diagnostic)]
+#[diag(interface_abi_required_feature)]
+#[note]
+#[note(interface_abi_required_feature_issue)]
+pub(crate) struct AbiRequiredTargetFeature<'a> {
+    pub feature: &'a str,
+    pub enabled: &'a str,
+}
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index 2113345eda3..d9803236f85 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -492,6 +492,8 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
             }
             sess.lint_store = Some(Lrc::new(lint_store));
 
+            util::check_abi_required_features(&sess);
+
             let compiler = Compiler {
                 sess,
                 codegen_backend,
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 984b8104f53..e900ec14fca 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -18,21 +18,25 @@ use rustc_session::{EarlyDiagCtxt, Session, filesearch};
 use rustc_span::edit_distance::find_best_match_for_name;
 use rustc_span::edition::Edition;
 use rustc_span::source_map::SourceMapInputs;
-use rustc_span::sym;
+use rustc_span::{Symbol, sym};
 use rustc_target::spec::Target;
 use tracing::info;
 
 use crate::errors;
 
 /// Function pointer type that constructs a new CodegenBackend.
-pub type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
+type MakeBackendFn = fn() -> Box<dyn CodegenBackend>;
 
 /// Adds `target_feature = "..."` cfgs for a variety of platform
 /// specific features (SSE, NEON etc.).
 ///
 /// This is performed by checking whether a set of permitted features
 /// is available on the target machine, by querying the codegen backend.
-pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dyn CodegenBackend) {
+pub(crate) fn add_configuration(
+    cfg: &mut Cfg,
+    sess: &mut Session,
+    codegen_backend: &dyn CodegenBackend,
+) {
     let tf = sym::target_feature;
 
     let unstable_target_features = codegen_backend.target_features_cfg(sess, true);
@@ -48,6 +52,34 @@ pub fn add_configuration(cfg: &mut Cfg, sess: &mut Session, codegen_backend: &dy
     }
 }
 
+/// Ensures that all target features required by the ABI are present.
+/// Must be called after `unstable_target_features` has been populated!
+pub(crate) fn check_abi_required_features(sess: &Session) {
+    let abi_feature_constraints = sess.target.abi_required_features();
+    // We check this against `unstable_target_features` as that is conveniently already
+    // back-translated to rustc feature names, taking into account `-Ctarget-cpu` and `-Ctarget-feature`.
+    // Just double-check that the features we care about are actually on our list.
+    for feature in
+        abi_feature_constraints.required.iter().chain(abi_feature_constraints.incompatible.iter())
+    {
+        assert!(
+            sess.target.rust_target_features().iter().any(|(name, ..)| feature == name),
+            "target feature {feature} is required/incompatible for the current ABI but not a recognized feature for this target"
+        );
+    }
+
+    for feature in abi_feature_constraints.required {
+        if !sess.unstable_target_features.contains(&Symbol::intern(feature)) {
+            sess.dcx().emit_warn(errors::AbiRequiredTargetFeature { feature, enabled: "enabled" });
+        }
+    }
+    for feature in abi_feature_constraints.incompatible {
+        if sess.unstable_target_features.contains(&Symbol::intern(feature)) {
+            sess.dcx().emit_warn(errors::AbiRequiredTargetFeature { feature, enabled: "disabled" });
+        }
+    }
+}
+
 pub static STACK_SIZE: OnceLock<usize> = OnceLock::new();
 pub const DEFAULT_STACK_SIZE: usize = 8 * 1024 * 1024;
 
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index c03de687a33..e8a4e9a84c4 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -330,10 +330,12 @@ impl EarlyLintPass for UnsafeCode {
         if let FnKind::Fn(
             ctxt,
             _,
-            ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
             _,
-            _,
-            body,
+            ast::Fn {
+                sig: ast::FnSig { header: ast::FnHeader { safety: ast::Safety::Unsafe(_), .. }, .. },
+                body,
+                ..
+            },
         ) = fk
         {
             let decorator = match ctxt {
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 166ff60f7e1..546df4497ad 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::{
     AmbigArg, BinOp, BinOpKind, Expr, ExprKind, GenericArg, HirId, Impl, Item, ItemKind, Node, Pat,
-    PatKind, Path, PathSegment, QPath, Ty, TyKind,
+    PatExpr, PatExprKind, PatKind, Path, PathSegment, QPath, Ty, TyKind,
 };
 use rustc_middle::ty::{self, GenericArgsRef, Ty as MiddleTy};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -164,11 +164,9 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind {
             TyKind::Path(QPath::Resolved(_, path)) => {
                 if lint_ty_kind_usage(cx, &path.res) {
                     let span = match cx.tcx.parent_hir_node(ty.hir_id) {
-                        Node::Pat(Pat {
-                            kind:
-                                PatKind::Path(qpath)
-                                | PatKind::TupleStruct(qpath, ..)
-                                | PatKind::Struct(qpath, ..),
+                        Node::PatExpr(PatExpr { kind: PatExprKind::Path(qpath), .. })
+                        | Node::Pat(Pat {
+                            kind: PatKind::TupleStruct(qpath, ..) | PatKind::Struct(qpath, ..),
                             ..
                         })
                         | Node::Expr(
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index e09049f322f..0c180ab9570 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -1,7 +1,7 @@
 use rustc_abi::ExternAbi;
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::intravisit::FnKind;
-use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatKind};
+use rustc_hir::{AttrArgs, AttrItem, AttrKind, GenericParamKind, PatExprKind, PatKind};
 use rustc_middle::ty;
 use rustc_session::config::CrateType;
 use rustc_session::{declare_lint, declare_lint_pass};
@@ -527,7 +527,11 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
 
     fn check_pat(&mut self, cx: &LateContext<'_>, p: &hir::Pat<'_>) {
         // Lint for constants that look like binding identifiers (#7526)
-        if let PatKind::Path(hir::QPath::Resolved(None, path)) = p.kind {
+        if let PatKind::Expr(hir::PatExpr {
+            kind: PatExprKind::Path(hir::QPath::Resolved(None, path)),
+            ..
+        }) = p.kind
+        {
             if let Res::Def(DefKind::Const, _) = path.res {
                 if let [segment] = path.segments {
                     NonUpperCaseGlobals::check_upper_case(
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 3059adb3fda..5696fcaed13 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -289,25 +289,22 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
                 }
                 ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
                 ty::Alias(ty::Opaque | ty::Projection, ty::AliasTy { def_id: def, .. }) => {
-                    elaborate(
-                        cx.tcx,
-                        cx.tcx.explicit_item_super_predicates(def).iter_identity_copied(),
-                    )
-                    // We only care about self bounds for the impl-trait
-                    .filter_only_self()
-                    .find_map(|(pred, _span)| {
-                        // We only look at the `DefId`, so it is safe to skip the binder here.
-                        if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
-                            pred.kind().skip_binder()
-                        {
-                            let def_id = poly_trait_predicate.trait_ref.def_id;
-
-                            is_def_must_use(cx, def_id, span)
-                        } else {
-                            None
-                        }
-                    })
-                    .map(|inner| MustUsePath::Opaque(Box::new(inner)))
+                    elaborate(cx.tcx, cx.tcx.explicit_item_self_bounds(def).iter_identity_copied())
+                        // We only care about self bounds for the impl-trait
+                        .filter_only_self()
+                        .find_map(|(pred, _span)| {
+                            // We only look at the `DefId`, so it is safe to skip the binder here.
+                            if let ty::ClauseKind::Trait(ref poly_trait_predicate) =
+                                pred.kind().skip_binder()
+                            {
+                                let def_id = poly_trait_predicate.trait_ref.def_id;
+
+                                is_def_must_use(cx, def_id, span)
+                            } else {
+                                None
+                            }
+                        })
+                        .map(|inner| MustUsePath::Opaque(Box::new(inner)))
                 }
                 ty::Dynamic(binders, _, _) => binders.iter().find_map(|predicate| {
                     if let ty::ExistentialPredicate::Trait(ref trait_ref) = predicate.skip_binder()
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 527f2f10205..da07ad8f6c0 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -241,7 +241,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) {
 
 provide! { tcx, def_id, other, cdata,
     explicit_item_bounds => { table_defaulted_array }
-    explicit_item_super_predicates => { table_defaulted_array }
+    explicit_item_self_bounds => { table_defaulted_array }
     explicit_predicates_of => { table }
     generics_of => { table }
     inferred_outlives_of => { table_defaulted_array }
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index c538ab99fb5..904409dd777 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -1554,7 +1554,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             }
             if let DefKind::OpaqueTy = def_kind {
                 self.encode_explicit_item_bounds(def_id);
-                self.encode_explicit_item_super_predicates(def_id);
+                self.encode_explicit_item_self_bounds(def_id);
                 record!(self.tables.opaque_ty_origin[def_id] <- self.tcx.opaque_ty_origin(def_id));
                 self.encode_precise_capturing_args(def_id);
                 if tcx.is_conditionally_const(def_id) {
@@ -1667,10 +1667,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
         record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
     }
 
-    fn encode_explicit_item_super_predicates(&mut self, def_id: DefId) {
-        debug!("EncodeContext::encode_explicit_item_super_predicates({:?})", def_id);
-        let bounds = self.tcx.explicit_item_super_predicates(def_id).skip_binder();
-        record_defaulted_array!(self.tables.explicit_item_super_predicates[def_id] <- bounds);
+    fn encode_explicit_item_self_bounds(&mut self, def_id: DefId) {
+        debug!("EncodeContext::encode_explicit_item_self_bounds({:?})", def_id);
+        let bounds = self.tcx.explicit_item_self_bounds(def_id).skip_binder();
+        record_defaulted_array!(self.tables.explicit_item_self_bounds[def_id] <- bounds);
     }
 
     #[instrument(level = "debug", skip(self))]
@@ -1685,7 +1685,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
             AssocItemContainer::Trait => {
                 if let ty::AssocKind::Type = item.kind {
                     self.encode_explicit_item_bounds(def_id);
-                    self.encode_explicit_item_super_predicates(def_id);
+                    self.encode_explicit_item_self_bounds(def_id);
                     if tcx.is_conditionally_const(def_id) {
                         record_defaulted_array!(self.tables.explicit_implied_const_bounds[def_id]
                             <- self.tcx.explicit_implied_const_bounds(def_id).skip_binder());
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 4f9cdc9a474..d1d356c5220 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -386,7 +386,7 @@ define_tables! {
     // corresponding DefPathHash.
     def_path_hashes: Table<DefIndex, u64>,
     explicit_item_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
-    explicit_item_super_predicates: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
+    explicit_item_self_bounds: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     inferred_outlives_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_super_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
     explicit_implied_predicates_of: Table<DefIndex, LazyArray<(ty::Clause<'static>, Span)>>,
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs
index 1b07846e0cf..2e4d258ffff 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs
@@ -270,6 +270,12 @@ impl AllocRange {
     }
 }
 
+/// Whether a new allocation should be initialized with zero-bytes.
+pub enum AllocInit {
+    Uninit,
+    Zero,
+}
+
 // The constructors are all without extra; the extra gets added by a machine hook later.
 impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     /// Creates an allocation initialized by the given bytes
@@ -294,7 +300,12 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
         Allocation::from_bytes(slice, Align::ONE, Mutability::Not)
     }
 
-    fn uninit_inner<R>(size: Size, align: Align, fail: impl FnOnce() -> R) -> Result<Self, R> {
+    fn new_inner<R>(
+        size: Size,
+        align: Align,
+        init: AllocInit,
+        fail: impl FnOnce() -> R,
+    ) -> Result<Self, R> {
         // We raise an error if we cannot create the allocation on the host.
         // This results in an error that can happen non-deterministically, since the memory
         // available to the compiler can change between runs. Normally queries are always
@@ -306,7 +317,10 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
         Ok(Allocation {
             bytes,
             provenance: ProvenanceMap::new(),
-            init_mask: InitMask::new(size, false),
+            init_mask: InitMask::new(size, match init {
+                AllocInit::Uninit => false,
+                AllocInit::Zero => true,
+            }),
             align,
             mutability: Mutability::Mut,
             extra: (),
@@ -315,8 +329,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
 
     /// Try to create an Allocation of `size` bytes, failing if there is not enough memory
     /// available to the compiler to do so.
-    pub fn try_uninit<'tcx>(size: Size, align: Align) -> InterpResult<'tcx, Self> {
-        Self::uninit_inner(size, align, || {
+    pub fn try_new<'tcx>(size: Size, align: Align, init: AllocInit) -> InterpResult<'tcx, Self> {
+        Self::new_inner(size, align, init, || {
             ty::tls::with(|tcx| tcx.dcx().delayed_bug("exhausted memory during interpretation"));
             InterpErrorKind::ResourceExhaustion(ResourceExhaustionInfo::MemoryExhausted)
         })
@@ -328,8 +342,8 @@ impl<Prov: Provenance, Bytes: AllocBytes> Allocation<Prov, (), Bytes> {
     ///
     /// Example use case: To obtain an Allocation filled with specific data,
     /// first call this function and then call write_scalar to fill in the right data.
-    pub fn uninit(size: Size, align: Align) -> Self {
-        match Self::uninit_inner(size, align, || {
+    pub fn new(size: Size, align: Align, init: AllocInit) -> Self {
+        match Self::new_inner(size, align, init, || {
             panic!(
                 "interpreter ran out of memory: cannot create allocation of {} bytes",
                 size.bytes()
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index b88137544bc..f4f9f221a75 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -30,8 +30,8 @@ pub use {
 };
 
 pub use self::allocation::{
-    AllocBytes, AllocError, AllocRange, AllocResult, Allocation, ConstAllocation, InitChunk,
-    InitChunkIter, alloc_range,
+    AllocBytes, AllocError, AllocInit, AllocRange, AllocResult, Allocation, ConstAllocation,
+    InitChunk, InitChunkIter, alloc_range,
 };
 pub use self::error::{
     BadBytesAccess, CheckAlignMsg, CheckInAllocMsg, ErrorHandled, EvalStaticInitializerRawResult,
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index e27a9823639..d83bc19a6a2 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -393,7 +393,7 @@ rustc_queries! {
     /// like closure signature deduction.
     ///
     /// [explicit item bounds]: Self::explicit_item_bounds
-    query explicit_item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
+    query explicit_item_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, &'tcx [(ty::Clause<'tcx>, Span)]> {
         desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
         cache_on_disk_if { key.is_local() }
         separate_provide_extern
@@ -427,11 +427,11 @@ rustc_queries! {
         desc { |tcx| "elaborating item bounds for `{}`", tcx.def_path_str(key) }
     }
 
-    query item_super_predicates(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
+    query item_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
-    query item_non_self_assumptions(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
+    query item_non_self_bounds(key: DefId) -> ty::EarlyBinder<'tcx, ty::Clauses<'tcx>> {
         desc { |tcx| "elaborating item assumptions for `{}`", tcx.def_path_str(key) }
     }
 
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 55d78e083e0..8a9110f842a 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -194,6 +194,9 @@ pub enum ObligationCauseCode<'tcx> {
     /// A slice or array is WF only if `T: Sized`.
     SliceOrArrayElem,
 
+    /// An array `[T; N]` can only be indexed (and is only well-formed if) `N` has type usize.
+    ArrayLen(Ty<'tcx>),
+
     /// A tuple is WF only if its middle elements are `Sized`.
     TupleElem,
 
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 1f0710e2415..0c22c056dab 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -345,6 +345,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> {
         self.item_bounds(def_id).map_bound(IntoIterator::into_iter)
     }
 
+    fn item_self_bounds(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
+        self.item_self_bounds(def_id).map_bound(IntoIterator::into_iter)
+    }
+
+    fn item_non_self_bounds(
+        self,
+        def_id: DefId,
+    ) -> ty::EarlyBinder<'tcx, impl IntoIterator<Item = ty::Clause<'tcx>>> {
+        self.item_non_self_bounds(def_id).map_bound(IntoIterator::into_iter)
+    }
+
     fn predicates_of(
         self,
         def_id: DefId,
@@ -2577,7 +2591,7 @@ impl<'tcx> TyCtxt<'tcx> {
         let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
         let future_trait = self.require_lang_item(LangItem::Future, None);
 
-        self.explicit_item_super_predicates(def_id).skip_binder().iter().any(|&(predicate, _)| {
+        self.explicit_item_self_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
             let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() else {
                 return false;
             };
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index ac900edefe1..027a4315b4b 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1740,6 +1740,10 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
                     " as ",
                 )?;
             }
+            ty::Pat(base_ty, pat) => {
+                self.pretty_print_const_scalar_int(int, *base_ty, print_ty)?;
+                p!(write(" is {pat:?}"));
+            }
             // Nontrivial types with scalar bit representation
             _ => {
                 let print = |this: &mut Self| {
diff --git a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
index 21c605f8296..cbc02097d82 100644
--- a/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
+++ b/compiler/rustc_middle/src/ty/return_position_impl_trait_in_trait.rs
@@ -64,7 +64,7 @@ impl<'tcx> TyCtxt<'tcx> {
         args: ty::GenericArgsRef<'tcx>,
     ) -> &'tcx ty::List<ty::PolyExistentialPredicate<'tcx>> {
         let mut bounds: Vec<_> = self
-            .item_super_predicates(def_id)
+            .item_self_bounds(def_id)
             .iter_instantiated(self, args)
             .filter_map(|clause| {
                 clause
diff --git a/compiler/rustc_middle/src/ty/vtable.rs b/compiler/rustc_middle/src/ty/vtable.rs
index 23e2e8ad3d3..455bd16ff8c 100644
--- a/compiler/rustc_middle/src/ty/vtable.rs
+++ b/compiler/rustc_middle/src/ty/vtable.rs
@@ -4,7 +4,9 @@ use rustc_ast::Mutability;
 use rustc_macros::HashStable;
 use rustc_type_ir::elaborate;
 
-use crate::mir::interpret::{AllocId, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range};
+use crate::mir::interpret::{
+    AllocId, AllocInit, Allocation, CTFE_ALLOC_SALT, Pointer, Scalar, alloc_range,
+};
 use crate::ty::{self, Instance, PolyTraitRef, Ty, TyCtxt};
 
 #[derive(Clone, Copy, PartialEq, HashStable)]
@@ -108,7 +110,7 @@ pub(super) fn vtable_allocation_provider<'tcx>(
     let ptr_align = tcx.data_layout.pointer_align.abi;
 
     let vtable_size = ptr_size * u64::try_from(vtable_entries.len()).unwrap();
-    let mut vtable = Allocation::uninit(vtable_size, ptr_align);
+    let mut vtable = Allocation::new(vtable_size, ptr_align, AllocInit::Uninit);
 
     // No need to do any alignment checks on the memory accesses below, because we know the
     // allocation is correctly aligned as we created it above. Also we're only offsetting by
diff --git a/compiler/rustc_mir_build/src/builder/matches/test.rs b/compiler/rustc_mir_build/src/builder/matches/test.rs
index 8cca84d7fcc..afe6b4475be 100644
--- a/compiler/rustc_mir_build/src/builder/matches/test.rs
+++ b/compiler/rustc_mir_build/src/builder/matches/test.rs
@@ -141,43 +141,49 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                 self.cfg.terminate(block, self.source_info(match_start_span), terminator);
             }
 
-            TestKind::Eq { value, ty } => {
+            TestKind::Eq { value, mut ty } => {
                 let tcx = self.tcx;
                 let success_block = target_block(TestBranch::Success);
                 let fail_block = target_block(TestBranch::Failure);
-                if let ty::Adt(def, _) = ty.kind()
-                    && tcx.is_lang_item(def.did(), LangItem::String)
-                {
-                    if !tcx.features().string_deref_patterns() {
-                        span_bug!(
+
+                let expect_ty = value.ty();
+                let expect = self.literal_operand(test.span, value);
+
+                let mut place = place;
+                let mut block = block;
+                match ty.kind() {
+                    ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
+                        if !tcx.features().string_deref_patterns() {
+                            span_bug!(
+                                test.span,
+                                "matching on `String` went through without enabling string_deref_patterns"
+                            );
+                        }
+                        let re_erased = tcx.lifetimes.re_erased;
+                        let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
+                        let ref_str = self.temp(ref_str_ty, test.span);
+                        let eq_block = self.cfg.start_new_block();
+                        // `let ref_str: &str = <String as Deref>::deref(&place);`
+                        self.call_deref(
+                            block,
+                            eq_block,
+                            place,
+                            Mutability::Not,
+                            ty,
+                            ref_str,
                             test.span,
-                            "matching on `String` went through without enabling string_deref_patterns"
                         );
+                        // Since we generated a `ref_str = <String as Deref>::deref(&place) -> eq_block` terminator,
+                        // we need to add all further statements to `eq_block`.
+                        // Similarly, the normal test code should be generated for the `&str`, instead of the `String`.
+                        block = eq_block;
+                        place = ref_str;
+                        ty = ref_str_ty;
                     }
-                    let re_erased = tcx.lifetimes.re_erased;
-                    let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
-                    let ref_str = self.temp(ref_str_ty, test.span);
-                    let eq_block = self.cfg.start_new_block();
-                    // `let ref_str: &str = <String as Deref>::deref(&place);`
-                    self.call_deref(
-                        block,
-                        eq_block,
-                        place,
-                        Mutability::Not,
-                        ty,
-                        ref_str,
-                        test.span,
-                    );
-                    self.non_scalar_compare(
-                        eq_block,
-                        success_block,
-                        fail_block,
-                        source_info,
-                        value,
-                        ref_str,
-                        ref_str_ty,
-                    );
-                } else if !ty.is_scalar() {
+                    _ => {}
+                }
+
+                if !ty.is_scalar() {
                     // Use `PartialEq::eq` instead of `BinOp::Eq`
                     // (the binop can only handle primitives)
                     self.non_scalar_compare(
@@ -185,14 +191,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         success_block,
                         fail_block,
                         source_info,
-                        value,
-                        place,
+                        expect,
+                        expect_ty,
+                        Operand::Copy(place),
                         ty,
                     );
                 } else {
-                    assert_eq!(value.ty(), ty);
-                    let expect = self.literal_operand(test.span, value);
-                    let val = Operand::Copy(place);
+                    assert_eq!(expect_ty, ty);
                     self.compare(
                         block,
                         success_block,
@@ -200,7 +205,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                         source_info,
                         BinOp::Eq,
                         expect,
-                        val,
+                        Operand::Copy(place),
                     );
                 }
             }
@@ -371,12 +376,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         success_block: BasicBlock,
         fail_block: BasicBlock,
         source_info: SourceInfo,
-        value: Const<'tcx>,
-        mut val: Place<'tcx>,
+        mut expect: Operand<'tcx>,
+        expect_ty: Ty<'tcx>,
+        mut val: Operand<'tcx>,
         mut ty: Ty<'tcx>,
     ) {
-        let mut expect = self.literal_operand(source_info.span, value);
-
         // If we're using `b"..."` as a pattern, we need to insert an
         // unsizing coercion, as the byte string has the type `&[u8; N]`.
         //
@@ -391,7 +395,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             _ => None,
         };
         let opt_ref_ty = unsize(ty);
-        let opt_ref_test_ty = unsize(value.ty());
+        let opt_ref_test_ty = unsize(expect_ty);
         match (opt_ref_ty, opt_ref_test_ty) {
             // nothing to do, neither is an array
             (None, None) => {}
@@ -410,11 +414,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
                                 PointerCoercion::Unsize,
                                 CoercionSource::Implicit,
                             ),
-                            Operand::Copy(val),
+                            val,
                             ty,
                         ),
                     );
-                    val = temp;
+                    val = Operand::Copy(temp);
                 }
                 if opt_ref_test_ty.is_some() {
                     let slice = self.temp(ty, source_info.span);
@@ -470,11 +474,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
 
                 const_: method,
             })),
-            args: [Spanned { node: Operand::Copy(val), span: DUMMY_SP }, Spanned {
-                node: expect,
-                span: DUMMY_SP,
-            }]
-            .into(),
+            args: [Spanned { node: val, span: DUMMY_SP }, Spanned { node: expect, span: DUMMY_SP }]
+                .into(),
             destination: eq_result,
             target: Some(eq_block),
             unwind: UnwindAction::Continue,
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 44b038bb5fa..20a728d6d5b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -332,10 +332,6 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
                     .unwrap_or_else(PatKind::Error)
             }
 
-            hir::PatKind::Path(ref qpath) => {
-                return self.lower_path(qpath, pat.hir_id, pat.span);
-            }
-
             hir::PatKind::Deref(subpattern) => {
                 let mutable = self.typeck_results.pat_has_ref_mut_binding(subpattern);
                 let mutability = if mutable { hir::Mutability::Mut } else { hir::Mutability::Not };
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index bb603df1129..d53848f7461 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -1454,11 +1454,14 @@ impl<'v> RootCollector<'_, 'v> {
                 self.output.push(dummy_spanned(MonoItem::Static(def_id)));
             }
             DefKind::Const => {
-                // const items only generate mono items if they are
-                // actually used somewhere. Just declaring them is insufficient.
+                // Const items only generate mono items if they are actually used somewhere.
+                // Just declaring them is insufficient.
 
-                // but even just declaring them must collect the items they refer to
-                if let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id()) {
+                // But even just declaring them must collect the items they refer to
+                // unless their generics require monomorphization.
+                if !self.tcx.generics_of(id.owner_id).requires_monomorphization(self.tcx)
+                    && let Ok(val) = self.tcx.const_eval_poly(id.owner_id.to_def_id())
+                {
                     collect_const_value(self.tcx, val, self.output);
                 }
             }
diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
index 63432dc199b..d0b01b14d63 100644
--- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
+++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs
@@ -19,6 +19,11 @@ use crate::solve::{
     MaybeCause, NoSolution, QueryResult,
 };
 
+enum AliasBoundKind {
+    SelfBounds,
+    NonSelfBounds,
+}
+
 /// A candidate is a possible way to prove a goal.
 ///
 /// It consists of both the `source`, which describes how that goal would be proven,
@@ -510,7 +515,12 @@ where
         candidates: &mut Vec<Candidate<I>>,
     ) {
         let () = self.probe(|_| ProbeKind::NormalizedSelfTyAssembly).enter(|ecx| {
-            ecx.assemble_alias_bound_candidates_recur(goal.predicate.self_ty(), goal, candidates);
+            ecx.assemble_alias_bound_candidates_recur(
+                goal.predicate.self_ty(),
+                goal,
+                candidates,
+                AliasBoundKind::SelfBounds,
+            );
         });
     }
 
@@ -528,6 +538,7 @@ where
         self_ty: I::Ty,
         goal: Goal<I, G>,
         candidates: &mut Vec<Candidate<I>>,
+        consider_self_bounds: AliasBoundKind,
     ) {
         let (kind, alias_ty) = match self_ty.kind() {
             ty::Bool
@@ -580,16 +591,37 @@ where
             }
         };
 
-        for assumption in
-            self.cx().item_bounds(alias_ty.def_id).iter_instantiated(self.cx(), alias_ty.args)
-        {
-            candidates.extend(G::probe_and_consider_implied_clause(
-                self,
-                CandidateSource::AliasBound,
-                goal,
-                assumption,
-                [],
-            ));
+        match consider_self_bounds {
+            AliasBoundKind::SelfBounds => {
+                for assumption in self
+                    .cx()
+                    .item_self_bounds(alias_ty.def_id)
+                    .iter_instantiated(self.cx(), alias_ty.args)
+                {
+                    candidates.extend(G::probe_and_consider_implied_clause(
+                        self,
+                        CandidateSource::AliasBound,
+                        goal,
+                        assumption,
+                        [],
+                    ));
+                }
+            }
+            AliasBoundKind::NonSelfBounds => {
+                for assumption in self
+                    .cx()
+                    .item_non_self_bounds(alias_ty.def_id)
+                    .iter_instantiated(self.cx(), alias_ty.args)
+                {
+                    candidates.extend(G::probe_and_consider_implied_clause(
+                        self,
+                        CandidateSource::AliasBound,
+                        goal,
+                        assumption,
+                        [],
+                    ));
+                }
+            }
         }
 
         candidates.extend(G::consider_additional_alias_assumptions(self, goal, alias_ty));
@@ -600,9 +632,12 @@ where
 
         // Recurse on the self type of the projection.
         match self.structurally_normalize_ty(goal.param_env, alias_ty.self_ty()) {
-            Ok(next_self_ty) => {
-                self.assemble_alias_bound_candidates_recur(next_self_ty, goal, candidates)
-            }
+            Ok(next_self_ty) => self.assemble_alias_bound_candidates_recur(
+                next_self_ty,
+                goal,
+                candidates,
+                AliasBoundKind::NonSelfBounds,
+            ),
             Err(NoSolution) => {}
         }
     }
diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs
index 5418f054beb..09c88e7f83b 100644
--- a/compiler/rustc_parse_format/src/lib.rs
+++ b/compiler/rustc_parse_format/src/lib.rs
@@ -16,11 +16,8 @@
 #![warn(unreachable_pub)]
 // tidy-alphabetical-end
 
-use std::{iter, str, string};
-
 pub use Alignment::*;
 pub use Count::*;
-pub use Piece::*;
 pub use Position::*;
 use rustc_lexer::unescape;
 
@@ -86,7 +83,7 @@ impl InnerOffset {
 #[derive(Clone, Debug, PartialEq)]
 pub enum Piece<'a> {
     /// A literal string which should directly be emitted
-    String(&'a str),
+    Lit(&'a str),
     /// This describes that formatting should process the next argument (as
     /// specified inside) for emission.
     NextArgument(Box<Argument<'a>>),
@@ -205,11 +202,11 @@ pub enum Count<'a> {
 }
 
 pub struct ParseError {
-    pub description: string::String,
-    pub note: Option<string::String>,
-    pub label: string::String,
+    pub description: String,
+    pub note: Option<String>,
+    pub label: String,
     pub span: InnerSpan,
-    pub secondary_label: Option<(string::String, InnerSpan)>,
+    pub secondary_label: Option<(String, InnerSpan)>,
     pub suggestion: Suggestion,
 }
 
@@ -225,7 +222,7 @@ pub enum Suggestion {
     /// `format!("{foo:?#}")` -> `format!("{foo:#?}")`
     /// `format!("{foo:?x}")` -> `format!("{foo:x?}")`
     /// `format!("{foo:?X}")` -> `format!("{foo:X?}")`
-    ReorderFormatParameter(InnerSpan, string::String),
+    ReorderFormatParameter(InnerSpan, String),
 }
 
 /// The parser structure for interpreting the input format string. This is
@@ -237,7 +234,7 @@ pub enum Suggestion {
 pub struct Parser<'a> {
     mode: ParseMode,
     input: &'a str,
-    cur: iter::Peekable<str::CharIndices<'a>>,
+    cur: std::iter::Peekable<std::str::CharIndices<'a>>,
     /// Error messages accumulated during parsing
     pub errors: Vec<ParseError>,
     /// Current position of implicit positional argument pointer
@@ -278,7 +275,7 @@ impl<'a> Iterator for Parser<'a> {
                     if self.consume('{') {
                         self.last_opening_brace = curr_last_brace;
 
-                        Some(String(self.string(pos + 1)))
+                        Some(Piece::Lit(self.string(pos + 1)))
                     } else {
                         let arg = self.argument(lbrace_end);
                         if let Some(rbrace_pos) = self.consume_closing_brace(&arg) {
@@ -299,13 +296,13 @@ impl<'a> Iterator for Parser<'a> {
                                 _ => self.suggest_positional_arg_instead_of_captured_arg(arg),
                             }
                         }
-                        Some(NextArgument(Box::new(arg)))
+                        Some(Piece::NextArgument(Box::new(arg)))
                     }
                 }
                 '}' => {
                     self.cur.next();
                     if self.consume('}') {
-                        Some(String(self.string(pos + 1)))
+                        Some(Piece::Lit(self.string(pos + 1)))
                     } else {
                         let err_pos = self.to_span_index(pos);
                         self.err_with_note(
@@ -317,7 +314,7 @@ impl<'a> Iterator for Parser<'a> {
                         None
                     }
                 }
-                _ => Some(String(self.string(pos))),
+                _ => Some(Piece::Lit(self.string(pos))),
             }
         } else {
             if self.is_source_literal {
@@ -336,7 +333,7 @@ impl<'a> Parser<'a> {
     pub fn new(
         s: &'a str,
         style: Option<usize>,
-        snippet: Option<string::String>,
+        snippet: Option<String>,
         append_newline: bool,
         mode: ParseMode,
     ) -> Parser<'a> {
@@ -366,7 +363,7 @@ impl<'a> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err<S1: Into<string::String>, S2: Into<string::String>>(
+    fn err<S1: Into<String>, S2: Into<String>>(
         &mut self,
         description: S1,
         label: S2,
@@ -385,11 +382,7 @@ impl<'a> Parser<'a> {
     /// Notifies of an error. The message doesn't actually need to be of type
     /// String, but I think it does when this eventually uses conditions so it
     /// might as well start using it now.
-    fn err_with_note<
-        S1: Into<string::String>,
-        S2: Into<string::String>,
-        S3: Into<string::String>,
-    >(
+    fn err_with_note<S1: Into<String>, S2: Into<String>, S3: Into<String>>(
         &mut self,
         description: S1,
         label: S2,
@@ -968,7 +961,7 @@ impl<'a> Parser<'a> {
 /// in order to properly synthesise the intra-string `Span`s for error diagnostics.
 fn find_width_map_from_snippet(
     input: &str,
-    snippet: Option<string::String>,
+    snippet: Option<String>,
     str_style: Option<usize>,
 ) -> InputStringKind {
     let snippet = match snippet {
@@ -1083,8 +1076,8 @@ fn find_width_map_from_snippet(
     InputStringKind::Literal { width_mappings }
 }
 
-fn unescape_string(string: &str) -> Option<string::String> {
-    let mut buf = string::String::new();
+fn unescape_string(string: &str) -> Option<String> {
+    let mut buf = String::new();
     let mut ok = true;
     unescape::unescape_unicode(string, unescape::Mode::Str, &mut |_, unescaped_char| {
         match unescaped_char {
diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs
index 81e5bca0ba9..fbb217b16fc 100644
--- a/compiler/rustc_parse_format/src/tests.rs
+++ b/compiler/rustc_parse_format/src/tests.rs
@@ -1,3 +1,5 @@
+use Piece::*;
+
 use super::*;
 
 #[track_caller]
@@ -32,12 +34,12 @@ fn musterr(s: &str) {
 
 #[test]
 fn simple() {
-    same("asdf", &[String("asdf")]);
-    same("a{{b", &[String("a"), String("{b")]);
-    same("a}}b", &[String("a"), String("}b")]);
-    same("a}}", &[String("a"), String("}")]);
-    same("}}", &[String("}")]);
-    same("\\}}", &[String("\\"), String("}")]);
+    same("asdf", &[Lit("asdf")]);
+    same("a{{b", &[Lit("a"), Lit("{b")]);
+    same("a}}b", &[Lit("a"), Lit("}b")]);
+    same("a}}", &[Lit("a"), Lit("}")]);
+    same("}}", &[Lit("}")]);
+    same("\\}}", &[Lit("\\"), Lit("}")]);
 }
 
 #[test]
@@ -370,7 +372,7 @@ fn format_flags() {
 #[test]
 fn format_mixture() {
     same("abcd {3:x} efg", &[
-        String("abcd "),
+        Lit("abcd "),
         NextArgument(Box::new(Argument {
             position: ArgumentIs(3),
             position_span: InnerSpan { start: 7, end: 8 },
@@ -390,7 +392,7 @@ fn format_mixture() {
                 ty_span: None,
             },
         })),
-        String(" efg"),
+        Lit(" efg"),
     ]);
 }
 #[test]
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index e5b63b9b4a6..95f18eaa7ef 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -10,11 +10,10 @@ use hir::def_id::{LocalDefIdMap, LocalDefIdSet};
 use rustc_abi::FieldIdx;
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::MultiSpan;
-use rustc_hir as hir;
 use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{Node, PatKind, TyKind};
+use rustc_hir::{self as hir, Node, PatKind, TyKind};
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
 use rustc_middle::middle::privacy::Level;
 use rustc_middle::query::Providers;
@@ -637,10 +636,6 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
                 let res = self.typeck_results().qpath_res(path, pat.hir_id);
                 self.handle_field_pattern_match(pat, res, fields);
             }
-            PatKind::Path(ref qpath) => {
-                let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
-                self.handle_res(res);
-            }
             PatKind::TupleStruct(ref qpath, fields, dotdot) => {
                 let res = self.typeck_results().qpath_res(qpath, pat.hir_id);
                 self.handle_tuple_field_pattern_match(pat, res, fields, dotdot);
@@ -652,6 +647,17 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
         self.in_pat = false;
     }
 
+    fn visit_pat_expr(&mut self, expr: &'tcx rustc_hir::PatExpr<'tcx>) {
+        match &expr.kind {
+            rustc_hir::PatExprKind::Path(qpath) => {
+                let res = self.typeck_results().qpath_res(qpath, expr.hir_id);
+                self.handle_res(res);
+            }
+            _ => {}
+        }
+        intravisit::walk_pat_expr(self, expr);
+    }
+
     fn visit_path(&mut self, path: &hir::Path<'tcx>, _: hir::HirId) {
         self.handle_res(path.res);
         intravisit::walk_path(self, path);
diff --git a/compiler/rustc_passes/src/input_stats.rs b/compiler/rustc_passes/src/input_stats.rs
index 8b10543f6fd..75b62a40ff9 100644
--- a/compiler/rustc_passes/src/input_stats.rs
+++ b/compiler/rustc_passes/src/input_stats.rs
@@ -298,7 +298,6 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
             TupleStruct,
             Or,
             Never,
-            Path,
             Tuple,
             Box,
             Deref,
diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs
index 87024c487df..16c0a345f87 100644
--- a/compiler/rustc_resolve/src/def_collector.rs
+++ b/compiler/rustc_resolve/src/def_collector.rs
@@ -170,9 +170,12 @@ impl<'a, 'ra, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'ra, 'tcx> {
 
     fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
         match fn_kind {
-            FnKind::Fn(_ctxt, _ident, FnSig { header, decl, span: _ }, _vis, generics, body)
-                if let Some(coroutine_kind) = header.coroutine_kind =>
-            {
+            FnKind::Fn(
+                _ctxt,
+                _ident,
+                _vis,
+                Fn { sig: FnSig { header, decl, span: _ }, generics, body, .. },
+            ) if let Some(coroutine_kind) = header.coroutine_kind => {
                 self.visit_fn_header(header);
                 self.visit_generics(generics);
 
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 68d3351f174..4842cbd556c 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -986,8 +986,8 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
         match fn_kind {
             // Bail if the function is foreign, and thus cannot validly have
             // a body, or if there's no body for some other reason.
-            FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _)
-            | FnKind::Fn(_, _, sig, _, generics, None) => {
+            FnKind::Fn(FnCtxt::Foreign, _, _, Fn { sig, generics, .. })
+            | FnKind::Fn(_, _, _, Fn { sig, generics, body: None, .. }) => {
                 self.visit_fn_header(&sig.header);
                 self.visit_generics(generics);
                 self.with_lifetime_rib(
@@ -1019,7 +1019,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
             // Create a label rib for the function.
             this.with_label_rib(RibKind::FnOrCoroutine, |this| {
                 match fn_kind {
-                    FnKind::Fn(_, _, sig, _, generics, body) => {
+                    FnKind::Fn(_, _, _, Fn { sig, generics, body, .. }) => {
                         this.visit_generics(generics);
 
                         let declaration = &sig.decl;
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 2db8087fd83..57679d595da 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -224,7 +224,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 let suggestion = if self.current_trait_ref.is_none()
                     && let Some((fn_kind, _)) = self.diag_metadata.current_function
                     && let Some(FnCtxt::Assoc(_)) = fn_kind.ctxt()
-                    && let FnKind::Fn(_, _, sig, ..) = fn_kind
+                    && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = fn_kind
                     && let Some(items) = self.diag_metadata.current_impl_items
                     && let Some(item) = items.iter().find(|i| {
                         i.ident.name == item_str.name
@@ -560,7 +560,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                 Applicability::MaybeIncorrect,
             );
             if !self.self_value_is_available(path[0].ident.span) {
-                if let Some((FnKind::Fn(_, _, sig, ..), fn_span)) =
+                if let Some((FnKind::Fn(_, _, _, ast::Fn { sig, .. }), fn_span)) =
                     &self.diag_metadata.current_function
                 {
                     let (span, sugg) = if let Some(param) = sig.decl.inputs.get(0) {
@@ -3249,7 +3249,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                     {
                         let pre = if lt.kind == MissingLifetimeKind::Ampersand
                             && let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
                             && !sig.decl.inputs.is_empty()
                             && let sugg = sig
                                 .decl
@@ -3290,7 +3290,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                         } else if (lt.kind == MissingLifetimeKind::Ampersand
                             || lt.kind == MissingLifetimeKind::Underscore)
                             && let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
                             && let ast::FnRetTy::Ty(ret_ty) = &sig.decl.output
                             && !sig.decl.inputs.is_empty()
                             && let arg_refs = sig
@@ -3350,7 +3350,7 @@ impl<'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
                         let mut owned_sugg = lt.kind == MissingLifetimeKind::Ampersand;
                         let mut sugg = vec![(lt.span, String::new())];
                         if let Some((kind, _span)) = self.diag_metadata.current_function
-                            && let FnKind::Fn(_, _, sig, _, _, _) = kind
+                            && let FnKind::Fn(_, _, _, ast::Fn { sig, .. }) = kind
                             && let ast::FnRetTy::Ty(ty) = &sig.decl.output
                         {
                             let mut lt_finder =
diff --git a/compiler/rustc_smir/src/rustc_smir/alloc.rs b/compiler/rustc_smir/src/rustc_smir/alloc.rs
index 4e8db6096d4..52c5b425c14 100644
--- a/compiler/rustc_smir/src/rustc_smir/alloc.rs
+++ b/compiler/rustc_smir/src/rustc_smir/alloc.rs
@@ -1,6 +1,6 @@
 use rustc_abi::{Align, Size};
 use rustc_middle::mir::ConstValue;
-use rustc_middle::mir::interpret::{AllocRange, Pointer, alloc_range};
+use rustc_middle::mir::interpret::{AllocInit, AllocRange, Pointer, alloc_range};
 use stable_mir::Error;
 use stable_mir::mir::Mutability;
 use stable_mir::ty::{Allocation, ProvenanceMap};
@@ -44,7 +44,8 @@ pub(crate) fn try_new_allocation<'tcx>(
                 .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?
                 .align;
-            let mut allocation = rustc_middle::mir::interpret::Allocation::uninit(size, align.abi);
+            let mut allocation =
+                rustc_middle::mir::interpret::Allocation::new(size, align.abi, AllocInit::Uninit);
             allocation
                 .write_scalar(&tables.tcx, alloc_range(Size::ZERO, size), scalar)
                 .map_err(|e| e.stable(tables))?;
@@ -68,8 +69,11 @@ pub(crate) fn try_new_allocation<'tcx>(
                 .tcx
                 .layout_of(rustc_middle::ty::TypingEnv::fully_monomorphized().as_query_input(ty))
                 .map_err(|e| e.stable(tables))?;
-            let mut allocation =
-                rustc_middle::mir::interpret::Allocation::uninit(layout.size, layout.align.abi);
+            let mut allocation = rustc_middle::mir::interpret::Allocation::new(
+                layout.size,
+                layout.align.abi,
+                AllocInit::Uninit,
+            );
             allocation
                 .write_scalar(
                     &tables.tcx,
diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs
index 9fd07c8634a..0d8a4988dce 100644
--- a/compiler/rustc_target/src/target_features.rs
+++ b/compiler/rustc_target/src/target_features.rs
@@ -108,21 +108,19 @@ impl Stability {
 // per-function level, since we would then allow safe calls from functions with `+soft-float` to
 // functions without that feature!
 //
-// It is important for soundness that features allowed here do *not* change the function call ABI.
-// For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
-// arguments, so enabling toggling that feature would be unsound. In fact, since `-Ctarget-feature`
-// will just allow unknown features (with a warning), we have to explicitly list features that change
-// the ABI as `Forbidden` to ensure using them causes an error. Note that this is only effective if
-// such features can never be toggled via `-Ctarget-cpu`! If that is ever a possibility, we will need
-// extra checks ensuring that the LLVM-computed target features for a CPU did not (un)set a
-// `Forbidden` feature. See https://github.com/rust-lang/rust/issues/116344 for some more context.
-// FIXME: add such "forbidden" features for non-x86 targets.
+// It is important for soundness to consider the interaction of targets features and the function
+// call ABI. For example, disabling the `x87` feature on x86 changes how scalar floats are passed as
+// arguments, so letting people toggle that feature would be unsound. To this end, the
+// `abi_required_features` function computes which target features must and must not be enabled for
+// any given target, and individual features can also be marked as `Forbidden`.
+// See https://github.com/rust-lang/rust/issues/116344 for some more context.
 //
 // The one exception to features that change the ABI is features that enable larger vector
-// registers. Those are permitted to be listed here. This is currently unsound (see
-// https://github.com/rust-lang/rust/issues/116558); in the future we will have to ensure that
-// functions can only use such vectors as arguments/return types if the corresponding target feature
-// is enabled.
+// registers. Those are permitted to be listed here. The `*_FOR_CORRECT_VECTOR_ABI` arrays store
+// information about which target feature is ABI-required for which vector size; this is used to
+// ensure that vectors can only be passed via `extern "C"` when the right feature is enabled. (For
+// the "Rust" ABI we generally pass vectors by-ref exactly to avoid these issues.)
+// Also see https://github.com/rust-lang/rust/issues/116558.
 //
 // Stabilizing a target feature requires t-lang approval.
 
@@ -137,6 +135,11 @@ const ARM_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
     // tidy-alphabetical-start
     ("aclass", Unstable(sym::arm_target_feature), &[]),
     ("aes", Unstable(sym::arm_target_feature), &["neon"]),
+    (
+        "atomics-32",
+        Stability::Forbidden { reason: "unsound because it changes the ABI of atomic operations" },
+        &[],
+    ),
     ("crc", Unstable(sym::arm_target_feature), &[]),
     ("d32", Unstable(sym::arm_target_feature), &[]),
     ("dotprod", Unstable(sym::arm_target_feature), &["neon"]),
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 750d2756b4a..7c72318b4d7 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -165,6 +165,8 @@ trait_selection_explicit_lifetime_required_with_param_type = explicit lifetime r
 
 trait_selection_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
 
+trait_selection_fn_consider_casting_both = consider casting both fn items to fn pointers using `as {$sig}`
+
 trait_selection_fn_uniq_types = different fn items have unique types, even if their signatures are the same
 trait_selection_fps_cast = consider casting to a fn pointer
 trait_selection_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index bcb6ac13b8f..9eacd377361 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -196,7 +196,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
 
         self.tcx
-            .explicit_item_super_predicates(def_id)
+            .explicit_item_self_bounds(def_id)
             .iter_instantiated_copied(self.tcx, args)
             .find_map(|(predicate, _)| {
                 predicate
@@ -1844,7 +1844,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 self.suggest_tuple_pattern(cause, &exp_found, diag);
                 self.suggest_accessing_field_where_appropriate(cause, &exp_found, diag);
                 self.suggest_await_on_expect_found(cause, span, &exp_found, diag);
-                self.suggest_function_pointers(cause, span, &exp_found, diag);
+                self.suggest_function_pointers(cause, span, &exp_found, terr, diag);
                 self.suggest_turning_stmt_into_expr(cause, &exp_found, diag);
             }
         }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index 1dd09fe7aaf..e8d14b89d69 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -293,7 +293,7 @@ impl<T> Trait<T> for X {
                     (ty::Dynamic(t, _, ty::DynKind::Dyn), ty::Alias(ty::Opaque, alias))
                         if let Some(def_id) = t.principal_def_id()
                             && tcx
-                                .explicit_item_super_predicates(alias.def_id)
+                                .explicit_item_self_bounds(alias.def_id)
                                 .skip_binder()
                                 .iter()
                                 .any(|(pred, _span)| match pred.kind().skip_binder() {
@@ -422,7 +422,7 @@ impl<T> Trait<T> for X {
                             ty::Alias(..) => values.expected,
                             _ => values.found,
                         };
-                        let preds = tcx.explicit_item_super_predicates(opaque_ty.def_id);
+                        let preds = tcx.explicit_item_self_bounds(opaque_ty.def_id);
                         for (pred, _span) in preds.skip_binder() {
                             let ty::ClauseKind::Trait(trait_predicate) = pred.kind().skip_binder()
                             else {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index af7e56961b7..231fecf7a4a 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -12,6 +12,7 @@ use rustc_middle::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
     StatementAsExpression,
 };
+use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::with_no_trimmed_paths;
 use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
 use rustc_span::{Span, sym};
@@ -20,7 +21,7 @@ use tracing::debug;
 use crate::error_reporting::TypeErrCtxt;
 use crate::error_reporting::infer::hir::Path;
 use crate::errors::{
-    ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
+    ConsiderAddingAwait, FnConsiderCasting, FnConsiderCastingBoth, FnItemsAreDistinct, FnUniqTypes,
     FunctionPointerSuggestion, SuggestAccessingField, SuggestRemoveSemiOrReturnBinding,
     SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
 };
@@ -381,14 +382,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    pub(super) fn suggest_function_pointers(
+    pub fn suggest_function_pointers_impl(
         &self,
-        cause: &ObligationCause<'tcx>,
-        span: Span,
+        span: Option<Span>,
         exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
         diag: &mut Diag<'_>,
     ) {
-        debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
         let ty::error::ExpectedFound { expected, found } = exp_found;
         let expected_inner = expected.peel_refs();
         let found_inner = found.peel_refs();
@@ -411,6 +410,13 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     return;
                 }
 
+                let Some(span) = span else {
+                    let casting = format!("{fn_name} as {sig}");
+                    diag.subdiagnostic(FnItemsAreDistinct);
+                    diag.subdiagnostic(FnConsiderCasting { casting });
+                    return;
+                };
+
                 let sugg = match (expected.is_ref(), found.is_ref()) {
                     (true, false) => FunctionPointerSuggestion::UseRef { span, fn_name },
                     (false, true) => FunctionPointerSuggestion::RemoveRef { span, fn_name },
@@ -445,6 +451,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 }
 
                 let fn_name = self.tcx.def_path_str_with_args(*did2, args2);
+
+                let Some(span) = span else {
+                    diag.subdiagnostic(FnConsiderCastingBoth { sig: *expected_sig });
+                    return;
+                };
+
                 let sug = if found.is_ref() {
                     FunctionPointerSuggestion::CastBothRef {
                         span,
@@ -488,6 +500,23 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         };
     }
 
+    pub(super) fn suggest_function_pointers(
+        &self,
+        cause: &ObligationCause<'tcx>,
+        span: Span,
+        exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
+        terr: TypeError<'tcx>,
+        diag: &mut Diag<'_>,
+    ) {
+        debug!("suggest_function_pointers(cause={:?}, exp_found={:?})", cause, exp_found);
+
+        if exp_found.expected.peel_refs().is_fn() && exp_found.found.peel_refs().is_fn() {
+            self.suggest_function_pointers_impl(Some(span), exp_found, diag);
+        } else if let TypeError::Sorts(exp_found) = terr {
+            self.suggest_function_pointers_impl(None, &exp_found, diag);
+        }
+    }
+
     pub fn should_suggest_as_ref_kind(
         &self,
         expected: Ty<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 5021fd8bf83..6d39cbce3b7 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -1969,6 +1969,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             StringPart::highlighted(exp_found.found.to_string()),
                             StringPart::normal("`"),
                         ]);
+                        self.suggest_function_pointers_impl(None, &exp_found, err);
                     }
 
                     true
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 4e0b097db4c..3d79b0acf83 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -799,7 +799,7 @@ impl<'tcx> OnUnimplementedFormatString {
         let mut result = Ok(());
         for token in &mut parser {
             match token {
-                Piece::String(_) => (), // Normal string, no need to check it
+                Piece::Lit(_) => (), // Normal string, no need to check it
                 Piece::NextArgument(a) => {
                     let format_spec = a.format;
                     if self.is_diagnostic_namespace_variant
@@ -950,7 +950,7 @@ impl<'tcx> OnUnimplementedFormatString {
         let item_context = (options.get(&sym::ItemContext)).unwrap_or(&empty_string);
         let constructed_message = (&mut parser)
             .map(|p| match p {
-                Piece::String(s) => s.to_owned(),
+                Piece::Lit(s) => s.to_owned(),
                 Piece::NextArgument(a) => match a.position {
                     Position::ArgumentNamed(arg) => {
                         let s = Symbol::intern(arg);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index 471105773e2..ab25bef4120 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -1087,28 +1087,27 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         sig_parts.map_bound(|sig| sig.tupled_inputs_ty.tuple_fields().as_slice()),
                     ))
                 }
-                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
-                    .tcx
-                    .item_super_predicates(def_id)
-                    .instantiate(self.tcx, args)
-                    .iter()
-                    .find_map(|pred| {
-                        if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
+                ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => {
+                    self.tcx.item_self_bounds(def_id).instantiate(self.tcx, args).iter().find_map(
+                        |pred| {
+                            if let ty::ClauseKind::Projection(proj) = pred.kind().skip_binder()
                             && self
                                 .tcx
                                 .is_lang_item(proj.projection_term.def_id, LangItem::FnOnceOutput)
                             // args tuple will always be args[1]
                             && let ty::Tuple(args) = proj.projection_term.args.type_at(1).kind()
-                        {
-                            Some((
-                                DefIdOrName::DefId(def_id),
-                                pred.kind().rebind(proj.term.expect_type()),
-                                pred.kind().rebind(args.as_slice()),
-                            ))
-                        } else {
-                            None
-                        }
-                    }),
+                            {
+                                Some((
+                                    DefIdOrName::DefId(def_id),
+                                    pred.kind().rebind(proj.term.expect_type()),
+                                    pred.kind().rebind(args.as_slice()),
+                                ))
+                            } else {
+                                None
+                            }
+                        },
+                    )
+                }
                 ty::Dynamic(data, _, ty::Dyn) => data.iter().find_map(|pred| {
                     if let ty::ExistentialPredicate::Projection(proj) = pred.skip_binder()
                         && self.tcx.is_lang_item(proj.def_id, LangItem::FnOnceOutput)
@@ -2770,6 +2769,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             ObligationCauseCode::SliceOrArrayElem => {
                 err.note("slice and array elements must have `Sized` type");
             }
+            ObligationCauseCode::ArrayLen(array_ty) => {
+                err.note(format!("the length of array `{array_ty}` must be type `usize`"));
+            }
             ObligationCauseCode::TupleElem => {
                 err.note("only the last element of a tuple may have a dynamically sized type");
             }
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 2dfa72972ba..c8672b9dbd2 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1497,6 +1497,12 @@ pub struct FnConsiderCasting {
 }
 
 #[derive(Subdiagnostic)]
+#[help(trait_selection_fn_consider_casting_both)]
+pub struct FnConsiderCastingBoth<'a> {
+    pub sig: Binder<'a, FnSig<'a>>,
+}
+
+#[derive(Subdiagnostic)]
 pub enum SuggestAccessingField<'a> {
     #[suggestion(
         trait_selection_suggest_accessing_field,
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 0cc0d7f786b..6b6e0b32385 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1620,9 +1620,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             // projections, we will never be able to equate, e.g. `<T as Tr>::A`
             // with `<<T as Tr>::A as Tr>::A`.
             let relevant_bounds = if in_parent_alias_type {
-                self.tcx().item_non_self_assumptions(alias_ty.def_id)
+                self.tcx().item_non_self_bounds(alias_ty.def_id)
             } else {
-                self.tcx().item_super_predicates(alias_ty.def_id)
+                self.tcx().item_self_bounds(alias_ty.def_id)
             };
 
             for bound in relevant_bounds.instantiate(self.tcx(), alias_ty.args) {
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 9d32eb05386..20b675bcb76 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -689,7 +689,7 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 self.require_sized(subty, ObligationCauseCode::SliceOrArrayElem);
                 // Note that the len being WF is implicitly checked while visiting.
                 // Here we just check that it's of type usize.
-                let cause = self.cause(ObligationCauseCode::Misc);
+                let cause = self.cause(ObligationCauseCode::ArrayLen(t));
                 self.out.push(traits::Obligation::with_depth(
                     tcx,
                     cause,
diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs
index 4fec606a831..0c3b0758f0f 100644
--- a/compiler/rustc_type_ir/src/interner.rs
+++ b/compiler/rustc_type_ir/src/interner.rs
@@ -203,6 +203,16 @@ pub trait Interner:
         def_id: Self::DefId,
     ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
 
+    fn item_self_bounds(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
+
+    fn item_non_self_bounds(
+        self,
+        def_id: Self::DefId,
+    ) -> ty::EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>>;
+
     fn predicates_of(
         self,
         def_id: Self::DefId,
diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs
index 5c04e5a40df..01a3c9d2ada 100644
--- a/library/core/src/macros/mod.rs
+++ b/library/core/src/macros/mod.rs
@@ -313,6 +313,17 @@ pub macro cfg_match {
 ///     }
 /// }
 /// ```
+///
+/// If desired, it is possible to return expressions through the use of surrounding braces:
+///
+/// ```
+/// #![feature(cfg_match)]
+///
+/// let _some_string = cfg_match! {{
+///     unix => { "With great power comes great electricity bills" }
+///     _ => { "Behind every successful diet is an unwatched pizza" }
+/// }};
+/// ```
 #[cfg(not(bootstrap))]
 #[unstable(feature = "cfg_match", issue = "115585")]
 #[rustc_diagnostic_item = "cfg_match"]
diff --git a/library/std/src/io/pipe/tests.rs b/library/std/src/io/pipe/tests.rs
index c1f3f192ca2..f113b157459 100644
--- a/library/std/src/io/pipe/tests.rs
+++ b/library/std/src/io/pipe/tests.rs
@@ -1,7 +1,7 @@
 use crate::io::{Read, Write, pipe};
 
 #[test]
-#[cfg(all(windows, unix, not(miri)))]
+#[cfg(all(any(unix, windows), not(miri)))]
 fn pipe_creation_clone_and_rw() {
     let (rx, tx) = pipe().unwrap();
 
diff --git a/library/std/src/sys/pal/uefi/process.rs b/library/std/src/sys/pal/uefi/process.rs
index 1a0754134df..3077a72eac6 100644
--- a/library/std/src/sys/pal/uefi/process.rs
+++ b/library/std/src/sys/pal/uefi/process.rs
@@ -460,7 +460,7 @@ mod uefi_command_internal {
                 helpers::open_protocol(self.handle, loaded_image::PROTOCOL_GUID).unwrap();
 
             let len = args.len();
-            let args_size: u32 = crate::mem::size_of_val(&args).try_into().unwrap();
+            let args_size: u32 = (len * crate::mem::size_of::<u16>()).try_into().unwrap();
             let ptr = Box::into_raw(args).as_mut_ptr();
 
             unsafe {
@@ -706,9 +706,10 @@ mod uefi_command_internal {
         res.push(QUOTE);
         res.extend(prog.encode_wide());
         res.push(QUOTE);
-        res.push(SPACE);
 
         for arg in args {
+            res.push(SPACE);
+
             // Wrap the argument in quotes to be treat as single arg
             res.push(QUOTE);
             for c in arg.encode_wide() {
@@ -719,8 +720,6 @@ mod uefi_command_internal {
                 res.push(c);
             }
             res.push(QUOTE);
-
-            res.push(SPACE);
         }
 
         res.into_boxed_slice()
diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
index d408cd518a0..9234c6dc921 100644
--- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile
+++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile
@@ -29,7 +29,7 @@ ENV PATH="/node/bin:${PATH}"
 
 # Install es-check
 # Pin its version to prevent unrelated CI failures due to future es-check versions.
-RUN npm install es-check@6.1.1 eslint@8.6.0 -g
+RUN npm install es-check@6.1.1 eslint@8.6.0 typescript@5.7.3 -g
 
 COPY scripts/sccache.sh /scripts/
 RUN sh /scripts/sccache.sh
@@ -68,4 +68,5 @@ ENV SCRIPT \
            es-check es2019 ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/librustdoc/html/static/.eslintrc.js ../src/librustdoc/html/static/js/*.js && \
            eslint -c ../src/tools/rustdoc-js/.eslintrc.js ../src/tools/rustdoc-js/tester.js && \
-           eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js
+           eslint -c ../src/tools/rustdoc-gui/.eslintrc.js ../src/tools/rustdoc-gui/tester.js && \
+           tsc --project ../src/librustdoc/html/static/js/tsconfig.json
diff --git a/src/ci/github-actions/jobs.yml b/src/ci/github-actions/jobs.yml
index 4c4863e2b4b..c6bc19f9e6c 100644
--- a/src/ci/github-actions/jobs.yml
+++ b/src/ci/github-actions/jobs.yml
@@ -43,10 +43,6 @@ runners:
     os: windows-2022-8core-32gb
     <<: *base-job
 
-  - &job-windows-16c
-    os: windows-2022-16core-64gb
-    <<: *base-job
-
   - &job-aarch64-linux
     # Free some disk space to avoid running out of space during the build.
     free_disk: true
diff --git a/src/doc/book b/src/doc/book
-Subproject 82a4a49789bc96db1a1b2a210b4c5ed7c9ef0c0
+Subproject fa312a343fbff01bc6cef393e326817f7071981
diff --git a/src/doc/edition-guide b/src/doc/edition-guide
-Subproject d56e0f3a0656b7702ca466d4b191e16c28262b8
+Subproject 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917ed
diff --git a/src/doc/nomicon b/src/doc/nomicon
-Subproject 625b200e5b33a5af35589db0bc454203a3d46d2
+Subproject bc2298865544695c63454fc1f9f98a3dc22e994
diff --git a/src/doc/reference b/src/doc/reference
-Subproject 293af991003772bdccf2d6b980182d84dd05594
+Subproject 93b921c7d3213d38d920f7f905a3bec093d2217
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
index 8983915d78a..b0f9af1b8d1 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-example.rs
@@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
-        krate: &rustc_ast::Crate,
+        krate: &mut rustc_ast::Crate,
     ) -> Compilation {
         for item in &krate.items {
             println!("{}", item_to_string(&item));
diff --git a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
index c894b60444a..8766a817344 100644
--- a/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
+++ b/src/doc/rustc-dev-guide/examples/rustc-driver-interacting-with-the-ast.rs
@@ -58,7 +58,7 @@ impl rustc_driver::Callbacks for MyCallbacks {
     fn after_crate_root_parsing(
         &mut self,
         _compiler: &Compiler,
-        krate: &rustc_ast::Crate,
+        krate: &mut rustc_ast::Crate,
     ) -> Compilation {
         for item in &krate.items {
             println!("{}", item_to_string(&item));
diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs
index 80dc6b7250c..77040aeb94d 100644
--- a/src/librustdoc/clean/utils.rs
+++ b/src/librustdoc/clean/utils.rs
@@ -303,7 +303,8 @@ pub(crate) fn name_from_pat(p: &hir::Pat<'_>) -> Symbol {
             return kw::Underscore;
         }
         PatKind::Binding(_, _, ident, _) => return ident.name,
-        PatKind::TupleStruct(ref p, ..) | PatKind::Path(ref p) => qpath_to_string(p),
+        PatKind::TupleStruct(ref p, ..)
+        | PatKind::Expr(PatExpr { kind: PatExprKind::Path(ref p), .. }) => qpath_to_string(p),
         PatKind::Or(pats) => {
             pats.iter().map(|p| name_from_pat(p).to_string()).collect::<Vec<String>>().join(" | ")
         }
diff --git a/src/librustdoc/html/render/span_map.rs b/src/librustdoc/html/render/span_map.rs
index 85f87f01afd..a15ac155123 100644
--- a/src/librustdoc/html/render/span_map.rs
+++ b/src/librustdoc/html/render/span_map.rs
@@ -4,7 +4,9 @@ use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::{DefId, LOCAL_CRATE};
 use rustc_hir::intravisit::{self, Visitor};
-use rustc_hir::{ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatKind, QPath};
+use rustc_hir::{
+    ExprKind, HirId, Item, ItemKind, Mod, Node, Pat, PatExpr, PatExprKind, PatKind, QPath,
+};
 use rustc_middle::hir::nested_filter;
 use rustc_middle::ty::TyCtxt;
 use rustc_span::hygiene::MacroKind;
@@ -191,17 +193,21 @@ impl SpanMapVisitor<'_> {
     }
 
     fn handle_pat(&mut self, p: &Pat<'_>) {
+        let mut check_qpath = |qpath, hir_id| match qpath {
+            QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
+                self.infer_id(path.hir_id, Some(hir_id), qpath.span());
+            }
+            QPath::Resolved(_, path) => self.handle_path(path),
+            _ => {}
+        };
         match p.kind {
             PatKind::Binding(_, _, _, Some(p)) => self.handle_pat(p),
-            PatKind::Struct(qpath, _, _)
-            | PatKind::TupleStruct(qpath, _, _)
-            | PatKind::Path(qpath) => match qpath {
-                QPath::TypeRelative(_, path) if matches!(path.res, Res::Err) => {
-                    self.infer_id(path.hir_id, Some(p.hir_id), qpath.span());
-                }
-                QPath::Resolved(_, path) => self.handle_path(path),
-                _ => {}
-            },
+            PatKind::Struct(qpath, _, _) | PatKind::TupleStruct(qpath, _, _) => {
+                check_qpath(qpath, p.hir_id)
+            }
+            PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), hir_id, .. }) => {
+                check_qpath(*qpath, *hir_id)
+            }
             PatKind::Or(pats) => {
                 for pat in pats {
                     self.handle_pat(pat);
diff --git a/src/librustdoc/html/static/js/README.md b/src/librustdoc/html/static/js/README.md
index 1fd859ad7cf..e99d7330f0e 100644
--- a/src/librustdoc/html/static/js/README.md
+++ b/src/librustdoc/html/static/js/README.md
@@ -3,13 +3,9 @@
 These JavaScript files are incorporated into the rustdoc binary at build time,
 and are minified and written to the filesystem as part of the doc build process.
 
-We use the [Closure Compiler](https://github.com/google/closure-compiler/wiki/Annotating-JavaScript-for-the-Closure-Compiler)
+We use the [TypeScript Compiler](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html)
 dialect of JSDoc to comment our code and annotate params and return types.
 To run a check:
 
-    ./x.py doc library/std
-    npm i -g google-closure-compiler
-    google-closure-compiler -W VERBOSE \
-      build/<YOUR PLATFORM>/doc/{search-index*.js,crates*.js} \
-      src/librustdoc/html/static/js/{search.js,main.js,storage.js} \
-      --externs src/librustdoc/html/static/js/externs.js >/dev/null
+    npm i -g typescript
+    tsc --project tsconfig.json
diff --git a/src/librustdoc/html/static/js/externs.js b/src/librustdoc/html/static/js/externs.js
deleted file mode 100644
index c4faca1c0c3..00000000000
--- a/src/librustdoc/html/static/js/externs.js
+++ /dev/null
@@ -1,270 +0,0 @@
-// This file contains type definitions that are processed by the Closure Compiler but are
-// not put into the JavaScript we include as part of the documentation. It is used for
-// type checking. See README.md in this directory for more info.
-
-/* eslint-disable */
-let searchState;
-function initSearch(searchIndex){}
-
-/**
- * @typedef {{
- *     name: string,
- *     id: number|null,
- *     fullPath: Array<string>,
- *     pathWithoutLast: Array<string>,
- *     pathLast: string,
- *     generics: Array<QueryElement>,
- *     bindings: Map<number, Array<QueryElement>>,
- * }}
- */
-let QueryElement;
-
-/**
- * @typedef {{
- *      pos: number,
- *      totalElems: number,
- *      typeFilter: (null|string),
- *      userQuery: string,
- *      isInBinding: (null|string),
- * }}
- */
-let ParserState;
-
-/**
- * @typedef {{
- *     original: string,
- *     userQuery: string,
- *     typeFilter: number,
- *     elems: Array<QueryElement>,
- *     args: Array<QueryElement>,
- *     returned: Array<QueryElement>,
- *     foundElems: number,
- *     totalElems: number,
- *     literalSearch: boolean,
- *     hasReturnArrow: boolean,
- *     corrections: Array<{from: string, to: integer}> | null,
- *     typeFingerprint: Uint32Array,
- *     error: Array<string> | null,
- * }}
- */
-let ParsedQuery;
-
-/**
- * @typedef {{
- *    crate: string,
- *    desc: string,
- *    id: number,
- *    name: string,
- *    normalizedName: string,
- *    parent: (Object|null|undefined),
- *    path: string,
- *    ty: (Number|null|number),
- *    type: FunctionSearchType?
- * }}
- */
-let Row;
-
-/**
- * @typedef {{
- *    in_args: Array<Object>,
- *    returned: Array<Object>,
- *    others: Array<Object>,
- *    query: ParsedQuery,
- * }}
- */
-let ResultsTable;
-
-/**
- * @typedef {Map<String, ResultObject>}
- */
-let Results;
-
-/**
- * @typedef {{
- *     desc: string,
- *     displayPath: string,
- *     fullPath: string,
- *     href: string,
- *     id: number,
- *     lev: number,
- *     name: string,
- *     normalizedName: string,
- *     parent: (Object|undefined),
- *     path: string,
- *     ty: number,
- *     type: FunctionSearchType?,
- *     displayType: Promise<Array<Array<string>>>|null,
- *     displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
- * }}
- */
-let ResultObject;
-
-/**
- * A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
- * The JavaScript deserializes this into FunctionSearchType.
- *
- * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
- * because `null` is four bytes while `0` is one byte.
- *
- * An input or output can be encoded as just a number if there is only one of them, AND
- * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
- * a function with a single output, and that output had a single generic:
- *
- *     fn something() -> Result<usize, usize>
- *
- * If output was allowed to be any RawFunctionType, it would look like thi
- *
- *     [[], [50, [3, 3]]]
- *
- * The problem is that the above output could be interpreted as either a type with ID 50 and two
- * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
- * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
- * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
- * is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
- *
- * The output can be skipped if it's actually unit and there's no type constraints. If thi
- * function accepts constrained generics, then the output will be unconditionally emitted, and
- * after it will come a list of trait constraints. The position of the item in the list will
- * determine which type parameter it is. For example:
- *
- *     [1, 2, 3, 4, 5]
- *      ^  ^  ^  ^  ^
- *      |  |  |  |  - generic parameter (-3) of trait 5
- *      |  |  |  - generic parameter (-2) of trait 4
- *      |  |  - generic parameter (-1) of trait 3
- *      |  - this function returns a single value (type 2)
- *      - this function takes a single input parameter (type 1)
- *
- * Or, for a less contrived version:
- *
- *     [[[4, -1], 3], [[5, -1]], 11]
- *      -^^^^^^^----   ^^^^^^^   ^^
- *       |        |    |          - generic parameter, roughly `where -1: 11`
- *       |        |    |            since -1 is the type parameter and 11 the trait
- *       |        |    - function output 5<-1>
- *       |        - the overall function signature is something like
- *       |          `fn(4<-1>, 3) -> 5<-1> where -1: 11`
- *       - function input, corresponds roughly to 4<-1>
- *         4 is an index into the `p` array for a type
- *         -1 is the generic parameter, given by 11
- *
- * If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
- * function inputs and outputs:
- *
- *     [-1, -1, [4, 3]]
- *              ^^^^^^ where -1: 4 + 3
- *
- * If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
- * even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
- * favor of `4 + 3`:
- *
- *     [-1, -1, [[4, 3]]]
- *              ^^^^^^^^ where -1: 4 + 3
- *
- *     [-1, -1, [5, [4, 3]]]
- *              ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
- *
- * If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
- * implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
- *
- * @typedef {(
- *     0 |
- *     [(number|Array<RawFunctionType>)] |
- *     [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
- *     Array<(number|Array<RawFunctionType>)>
- * )}
- */
-let RawFunctionSearchType;
-
-/**
- * A single function input or output type. This is either a single path ID, or a pair of
- * [path ID, generics].
- *
- * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
- * because `null` is four bytes while `0` is one byte.
- *
- * @typedef {number | [number, Array<RawFunctionType>]}
- */
-let RawFunctionType;
-
-/**
- * @typedef {{
- *     inputs: Array<FunctionType>,
- *     output: Array<FunctionType>,
- *     where_clause: Array<Array<FunctionType>>,
- * }}
- */
-let FunctionSearchType;
-
-/**
- * @typedef {{
- *     id: (null|number),
- *     ty: number,
- *     generics: Array<FunctionType>,
- *     bindings: Map<integer, Array<FunctionType>>,
- * }}
- */
-let FunctionType;
-
-/**
- * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
- * are arrays with the same length. `q`, `a`, and `c` use a sparse
- * representation for compactness.
- *
- * `n[i]` contains the name of an item.
- *
- * `t[i]` contains the type of that item
- * (as a string of characters that represent an offset in `itemTypes`).
- *
- * `d[i]` contains the description of that item.
- *
- * `q` contains the full paths of the items. For compactness, it is a set of
- * (index, path) pairs used to create a map. If a given index `i` is
- * not present, this indicates "same as the last index present".
- *
- * `i[i]` contains an item's parent, usually a module. For compactness,
- * it is a set of indexes into the `p` array.
- *
- * `f` contains function signatures, or `0` if the item isn't a function.
- * More information on how they're encoded can be found in rustc-dev-guide
- *
- * Functions are themselves encoded as arrays. The first item is a list of
- * types representing the function's inputs, and the second list item is a list
- * of types representing the function's output. Tuples are flattened.
- * Types are also represented as arrays; the first item is an index into the `p`
- * array, while the second is a list of types representing any generic parameters.
- *
- * b[i] contains an item's impl disambiguator. This is only present if an item
- * is defined in an impl block and, the impl block's type has more than one associated
- * item with the same name.
- *
- * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
- * points into the n/t/d/q/i/f arrays.
- *
- * `doc` contains the description of the crate.
- *
- * `p` is a list of path/type pairs. It is used for parents and function parameters.
- * The first item is the type, the second is the name, the third is the visible path (if any) and
- * the fourth is the canonical path used for deduplication (if any).
- *
- * `r` is the canonical path used for deduplication of re-exported items.
- * It is not used for associated items like methods (that's the fourth element
- * of `p`) but is used for modules items like free functions.
- *
- * `c` is an array of item indices that are deprecated.
- * @typedef {{
- *   doc: string,
- *   a: Object,
- *   n: Array<string>,
- *   t: string,
- *   d: Array<string>,
- *   q: Array<[number, string]>,
- *   i: Array<number>,
- *   f: string,
- *   p: Array<[number, string] | [number, string, number] | [number, string, number, number]>,
- *   b: Array<[number, String]>,
- *   c: Array<number>,
- *   r: Array<[number, number]>,
- * }}
- */
-let RawSearchIndexCrate;
diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js
index 984b0877d8d..ccf4002bb30 100644
--- a/src/librustdoc/html/static/js/main.js
+++ b/src/librustdoc/html/static/js/main.js
@@ -11,8 +11,13 @@
 window.RUSTDOC_TOOLTIP_HOVER_MS = 300;
 window.RUSTDOC_TOOLTIP_HOVER_EXIT_MS = 450;
 
-// Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
-// for a resource under the root-path, with the resource-suffix.
+/**
+ * Given a basename (e.g. "storage") and an extension (e.g. ".js"), return a URL
+ * for a resource under the root-path, with the resource-suffix.
+ *
+ * @param {string} basename
+ * @param {string} extension
+ */
 function resourcePath(basename, extension) {
     return getVar("root-path") + basename + getVar("resource-suffix") + extension;
 }
@@ -27,13 +32,18 @@ function hideMain() {
 
 function showMain() {
     const main = document.getElementById(MAIN_ID);
+    if (!main) {
+        return;
+    }
     removeClass(main, "hidden");
     const mainHeading = main.querySelector(".main-heading");
-    if (mainHeading && searchState.rustdocToolbar) {
-        if (searchState.rustdocToolbar.parentElement) {
-            searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
+    if (mainHeading && window.searchState.rustdocToolbar) {
+        if (window.searchState.rustdocToolbar.parentElement) {
+            window.searchState.rustdocToolbar.parentElement.removeChild(
+                window.searchState.rustdocToolbar,
+            );
         }
-        mainHeading.appendChild(searchState.rustdocToolbar);
+        mainHeading.appendChild(window.searchState.rustdocToolbar);
     }
     const toggle = document.getElementById("toggle-all-docs");
     if (toggle) {
@@ -61,16 +71,20 @@ function setMobileTopbar() {
     }
 }
 
-// Gets the human-readable string for the virtual-key code of the
-// given KeyboardEvent, ev.
-//
-// This function is meant as a polyfill for KeyboardEvent#key,
-// since it is not supported in IE 11 or Chrome for Android. We also test for
-// KeyboardEvent#keyCode because the handleShortcut handler is
-// also registered for the keydown event, because Blink doesn't fire
-// keypress on hitting the Escape key.
-//
-// So I guess you could say things are getting pretty interoperable.
+/**
+ * Gets the human-readable string for the virtual-key code of the
+ * given KeyboardEvent, ev.
+ *
+ * This function is meant as a polyfill for KeyboardEvent#key,
+ * since it is not supported in IE 11 or Chrome for Android. We also test for
+ * KeyboardEvent#keyCode because the handleShortcut handler is
+ * also registered for the keydown event, because Blink doesn't fire
+ * keypress on hitting the Escape key.
+ *
+ * So I guess you could say things are getting pretty interoperable.
+ *
+ * @param {KeyboardEvent} ev
+ */
 function getVirtualKey(ev) {
     if ("key" in ev && typeof ev.key !== "undefined") {
         return ev.key;
@@ -110,6 +124,9 @@ function getNakedUrl() {
  * @param {HTMLElement} referenceNode
  */
 function insertAfter(newNode, referenceNode) {
+    // You're not allowed to pass an element with no parent.
+    // I dunno how to make TS's typechecker see that.
+    // @ts-expect-error
     referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling);
 }
 
@@ -129,6 +146,7 @@ function getOrCreateSection(id, classes) {
         el = document.createElement("section");
         el.id = id;
         el.className = classes;
+        // @ts-expect-error
         insertAfter(el, document.getElementById(MAIN_ID));
     }
     return el;
@@ -159,12 +177,13 @@ function getNotDisplayedElem() {
  * contains the displayed element (there can be only one at the same time!). So basically, we switch
  * elements between the two `<section>` elements.
  *
- * @param {HTMLElement} elemToDisplay
+ * @param {HTMLElement|null} elemToDisplay
  */
 function switchDisplayedElement(elemToDisplay) {
     const el = getAlternativeDisplayElem();
 
     if (el.children.length > 0) {
+        // @ts-expect-error
         getNotDisplayedElem().appendChild(el.firstElementChild);
     }
     if (elemToDisplay === null) {
@@ -177,10 +196,14 @@ function switchDisplayedElement(elemToDisplay) {
     removeClass(el, "hidden");
 
     const mainHeading = elemToDisplay.querySelector(".main-heading");
+    // @ts-expect-error
     if (mainHeading && searchState.rustdocToolbar) {
+        // @ts-expect-error
         if (searchState.rustdocToolbar.parentElement) {
+            // @ts-expect-error
             searchState.rustdocToolbar.parentElement.removeChild(searchState.rustdocToolbar);
         }
+        // @ts-expect-error
         mainHeading.appendChild(searchState.rustdocToolbar);
     }
 }
@@ -189,6 +212,7 @@ function browserSupportsHistoryApi() {
     return window.history && typeof window.history.pushState === "function";
 }
 
+// @ts-expect-error
 function preLoadCss(cssUrl) {
     // https://developer.mozilla.org/en-US/docs/Web/HTML/Link_types/preload
     const link = document.createElement("link");
@@ -201,6 +225,7 @@ function preLoadCss(cssUrl) {
 (function() {
     const isHelpPage = window.location.pathname.endsWith("/help.html");
 
+    // @ts-expect-error
     function loadScript(url, errorCallback) {
         const script = document.createElement("script");
         script.src = url;
@@ -211,21 +236,25 @@ function preLoadCss(cssUrl) {
     }
 
     if (getSettingsButton()) {
+        // @ts-expect-error
         getSettingsButton().onclick = event => {
             if (event.ctrlKey || event.altKey || event.metaKey) {
                 return;
             }
+            // @ts-expect-error
             window.hideAllModals(false);
             addClass(getSettingsButton(), "rotate");
             event.preventDefault();
             // Sending request for the CSS and the JS files at the same time so it will
             // hopefully be loaded when the JS will generate the settings content.
+            // @ts-expect-error
             loadScript(getVar("static-root-path") + getVar("settings-js"));
             // Pre-load all theme CSS files, so that switching feels seamless.
             //
             // When loading settings.html as a standalone page, the equivalent HTML is
             // generated in context.rs.
             setTimeout(() => {
+                // @ts-expect-error
                 const themes = getVar("themes").split(",");
                 for (const theme of themes) {
                     // if there are no themes, do nothing
@@ -241,6 +270,8 @@ function preLoadCss(cssUrl) {
     window.searchState = {
         rustdocToolbar: document.querySelector("rustdoc-toolbar"),
         loadingText: "Loading search results...",
+        // This will always be an HTMLInputElement, but tsc can't see that
+        // @ts-expect-error
         input: document.getElementsByClassName("search-input")[0],
         outputElement: () => {
             let el = document.getElementById("search");
@@ -263,31 +294,38 @@ function preLoadCss(cssUrl) {
         // tab and back preserves the element that was focused.
         focusedByTab: [null, null, null],
         clearInputTimeout: () => {
-            if (searchState.timeout !== null) {
-                clearTimeout(searchState.timeout);
-                searchState.timeout = null;
+            if (window.searchState.timeout !== null) {
+                clearTimeout(window.searchState.timeout);
+                window.searchState.timeout = null;
             }
         },
-        isDisplayed: () => searchState.outputElement().parentElement.id === ALTERNATIVE_DISPLAY_ID,
+        // @ts-expect-error
+        isDisplayed: () => {
+            const outputElement = window.searchState.outputElement();
+            return outputElement &&
+                outputElement.parentElement &&
+                outputElement.parentElement.id === ALTERNATIVE_DISPLAY_ID;
+        },
         // Sets the focus on the search bar at the top of the page
         focus: () => {
-            searchState.input.focus();
+            window.searchState.input && window.searchState.input.focus();
         },
         // Removes the focus from the search bar.
         defocus: () => {
-            searchState.input.blur();
+            window.searchState.input && window.searchState.input.blur();
         },
         showResults: search => {
             if (search === null || typeof search === "undefined") {
-                search = searchState.outputElement();
+                search = window.searchState.outputElement();
             }
             switchDisplayedElement(search);
-            searchState.mouseMovedAfterSearch = false;
-            document.title = searchState.title;
+            // @ts-expect-error
+            window.searchState.mouseMovedAfterSearch = false;
+            document.title = window.searchState.title;
         },
         removeQueryParameters: () => {
             // We change the document title.
-            document.title = searchState.titleBeforeSearch;
+            document.title = window.searchState.titleBeforeSearch;
             if (browserSupportsHistoryApi()) {
                 history.replaceState(null, "", getNakedUrl() + window.location.hash);
             }
@@ -295,9 +333,10 @@ function preLoadCss(cssUrl) {
         hideResults: () => {
             switchDisplayedElement(null);
             // We also remove the query parameter from the URL.
-            searchState.removeQueryParameters();
+            window.searchState.removeQueryParameters();
         },
         getQueryStringParams: () => {
+            /** @type {Object.<any, string>} */
             const params = {};
             window.location.search.substring(1).split("&").
                 map(s => {
@@ -309,26 +348,28 @@ function preLoadCss(cssUrl) {
             return params;
         },
         setup: () => {
-            const search_input = searchState.input;
-            if (!searchState.input) {
+            const search_input = window.searchState.input;
+            if (!search_input) {
                 return;
             }
             let searchLoaded = false;
             // If you're browsing the nightly docs, the page might need to be refreshed for the
             // search to work because the hash of the JS scripts might have changed.
             function sendSearchForm() {
+                // @ts-expect-error
                 document.getElementsByClassName("search-form")[0].submit();
             }
             function loadSearch() {
                 if (!searchLoaded) {
                     searchLoaded = true;
+                    // @ts-expect-error
                     loadScript(getVar("static-root-path") + getVar("search-js"), sendSearchForm);
                     loadScript(resourcePath("search-index", ".js"), sendSearchForm);
                 }
             }
 
             search_input.addEventListener("focus", () => {
-                search_input.origPlaceholder = search_input.placeholder;
+                window.searchState.origPlaceholder = search_input.placeholder;
                 search_input.placeholder = "Type your search here.";
                 loadSearch();
             });
@@ -337,16 +378,21 @@ function preLoadCss(cssUrl) {
                 loadSearch();
             }
 
-            const params = searchState.getQueryStringParams();
+            const params = window.searchState.getQueryStringParams();
             if (params.search !== undefined) {
-                searchState.setLoadingSearch();
+                window.searchState.setLoadingSearch();
                 loadSearch();
             }
         },
         setLoadingSearch: () => {
-            const search = searchState.outputElement();
-            search.innerHTML = "<h3 class=\"search-loading\">" + searchState.loadingText + "</h3>";
-            searchState.showResults(search);
+            const search = window.searchState.outputElement();
+            if (!search) {
+                return;
+            }
+            search.innerHTML = "<h3 class=\"search-loading\">" +
+                window.searchState.loadingText +
+                "</h3>";
+            window.searchState.showResults(search);
         },
         descShards: new Map(),
         loadDesc: async function({descShard, descIndex}) {
@@ -370,6 +416,8 @@ function preLoadCss(cssUrl) {
             return list[descIndex];
         },
         loadedDescShard: function(crate, shard, data) {
+            // If loadedDescShard gets called, then the library must have been declared.
+            // @ts-expect-error
             this.descShards.get(crate)[shard].resolve(data.split("\n"));
         },
     };
@@ -377,8 +425,11 @@ function preLoadCss(cssUrl) {
     const toggleAllDocsId = "toggle-all-docs";
     let savedHash = "";
 
+    /**
+     * @param {HashChangeEvent|null} ev
+     */
     function handleHashes(ev) {
-        if (ev !== null && searchState.isDisplayed() && ev.newURL) {
+        if (ev !== null && window.searchState.isDisplayed() && ev.newURL) {
             // This block occurs when clicking on an element in the navbar while
             // in a search.
             switchDisplayedElement(null);
@@ -419,6 +470,7 @@ function preLoadCss(cssUrl) {
                     }
                     return onEachLazy(implElem.parentElement.parentElement.querySelectorAll(
                         `[id^="${assocId}"]`),
+                        // @ts-expect-error
                         item => {
                             const numbered = /^(.+?)-([0-9]+)$/.exec(item.id);
                             if (item.id === assocId || (numbered && numbered[1] === assocId)) {
@@ -437,12 +489,16 @@ function preLoadCss(cssUrl) {
         }
     }
 
+    /**
+     * @param {HashChangeEvent|null} ev
+     */
     function onHashChange(ev) {
         // If we're in mobile mode, we should hide the sidebar in any case.
         hideSidebar();
         handleHashes(ev);
     }
 
+    // @ts-expect-error
     function openParentDetails(elem) {
         while (elem) {
             if (elem.tagName === "DETAILS") {
@@ -452,18 +508,25 @@ function preLoadCss(cssUrl) {
         }
     }
 
+    // @ts-expect-error
     function expandSection(id) {
         openParentDetails(document.getElementById(id));
     }
 
+    // @ts-expect-error
     function handleEscape(ev) {
+        // @ts-expect-error
         searchState.clearInputTimeout();
+        // @ts-expect-error
         searchState.hideResults();
         ev.preventDefault();
+        // @ts-expect-error
         searchState.defocus();
+        // @ts-expect-error
         window.hideAllModals(true); // true = reset focus for tooltips
     }
 
+    // @ts-expect-error
     function handleShortcut(ev) {
         // Don't interfere with browser shortcuts
         const disableShortcuts = getSettingValue("disable-shortcuts") === "true";
@@ -471,8 +534,11 @@ function preLoadCss(cssUrl) {
             return;
         }
 
+        // @ts-expect-error
         if (document.activeElement.tagName === "INPUT" &&
+            // @ts-expect-error
             document.activeElement.type !== "checkbox" &&
+            // @ts-expect-error
             document.activeElement.type !== "radio") {
             switch (getVirtualKey(ev)) {
             case "Escape":
@@ -489,6 +555,7 @@ function preLoadCss(cssUrl) {
             case "S":
             case "/":
                 ev.preventDefault();
+                // @ts-expect-error
                 searchState.focus();
                 break;
 
@@ -515,6 +582,7 @@ function preLoadCss(cssUrl) {
     document.addEventListener("keydown", handleShortcut);
 
     function addSidebarItems() {
+        // @ts-expect-error
         if (!window.SIDEBAR_ITEMS) {
             return;
         }
@@ -529,6 +597,7 @@ function preLoadCss(cssUrl) {
          *                          "Modules", or "Macros".
          */
         function block(shortty, id, longty) {
+            // @ts-expect-error
             const filtered = window.SIDEBAR_ITEMS[shortty];
             if (!filtered) {
                 return;
@@ -564,7 +633,9 @@ function preLoadCss(cssUrl) {
                 li.appendChild(link);
                 ul.appendChild(li);
             }
+            // @ts-expect-error
             sidebar.appendChild(h3);
+            // @ts-expect-error
             sidebar.appendChild(ul);
         }
 
@@ -600,6 +671,7 @@ function preLoadCss(cssUrl) {
     }
 
     // <https://github.com/search?q=repo%3Arust-lang%2Frust+[RUSTDOCIMPL]+trait.impl&type=code>
+    // @ts-expect-error
     window.register_implementors = imp => {
         const implementors = document.getElementById("implementors-list");
         const synthetic_implementors = document.getElementById("synthetic-implementors-list");
@@ -615,18 +687,22 @@ function preLoadCss(cssUrl) {
             //
             // By the way, this is only used by and useful for traits implemented automatically
             // (like "Send" and "Sync").
+            // @ts-expect-error
             onEachLazy(synthetic_implementors.getElementsByClassName("impl"), el => {
                 const aliases = el.getAttribute("data-aliases");
                 if (!aliases) {
                     return;
                 }
+                // @ts-expect-error
                 aliases.split(",").forEach(alias => {
                     inlined_types.add(alias);
                 });
             });
         }
 
+        // @ts-expect-error
         let currentNbImpls = implementors.getElementsByClassName("impl").length;
+        // @ts-expect-error
         const traitName = document.querySelector(".main-heading h1 > .trait").textContent;
         const baseIdName = "impl-" + traitName + "-";
         const libs = Object.getOwnPropertyNames(imp);
@@ -636,6 +712,7 @@ function preLoadCss(cssUrl) {
         const script = document
             .querySelector("script[data-ignore-extern-crates]");
         const ignoreExternCrates = new Set(
+            // @ts-expect-error
             (script ? script.getAttribute("data-ignore-extern-crates") : "").split(","),
         );
         for (const lib of libs) {
@@ -663,6 +740,7 @@ function preLoadCss(cssUrl) {
                 code.innerHTML = struct[TEXT_IDX];
                 addClass(code, "code-header");
 
+                // @ts-expect-error
                 onEachLazy(code.getElementsByTagName("a"), elem => {
                     const href = elem.getAttribute("href");
 
@@ -681,12 +759,15 @@ function preLoadCss(cssUrl) {
                 addClass(display, "impl");
                 display.appendChild(anchor);
                 display.appendChild(code);
+                // @ts-expect-error
                 list.appendChild(display);
                 currentNbImpls += 1;
             }
         }
     };
+    // @ts-expect-error
     if (window.pending_implementors) {
+        // @ts-expect-error
         window.register_implementors(window.pending_implementors);
     }
 
@@ -719,12 +800,15 @@ function preLoadCss(cssUrl) {
      *
      * - After processing all of the impls, it sorts the sidebar items by name.
      *
-     * @param {{[cratename: string]: Array<Array<string|0>>}} impl
+     * @param {{[cratename: string]: Array<Array<string|0>>}} imp
      */
+    // @ts-expect-error
     window.register_type_impls = imp => {
+        // @ts-expect-error
         if (!imp || !imp[window.currentCrate]) {
             return;
         }
+        // @ts-expect-error
         window.pending_type_impls = null;
         const idMap = new Map();
 
@@ -744,6 +828,7 @@ function preLoadCss(cssUrl) {
         let associatedConstants = document.querySelector(".sidebar .block.associatedconstant");
         let sidebarTraitList = document.querySelector(".sidebar .block.trait-implementation");
 
+        // @ts-expect-error
         for (const impList of imp[window.currentCrate]) {
             const types = impList.slice(2);
             const text = impList[0];
@@ -772,20 +857,28 @@ function preLoadCss(cssUrl) {
                     h.appendChild(link);
                     trait_implementations = outputList;
                     trait_implementations_header = outputListHeader;
+                    // @ts-expect-error
                     sidebarSection.appendChild(h);
                     sidebarTraitList = document.createElement("ul");
                     sidebarTraitList.className = "block trait-implementation";
+                    // @ts-expect-error
                     sidebarSection.appendChild(sidebarTraitList);
+                    // @ts-expect-error
                     mainContent.appendChild(outputListHeader);
+                    // @ts-expect-error
                     mainContent.appendChild(outputList);
                 } else {
                     implementations = outputList;
                     if (trait_implementations) {
+                        // @ts-expect-error
                         mainContent.insertBefore(outputListHeader, trait_implementations_header);
+                        // @ts-expect-error
                         mainContent.insertBefore(outputList, trait_implementations_header);
                     } else {
                         const mainContent = document.querySelector("#main-content");
+                        // @ts-expect-error
                         mainContent.appendChild(outputListHeader);
+                        // @ts-expect-error
                         mainContent.appendChild(outputList);
                     }
                 }
@@ -793,6 +886,7 @@ function preLoadCss(cssUrl) {
             const template = document.createElement("template");
             template.innerHTML = text;
 
+            // @ts-expect-error
             onEachLazy(template.content.querySelectorAll("a"), elem => {
                 const href = elem.getAttribute("href");
 
@@ -800,6 +894,7 @@ function preLoadCss(cssUrl) {
                     elem.setAttribute("href", window.rootPath + href);
                 }
             });
+            // @ts-expect-error
             onEachLazy(template.content.querySelectorAll("[id]"), el => {
                 let i = 0;
                 if (idMap.has(el.id)) {
@@ -817,6 +912,7 @@ function preLoadCss(cssUrl) {
                     const oldHref = `#${el.id}`;
                     const newHref = `#${el.id}-${i}`;
                     el.id = `${el.id}-${i}`;
+                    // @ts-expect-error
                     onEachLazy(template.content.querySelectorAll("a[href]"), link => {
                         if (link.getAttribute("href") === oldHref) {
                             link.href = newHref;
@@ -830,11 +926,14 @@ function preLoadCss(cssUrl) {
             if (isTrait) {
                 const li = document.createElement("li");
                 const a = document.createElement("a");
+                // @ts-expect-error
                 a.href = `#${template.content.querySelector(".impl").id}`;
                 a.textContent = traitName;
                 li.appendChild(a);
+                // @ts-expect-error
                 sidebarTraitList.append(li);
             } else {
+                // @ts-expect-error
                 onEachLazy(templateAssocItems, item => {
                     let block = hasClass(item, "associatedtype") ? associatedTypes : (
                         hasClass(item, "associatedconstant") ? associatedConstants : (
@@ -856,10 +955,14 @@ function preLoadCss(cssUrl) {
                         const insertionReference = methods || sidebarTraitList;
                         if (insertionReference) {
                             const insertionReferenceH = insertionReference.previousElementSibling;
+                            // @ts-expect-error
                             sidebarSection.insertBefore(blockHeader, insertionReferenceH);
+                            // @ts-expect-error
                             sidebarSection.insertBefore(block, insertionReferenceH);
                         } else {
+                            // @ts-expect-error
                             sidebarSection.appendChild(blockHeader);
+                            // @ts-expect-error
                             sidebarSection.appendChild(block);
                         }
                         if (hasClass(item, "associatedtype")) {
@@ -896,11 +999,14 @@ function preLoadCss(cssUrl) {
             list.replaceChildren(...newChildren);
         }
     };
+    // @ts-expect-error
     if (window.pending_type_impls) {
+        // @ts-expect-error
         window.register_type_impls(window.pending_type_impls);
     }
 
     function addSidebarCrates() {
+        // @ts-expect-error
         if (!window.ALL_CRATES) {
             return;
         }
@@ -914,6 +1020,7 @@ function preLoadCss(cssUrl) {
         const ul = document.createElement("ul");
         ul.className = "block crate";
 
+        // @ts-expect-error
         for (const crate of window.ALL_CRATES) {
             const link = document.createElement("a");
             link.href = window.rootPath + crate + "/index.html";
@@ -933,17 +1040,20 @@ function preLoadCss(cssUrl) {
     function expandAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         removeClass(innerToggle, "will-expand");
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hasClass(e, "type-contents-toggle") && !hasClass(e, "more-examples-toggle")) {
                 e.open = true;
             }
         });
+        // @ts-expect-error
         innerToggle.children[0].innerText = "Summary";
     }
 
     function collapseAllDocs() {
         const innerToggle = document.getElementById(toggleAllDocsId);
         addClass(innerToggle, "will-expand");
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (e.parentNode.id !== "implementations-list" ||
                 (!hasClass(e, "implementors-toggle") &&
@@ -952,6 +1062,7 @@ function preLoadCss(cssUrl) {
                 e.open = false;
             }
         });
+        // @ts-expect-error
         innerToggle.children[0].innerText = "Show all";
     }
 
@@ -977,9 +1088,11 @@ function preLoadCss(cssUrl) {
         const hideImplementations = getSettingValue("auto-hide-trait-implementations") === "true";
         const hideLargeItemContents = getSettingValue("auto-hide-large-items") !== "false";
 
+        // @ts-expect-error
         function setImplementorsTogglesOpen(id, open) {
             const list = document.getElementById(id);
             if (list !== null) {
+                // @ts-expect-error
                 onEachLazy(list.getElementsByClassName("implementors-toggle"), e => {
                     e.open = open;
                 });
@@ -991,6 +1104,7 @@ function preLoadCss(cssUrl) {
             setImplementorsTogglesOpen("blanket-implementations-list", false);
         }
 
+        // @ts-expect-error
         onEachLazy(document.getElementsByClassName("toggle"), e => {
             if (!hideLargeItemContents && hasClass(e, "type-contents-toggle")) {
                 e.open = true;
@@ -1002,6 +1116,7 @@ function preLoadCss(cssUrl) {
         });
     }());
 
+    // @ts-expect-error
     window.rustdoc_add_line_numbers_to_examples = () => {
         if (document.querySelector(".rustdoc.src")) {
             // We are in the source code page, nothing to be done here!
@@ -1009,6 +1124,7 @@ function preLoadCss(cssUrl) {
         }
         onEachLazy(document.querySelectorAll(
             ":not(.scraped-example) > .example-wrap > pre:not(.example-line-numbers)",
+        // @ts-expect-error
         ), x => {
             const parent = x.parentNode;
             const line_numbers = parent.querySelectorAll(".example-line-numbers");
@@ -1027,33 +1143,41 @@ function preLoadCss(cssUrl) {
         });
     };
 
+    // @ts-expect-error
     window.rustdoc_remove_line_numbers_from_examples = () => {
+        // @ts-expect-error
         onEachLazy(document.querySelectorAll(".example-wrap > .example-line-numbers"), x => {
             x.parentNode.removeChild(x);
         });
     };
 
     if (getSettingValue("line-numbers") === "true") {
+        // @ts-expect-error
         window.rustdoc_add_line_numbers_to_examples();
     }
 
     function showSidebar() {
+        // @ts-expect-error
         window.hideAllModals(false);
         const sidebar = document.getElementsByClassName("sidebar")[0];
+        // @ts-expect-error
         addClass(sidebar, "shown");
     }
 
     function hideSidebar() {
         const sidebar = document.getElementsByClassName("sidebar")[0];
+        // @ts-expect-error
         removeClass(sidebar, "shown");
     }
 
     window.addEventListener("resize", () => {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT) {
             // As a workaround to the behavior of `contains: layout` used in doc togglers,
             // tooltip popovers are positioned using javascript.
             //
             // This means when the window is resized, we need to redo the layout.
+            // @ts-expect-error
             const base = window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE;
             const force_visible = base.TOOLTIP_FORCE_VISIBLE;
             hideTooltip(false);
@@ -1069,6 +1193,7 @@ function preLoadCss(cssUrl) {
         mainElem.addEventListener("click", hideSidebar);
     }
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll("a[href^='#']"), el => {
         // For clicks on internal links (<A> tags with a hash property), we expand the section we're
         // jumping to *before* jumping there. We can't do this in onHashChange, because it changes
@@ -1079,7 +1204,9 @@ function preLoadCss(cssUrl) {
         });
     });
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll(".toggle > summary:not(.hideme)"), el => {
+        // @ts-expect-error
         el.addEventListener("click", e => {
             if (e.target.tagName !== "SUMMARY" && e.target.tagName !== "A") {
                 e.preventDefault();
@@ -1090,15 +1217,17 @@ function preLoadCss(cssUrl) {
     /**
      * Show a tooltip immediately.
      *
-     * @param {DOMElement} e - The tooltip's anchor point. The DOM is consulted to figure
-     *                         out what the tooltip should contain, and where it should be
-     *                         positioned.
+     * @param {HTMLElement} e - The tooltip's anchor point. The DOM is consulted to figure
+     *                          out what the tooltip should contain, and where it should be
+     *                          positioned.
      */
     function showTooltip(e) {
         const notable_ty = e.getAttribute("data-notable-ty");
+        // @ts-expect-error
         if (!window.NOTABLE_TRAITS && notable_ty) {
             const data = document.getElementById("notable-traits-data");
             if (data) {
+                // @ts-expect-error
                 window.NOTABLE_TRAITS = JSON.parse(data.innerText);
             } else {
                 throw new Error("showTooltip() called with notable without any notable traits!");
@@ -1106,36 +1235,44 @@ function preLoadCss(cssUrl) {
         }
         // Make this function idempotent. If the tooltip is already shown, avoid doing extra work
         // and leave it alone.
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT && window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE === e) {
+            // @ts-expect-error
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
             return;
         }
+        // @ts-expect-error
         window.hideAllModals(false);
         const wrapper = document.createElement("div");
         if (notable_ty) {
             wrapper.innerHTML = "<div class=\"content\">" +
+                // @ts-expect-error
                 window.NOTABLE_TRAITS[notable_ty] + "</div>";
         } else {
             // Replace any `title` attribute with `data-title` to avoid double tooltips.
-            if (e.getAttribute("title") !== null) {
-                e.setAttribute("data-title", e.getAttribute("title"));
+            const ttl = e.getAttribute("title");
+            if (ttl !== null) {
+                e.setAttribute("data-title", ttl);
                 e.removeAttribute("title");
             }
-            if (e.getAttribute("data-title") !== null) {
+            const dttl = e.getAttribute("data-title");
+            if (dttl !== null) {
                 const titleContent = document.createElement("div");
                 titleContent.className = "content";
-                titleContent.appendChild(document.createTextNode(e.getAttribute("data-title")));
+                titleContent.appendChild(document.createTextNode(dttl));
                 wrapper.appendChild(titleContent);
             }
         }
         wrapper.className = "tooltip popover";
         const focusCatcher = document.createElement("div");
         focusCatcher.setAttribute("tabindex", "0");
+        // @ts-expect-error
         focusCatcher.onfocus = hideTooltip;
         wrapper.appendChild(focusCatcher);
         const pos = e.getBoundingClientRect();
         // 5px overlap so that the mouse can easily travel from place to place
         wrapper.style.top = (pos.top + window.scrollY + pos.height) + "px";
+        // @ts-expect-error
         wrapper.style.left = 0;
         wrapper.style.right = "auto";
         wrapper.style.visibility = "hidden";
@@ -1152,8 +1289,11 @@ function preLoadCss(cssUrl) {
             );
         }
         wrapper.style.visibility = "";
+        // @ts-expect-error
         window.CURRENT_TOOLTIP_ELEMENT = wrapper;
+        // @ts-expect-error
         window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE = e;
+        // @ts-expect-error
         clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
         wrapper.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
@@ -1164,7 +1304,7 @@ function preLoadCss(cssUrl) {
         };
         wrapper.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
-            if (ev.pointerType !== "mouse") {
+            if (ev.pointerType !== "mouse" || !(ev.relatedTarget instanceof HTMLElement)) {
                 return;
             }
             if (!e.TOOLTIP_FORCE_VISIBLE && !e.contains(ev.relatedTarget)) {
@@ -1180,23 +1320,27 @@ function preLoadCss(cssUrl) {
      * was called, that timeout gets cleared. If the tooltip is already in the requested state,
      * this function will still clear any pending timeout, but otherwise do nothing.
      *
-     * @param {DOMElement} element - The tooltip's anchor point. The DOM is consulted to figure
-     *                               out what the tooltip should contain, and where it should be
-     *                               positioned.
+     * @param {HTMLElement} element - The tooltip's anchor point. The DOM is consulted to figure
+     *                                out what the tooltip should contain, and where it should be
+     *                                positioned.
      * @param {boolean}    show    - If true, the tooltip will be made visible. If false, it will
      *                               be hidden.
      */
     function setTooltipHoverTimeout(element, show) {
         clearTooltipHoverTimeout(element);
+        // @ts-expect-error
         if (!show && !window.CURRENT_TOOLTIP_ELEMENT) {
             // To "hide" an already hidden element, just cancel its timeout.
             return;
         }
+        // @ts-expect-error
         if (show && window.CURRENT_TOOLTIP_ELEMENT) {
             // To "show" an already visible element, just cancel its timeout.
             return;
         }
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT &&
+            // @ts-expect-error
             window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE !== element) {
             // Don't do anything if another tooltip is already visible.
             return;
@@ -1214,22 +1358,29 @@ function preLoadCss(cssUrl) {
      * If a show/hide timeout was set by `setTooltipHoverTimeout`, cancel it. If none exists,
      * do nothing.
      *
-     * @param {DOMElement} element - The tooltip's anchor point,
-     *                               as passed to `setTooltipHoverTimeout`.
+     * @param {HTMLElement} element - The tooltip's anchor point,
+     *                                as passed to `setTooltipHoverTimeout`.
      */
     function clearTooltipHoverTimeout(element) {
         if (element.TOOLTIP_HOVER_TIMEOUT !== undefined) {
+            // @ts-expect-error
             removeClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");
             clearTimeout(element.TOOLTIP_HOVER_TIMEOUT);
             delete element.TOOLTIP_HOVER_TIMEOUT;
         }
     }
 
+    // @ts-expect-error
     function tooltipBlurHandler(event) {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) &&
+            // @ts-expect-error
             !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget)
         ) {
             // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari.
@@ -1251,32 +1402,45 @@ function preLoadCss(cssUrl) {
      *                          If set to `false`, leave keyboard focus alone.
      */
     function hideTooltip(focus) {
+        // @ts-expect-error
         if (window.CURRENT_TOOLTIP_ELEMENT) {
+            // @ts-expect-error
             if (window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE) {
                 if (focus) {
+                    // @ts-expect-error
                     window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.focus();
                 }
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.TOOLTIP_FORCE_VISIBLE = false;
             }
+            // @ts-expect-error
             document.body.removeChild(window.CURRENT_TOOLTIP_ELEMENT);
+            // @ts-expect-error
             clearTooltipHoverTimeout(window.CURRENT_TOOLTIP_ELEMENT);
+            // @ts-expect-error
             window.CURRENT_TOOLTIP_ELEMENT = null;
         }
     }
 
+    // @ts-expect-error
     onEachLazy(document.getElementsByClassName("tooltip"), e => {
         e.onclick = () => {
             e.TOOLTIP_FORCE_VISIBLE = e.TOOLTIP_FORCE_VISIBLE ? false : true;
+            // @ts-expect-error
             if (window.CURRENT_TOOLTIP_ELEMENT && !e.TOOLTIP_FORCE_VISIBLE) {
                 hideTooltip(true);
             } else {
                 showTooltip(e);
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.setAttribute("tabindex", "0");
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.focus();
+                // @ts-expect-error
                 window.CURRENT_TOOLTIP_ELEMENT.onblur = tooltipBlurHandler;
             }
             return false;
         };
+        // @ts-expect-error
         e.onpointerenter = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
@@ -1284,6 +1448,7 @@ function preLoadCss(cssUrl) {
             }
             setTooltipHoverTimeout(e, true);
         };
+        // @ts-expect-error
         e.onpointermove = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
@@ -1291,12 +1456,15 @@ function preLoadCss(cssUrl) {
             }
             setTooltipHoverTimeout(e, true);
         };
+        // @ts-expect-error
         e.onpointerleave = ev => {
             // If this is a synthetic touch event, ignore it. A click event will be along shortly.
             if (ev.pointerType !== "mouse") {
                 return;
             }
+            // @ts-expect-error
             if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT &&
+                // @ts-expect-error
                 !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) {
                 // Tooltip pointer leave gesture:
                 //
@@ -1329,6 +1497,7 @@ function preLoadCss(cssUrl) {
                 // * https://www.nngroup.com/articles/tooltip-guidelines/
                 // * https://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown
                 setTooltipHoverTimeout(e, false);
+                // @ts-expect-error
                 addClass(window.CURRENT_TOOLTIP_ELEMENT, "fade-out");
             }
         };
@@ -1338,6 +1507,7 @@ function preLoadCss(cssUrl) {
     if (sidebar_menu_toggle) {
         sidebar_menu_toggle.addEventListener("click", () => {
             const sidebar = document.getElementsByClassName("sidebar")[0];
+            // @ts-expect-error
             if (!hasClass(sidebar, "shown")) {
                 showSidebar();
             } else {
@@ -1346,12 +1516,18 @@ function preLoadCss(cssUrl) {
         });
     }
 
+    // @ts-expect-error
     function helpBlurHandler(event) {
+        // @ts-expect-error
         if (!getHelpButton().contains(document.activeElement) &&
+            // @ts-expect-error
             !getHelpButton().contains(event.relatedTarget) &&
+            // @ts-expect-error
             !getSettingsButton().contains(document.activeElement) &&
+            // @ts-expect-error
             !getSettingsButton().contains(event.relatedTarget)
         ) {
+            // @ts-expect-error
             window.hidePopoverMenus();
         }
     }
@@ -1427,14 +1603,18 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         if (isHelpPage) {
             const help_section = document.createElement("section");
             help_section.appendChild(container);
+            // @ts-expect-error
             document.getElementById("main-content").appendChild(help_section);
             container.style.display = "block";
         } else {
             const help_button = getHelpButton();
+            // @ts-expect-error
             help_button.appendChild(container);
 
             container.onblur = helpBlurHandler;
+            // @ts-expect-error
             help_button.onblur = helpBlurHandler;
+            // @ts-expect-error
             help_button.children[0].onblur = helpBlurHandler;
         }
 
@@ -1446,8 +1626,10 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      *
      * Pass "true" to reset focus for tooltip popovers.
      */
+    // @ts-expect-error
     window.hideAllModals = switchFocus => {
         hideSidebar();
+        // @ts-expect-error
         window.hidePopoverMenus();
         hideTooltip(switchFocus);
     };
@@ -1455,7 +1637,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     /**
      * Hide all the popover menus.
      */
+    // @ts-expect-error
     window.hidePopoverMenus = () => {
+        // @ts-expect-error
         onEachLazy(document.querySelectorAll("rustdoc-toolbar .popover"), elem => {
             elem.style.display = "none";
         });
@@ -1474,10 +1658,12 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      * @return {HTMLElement}
      */
     function getHelpMenu(buildNeeded) {
+        // @ts-expect-error
         let menu = getHelpButton().querySelector(".popover");
         if (!menu && buildNeeded) {
             menu = buildHelpMenu();
         }
+        // @ts-expect-error
         return menu;
     }
 
@@ -1489,9 +1675,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         // other modals.
         const button = getHelpButton();
         addClass(button, "help-open");
+        // @ts-expect-error
         button.querySelector("a").focus();
         const menu = getHelpMenu(true);
         if (menu.style.display === "none") {
+            // @ts-expect-error
             window.hideAllModals();
             menu.style.display = "";
         }
@@ -1506,8 +1694,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             // If user clicks with a moderator, though, use default browser behavior,
             // probably opening in a new window or tab.
             if (!helpLink.contains(helpLink) ||
+                // @ts-expect-error
                 event.ctrlKey ||
+                // @ts-expect-error
                 event.altKey ||
+                // @ts-expect-error
                 event.metaKey) {
                 return;
             }
@@ -1517,6 +1708,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             if (shouldShowHelp) {
                 showHelp();
             } else {
+                // @ts-expect-error
                 window.hidePopoverMenus();
             }
         });
@@ -1527,6 +1719,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     addSidebarCrates();
     onHashChange(null);
     window.addEventListener("hashchange", onHashChange);
+    // @ts-expect-error
     searchState.setup();
 }());
 
@@ -1580,6 +1773,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             removeClass(document.documentElement, "hide-sidebar");
             updateLocalStorage("hide-sidebar", "false");
             if (document.querySelector(".rustdoc.src")) {
+                // @ts-expect-error
                 window.rustdocToggleSrcSidebar();
             }
             e.preventDefault();
@@ -1589,6 +1783,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // Pointer capture.
     //
     // Resizing is a single-pointer gesture. Any secondary pointer is ignored
+    // @ts-expect-error
     let currentPointerId = null;
 
     // "Desired" sidebar size.
@@ -1596,6 +1791,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // This is stashed here for window resizing. If the sidebar gets
     // shrunk to maintain BODY_MIN, and then the user grows the window again,
     // it gets the sidebar to restore its size.
+    // @ts-expect-error
     let desiredSidebarSize = null;
 
     // Sidebar resize debouncer.
@@ -1626,7 +1822,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // through that size when using the shrink-to-nothing gesture.
     function hideSidebar() {
         if (isSrcPage) {
+            // @ts-expect-error
             window.rustdocCloseSourceSidebar();
+            // @ts-expect-error
             updateLocalStorage("src-sidebar-width", null);
             // [RUSTDOCIMPL] CSS variable fast path
             //
@@ -1639,14 +1837,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             //
             // So, to clear it, we need to clear all three.
             document.documentElement.style.removeProperty("--src-sidebar-width");
+            // @ts-expect-error
             sidebar.style.removeProperty("--src-sidebar-width");
+            // @ts-expect-error
             resizer.style.removeProperty("--src-sidebar-width");
         } else {
             addClass(document.documentElement, "hide-sidebar");
             updateLocalStorage("hide-sidebar", "true");
+            // @ts-expect-error
             updateLocalStorage("desktop-sidebar-width", null);
             document.documentElement.style.removeProperty("--desktop-sidebar-width");
+            // @ts-expect-error
             sidebar.style.removeProperty("--desktop-sidebar-width");
+            // @ts-expect-error
             resizer.style.removeProperty("--desktop-sidebar-width");
         }
     }
@@ -1659,6 +1862,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // remains visible all the time on there.
     function showSidebar() {
         if (isSrcPage) {
+            // @ts-expect-error
             window.rustdocShowSourceSidebar();
         } else {
             removeClass(document.documentElement, "hide-sidebar");
@@ -1674,6 +1878,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
      */
     function changeSidebarSize(size) {
         if (isSrcPage) {
+            // @ts-expect-error
             updateLocalStorage("src-sidebar-width", size);
             // [RUSTDOCIMPL] CSS variable fast path
             //
@@ -1681,11 +1886,16 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             // because the sidebar isn't actually loaded yet,
             // we scope this update to the sidebar to avoid hitting a slow
             // path in WebKit.
+            // @ts-expect-error
             sidebar.style.setProperty("--src-sidebar-width", size + "px");
+            // @ts-expect-error
             resizer.style.setProperty("--src-sidebar-width", size + "px");
         } else {
+            // @ts-expect-error
             updateLocalStorage("desktop-sidebar-width", size);
+            // @ts-expect-error
             sidebar.style.setProperty("--desktop-sidebar-width", size + "px");
+            // @ts-expect-error
             resizer.style.setProperty("--desktop-sidebar-width", size + "px");
         }
     }
@@ -1701,7 +1911,9 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     // Respond to the resize handle event.
     // This function enforces size constraints, and implements the
     // shrink-to-nothing gesture based on thresholds defined above.
+    // @ts-expect-error
     function resize(e) {
+        // @ts-expect-error
         if (currentPointerId === null || currentPointerId !== e.pointerId) {
             return;
         }
@@ -1719,15 +1931,19 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             changeSidebarSize(constrainedPos);
             desiredSidebarSize = constrainedPos;
             if (pendingSidebarResizingFrame !== false) {
+                // @ts-expect-error
                 clearTimeout(pendingSidebarResizingFrame);
             }
+            // @ts-expect-error
             pendingSidebarResizingFrame = setTimeout(() => {
+                // @ts-expect-error
                 if (currentPointerId === null || pendingSidebarResizingFrame === false) {
                     return;
                 }
                 pendingSidebarResizingFrame = false;
                 document.documentElement.style.setProperty(
                     "--resizing-sidebar-width",
+                    // @ts-expect-error
                     desiredSidebarSize + "px",
                 );
             }, 100);
@@ -1739,51 +1955,69 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             return;
         }
         stopResize();
+        // @ts-expect-error
         if (desiredSidebarSize >= (window.innerWidth - BODY_MIN)) {
             changeSidebarSize(window.innerWidth - BODY_MIN);
+        // @ts-expect-error
         } else if (desiredSidebarSize !== null && desiredSidebarSize > SIDEBAR_MIN) {
+            // @ts-expect-error
             changeSidebarSize(desiredSidebarSize);
         }
     });
+    // @ts-expect-error
     function stopResize(e) {
+        // @ts-expect-error
         if (currentPointerId === null) {
             return;
         }
         if (e) {
             e.preventDefault();
         }
+        // @ts-expect-error
         desiredSidebarSize = sidebar.getBoundingClientRect().width;
+        // @ts-expect-error
         removeClass(resizer, "active");
         window.removeEventListener("pointermove", resize, false);
         window.removeEventListener("pointerup", stopResize, false);
         removeClass(document.documentElement, "sidebar-resizing");
         document.documentElement.style.removeProperty( "--resizing-sidebar-width");
+        // @ts-expect-error
         if (resizer.releasePointerCapture) {
+            // @ts-expect-error
             resizer.releasePointerCapture(currentPointerId);
             currentPointerId = null;
         }
     }
+    // @ts-expect-error
     function initResize(e) {
+        // @ts-expect-error
         if (currentPointerId !== null || e.altKey || e.ctrlKey || e.metaKey || e.button !== 0) {
             return;
         }
+        // @ts-expect-error
         if (resizer.setPointerCapture) {
+            // @ts-expect-error
             resizer.setPointerCapture(e.pointerId);
+            // @ts-expect-error
             if (!resizer.hasPointerCapture(e.pointerId)) {
                 // unable to capture pointer; something else has it
                 // on iOS, this usually means you long-clicked a link instead
+                // @ts-expect-error
                 resizer.releasePointerCapture(e.pointerId);
                 return;
             }
             currentPointerId = e.pointerId;
         }
+        // @ts-expect-error
         window.hideAllModals(false);
         e.preventDefault();
         window.addEventListener("pointermove", resize, false);
         window.addEventListener("pointercancel", stopResize, false);
         window.addEventListener("pointerup", stopResize, false);
+        // @ts-expect-error
         addClass(resizer, "active");
         addClass(document.documentElement, "sidebar-resizing");
+        // @ts-expect-error
         const pos = e.clientX - sidebar.offsetLeft - 3;
         document.documentElement.style.setProperty( "--resizing-sidebar-width", pos + "px");
         desiredSidebarSize = null;
@@ -1795,6 +2029,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
 // and the copy buttons on the code examples.
 (function() {
     // Common functions to copy buttons.
+    // @ts-expect-error
     function copyContentToClipboard(content) {
         const el = document.createElement("textarea");
         el.value = content;
@@ -1809,6 +2044,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         document.body.removeChild(el);
     }
 
+    // @ts-expect-error
     function copyButtonAnimation(button) {
         button.classList.add("clicked");
 
@@ -1831,6 +2067,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         // Most page titles are '<Item> in <path::to::module> - Rust', except
         // modules (which don't have the first part) and keywords/primitives
         // (which don't have a module path)
+        // @ts-expect-error
         const title = document.querySelector("title").textContent.replace(" - Rust", "");
         const [item, module] = title.split(" in ");
         const path = [item];
@@ -1843,6 +2080,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
     };
 
     // Copy buttons on code examples.
+    // @ts-expect-error
     function copyCode(codeElem) {
         if (!codeElem) {
             // Should never happen, but the world is a dark and dangerous place.
@@ -1851,6 +2089,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         copyContentToClipboard(codeElem.textContent);
     }
 
+    // @ts-expect-error
     function getExampleWrap(event) {
         let elem = event.target;
         while (!hasClass(elem, "example-wrap")) {
@@ -1866,6 +2105,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         return elem;
     }
 
+    // @ts-expect-error
     function addCopyButton(event) {
         const elem = getExampleWrap(event);
         if (elem === null) {
@@ -1896,9 +2136,11 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
             return;
         }
         const scrapedWrapped = elem.parentElement;
+        // @ts-expect-error
         window.updateScrapedExample(scrapedWrapped, parent);
     }
 
+    // @ts-expect-error
     function showHideCodeExampleButtons(event) {
         const elem = getExampleWrap(event);
         if (elem === null) {
@@ -1917,6 +2159,7 @@ href="https://doc.rust-lang.org/${channel}/rustdoc/read-documentation/search.htm
         buttons.classList.toggle("keep-visible");
     }
 
+    // @ts-expect-error
     onEachLazy(document.querySelectorAll(".docblock .example-wrap"), elem => {
         elem.addEventListener("mouseover", addCopyButton);
         elem.addEventListener("click", showHideCodeExampleButtons);
diff --git a/src/librustdoc/html/static/js/rustdoc.d.ts b/src/librustdoc/html/static/js/rustdoc.d.ts
new file mode 100644
index 00000000000..18a3e22113b
--- /dev/null
+++ b/src/librustdoc/html/static/js/rustdoc.d.ts
@@ -0,0 +1,387 @@
+// This file contains type definitions that are processed by the TypeScript Compiler but are
+// not put into the JavaScript we include as part of the documentation. It is used for
+// type checking. See README.md in this directory for more info.
+
+/* eslint-disable */
+declare global {
+    interface Window {
+        /** Make the current theme easy to find */
+        currentTheme: HTMLLinkElement|null;
+        /** Used by the popover tooltip code. */
+        RUSTDOC_TOOLTIP_HOVER_MS: number;
+        /** Used by the popover tooltip code. */
+        RUSTDOC_TOOLTIP_HOVER_EXIT_MS: number;
+        /** Search engine data used by main.js and search.js */
+        searchState: rustdoc.SearchState;
+        /** Global option, with a long list of "../"'s */
+        rootPath: string|null;
+        /**
+         * Currently opened crate.
+         * As a multi-page application, we know this never changes once set.
+         */
+        currentCrate: string|null;
+    }
+    interface HTMLElement {
+        /** Used by the popover tooltip code. */
+        TOOLTIP_FORCE_VISIBLE: boolean|undefined,
+        /** Used by the popover tooltip code */
+        TOOLTIP_HOVER_TIMEOUT: Timeout|undefined,
+    }
+}
+
+export = rustdoc;
+
+declare namespace rustdoc {
+    interface SearchState {
+        rustdocToolbar: HTMLElement|null;
+        loadingText: string;
+        input: HTMLInputElement|null;
+        title: string;
+        titleBeforeSearch: string;
+        timeout: number|null;
+        currentTab: number;
+        focusedByTab: [number|null, number|null, number|null];
+        clearInputTimeout: function;
+        outputElement: function(): HTMLElement|null;
+        focus: function();
+        defocus: function();
+        showResults: function(HTMLElement|null|undefined);
+        removeQueryParameters: function();
+        hideResults: function();
+        getQueryStringParams: function(): Object.<any, string>;
+        origPlaceholder: string;
+        setup: function();
+        setLoadingSearch: function();
+        descShards: Map<string, SearchDescShard[]>;
+        loadDesc: function({descShard: SearchDescShard, descIndex: number}): Promise<string|null>;
+        loadedDescShard: function(string, number, string);
+        isDisplayed: function(): boolean,
+    }
+
+    interface SearchDescShard {
+        crate: string;
+        promise: Promise<string[]>|null;
+        resolve: function(string[])|null;
+        shard: number;
+    }
+
+    /**
+     * A single parsed "atom" in a search query. For example,
+     * 
+     *     std::fmt::Formatter, Write -> Result<()>
+     *     ┏━━━━━━━━━━━━━━━━━━  ┌────    ┏━━━━━┅┅┅┅┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
+     *     ┃                    │        ┗ QueryElement {        ┊
+     *     ┃                    │              name: Result      ┊
+     *     ┃                    │              generics: [       ┊
+     *     ┃                    │                   QueryElement ┘
+     *     ┃                    │                   name: ()
+     *     ┃                    │              ]
+     *     ┃                    │          }
+     *     ┃                    └ QueryElement {
+     *     ┃                          name: Write
+     *     ┃                      }
+     *     ┗ QueryElement {
+     *           name: Formatter
+     *           pathWithoutLast: std::fmt
+     *       }
+     */
+    interface QueryElement {
+        name: string,
+        id: number|null,
+        fullPath: Array<string>,
+        pathWithoutLast: Array<string>,
+        pathLast: string,
+        normalizedPathLast: string,
+        generics: Array<QueryElement>,
+        bindings: Map<number, Array<QueryElement>>,
+        typeFilter: number|null,
+    }
+
+    /**
+     * Same as QueryElement, but bindings and typeFilter support strings
+     */
+    interface ParserQueryElement {
+        name: string,
+        id: number|null,
+        fullPath: Array<string>,
+        pathWithoutLast: Array<string>,
+        pathLast: string,
+        normalizedPathLast: string,
+        generics: Array<ParserQueryElement>,
+        bindings: Map<string, Array<ParserQueryElement>>,
+        bindingName: {name: string, generics: ParserQueryElement[]}|null,
+        typeFilter: string|null,
+    }
+
+    /**
+     * Intermediate parser state. Discarded when parsing is done.
+     */
+    interface ParserState {
+        pos: number;
+        length: number;
+        totalElems: number;
+        genericsElems: number;
+        typeFilter: (null|string);
+        userQuery: string;
+        isInBinding: (null|{name: string, generics: ParserQueryElement[]});
+    }
+
+    /**
+     * A complete parsed query.
+     */
+    interface ParsedQuery<T> {
+        userQuery: string,
+        elems: Array<T>,
+        returned: Array<T>,
+        foundElems: number,
+        totalElems: number,
+        literalSearch: boolean,
+        hasReturnArrow: boolean,
+        correction: string|null,
+        proposeCorrectionFrom: string|null,
+        proposeCorrectionTo: string|null,
+        typeFingerprint: Uint32Array,
+        error: Array<string> | null,
+    }
+
+    /**
+     * An entry in the search index database.
+     */
+    interface Row {
+        crate: string,
+        descShard: SearchDescShard,
+        id: number,
+        name: string,
+        normalizedName: string,
+        word: string,
+        parent: ({ty: number, name: string, path: string, exactPath: string}|null|undefined),
+        path: string,
+        ty: number,
+        type?: FunctionSearchType
+    }
+
+    /**
+     * The viewmodel for the search engine results page.
+     */
+    interface ResultsTable {
+        in_args: Array<ResultObject>,
+        returned: Array<ResultObject>,
+        others: Array<ResultObject>,
+        query: ParsedQuery,
+    }
+
+    type Results = Map<String, ResultObject>;
+
+    /**
+     * An annotated `Row`, used in the viewmodel.
+     */
+    interface ResultObject {
+        desc: string,
+        displayPath: string,
+        fullPath: string,
+        href: string,
+        id: number,
+        dist: number,
+        path_dist: number,
+        name: string,
+        normalizedName: string,
+        word: string,
+        index: number,
+        parent: (Object|undefined),
+        path: string,
+        ty: number,
+        type?: FunctionSearchType,
+        paramNames?: string[],
+        displayType: Promise<Array<Array<string>>>|null,
+        displayTypeMappedNames: Promise<Array<[string, Array<string>]>>|null,
+        item: Row,
+        dontValidate?: boolean,
+    }
+
+    /**
+     * A pair of [inputs, outputs], or 0 for null. This is stored in the search index.
+     * The JavaScript deserializes this into FunctionSearchType.
+     *
+     * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+     * because `null` is four bytes while `0` is one byte.
+     *
+     * An input or output can be encoded as just a number if there is only one of them, AND
+     * it has no generics. The no generics rule exists to avoid ambiguity: imagine if you had
+     * a function with a single output, and that output had a single generic:
+     *
+     *     fn something() -> Result<usize, usize>
+     *
+     * If output was allowed to be any RawFunctionType, it would look like thi
+     *
+     *     [[], [50, [3, 3]]]
+     *
+     * The problem is that the above output could be interpreted as either a type with ID 50 and two
+     * generics, or it could be interpreted as a pair of types, the first one with ID 50 and the second
+     * with ID 3 and a single generic parameter that is also ID 3. We avoid this ambiguity by choosing
+     * in favor of the pair of types interpretation. This is why the `(number|Array<RawFunctionType>)`
+     * is used instead of `(RawFunctionType|Array<RawFunctionType>)`.
+     *
+     * The output can be skipped if it's actually unit and there's no type constraints. If thi
+     * function accepts constrained generics, then the output will be unconditionally emitted, and
+     * after it will come a list of trait constraints. The position of the item in the list will
+     * determine which type parameter it is. For example:
+     *
+     *     [1, 2, 3, 4, 5]
+     *      ^  ^  ^  ^  ^
+     *      |  |  |  |  - generic parameter (-3) of trait 5
+     *      |  |  |  - generic parameter (-2) of trait 4
+     *      |  |  - generic parameter (-1) of trait 3
+     *      |  - this function returns a single value (type 2)
+     *      - this function takes a single input parameter (type 1)
+     *
+     * Or, for a less contrived version:
+     *
+     *     [[[4, -1], 3], [[5, -1]], 11]
+     *      -^^^^^^^----   ^^^^^^^   ^^
+     *       |        |    |          - generic parameter, roughly `where -1: 11`
+     *       |        |    |            since -1 is the type parameter and 11 the trait
+     *       |        |    - function output 5<-1>
+     *       |        - the overall function signature is something like
+     *       |          `fn(4<-1>, 3) -> 5<-1> where -1: 11`
+     *       - function input, corresponds roughly to 4<-1>
+     *         4 is an index into the `p` array for a type
+     *         -1 is the generic parameter, given by 11
+     *
+     * If a generic parameter has multiple trait constraints, it gets wrapped in an array, just like
+     * function inputs and outputs:
+     *
+     *     [-1, -1, [4, 3]]
+     *              ^^^^^^ where -1: 4 + 3
+     *
+     * If a generic parameter's trait constraint has generic parameters, it gets wrapped in the array
+     * even if only one exists. In other words, the ambiguity of `4<3>` and `4 + 3` is resolved in
+     * favor of `4 + 3`:
+     *
+     *     [-1, -1, [[4, 3]]]
+     *              ^^^^^^^^ where -1: 4 + 3
+     *
+     *     [-1, -1, [5, [4, 3]]]
+     *              ^^^^^^^^^^^ where -1: 5, -2: 4 + 3
+     *
+     * If a generic parameter has no trait constraints (like in Rust, the `Sized` constraint i
+     * implied and a fake `?Sized` constraint used to note its absence), it will be filled in with 0.
+     */
+    type RawFunctionSearchType =
+        0 |
+        [(number|Array<RawFunctionType>)] |
+        [(number|Array<RawFunctionType>), (number|Array<RawFunctionType>)] |
+        Array<(number|Array<RawFunctionType>)>
+    ;
+
+    /**
+     * A single function input or output type. This is either a single path ID, or a pair of
+     * [path ID, generics].
+     *
+     * Numeric IDs are *ONE-indexed* into the paths array (`p`). Zero is used as a sentinel for `null`
+     * because `null` is four bytes while `0` is one byte.
+     */
+    type RawFunctionType = number | [number, Array<RawFunctionType>];
+
+    /**
+     * The type signature entry in the decoded search index.
+     * (The "Raw" objects are encoded differently to save space in the JSON).
+     */
+    interface FunctionSearchType {
+        inputs: Array<FunctionType>,
+        output: Array<FunctionType>,
+        where_clause: Array<Array<FunctionType>>,
+    }
+
+    /**
+     * A decoded function type, made from real objects.
+     * `ty` will be negative for generics, positive for types, and 0 for placeholders.
+     */
+    interface FunctionType {
+        id: null|number,
+        ty: number|null,
+        name?: string,
+        path: string|null,
+        exactPath: string|null,
+        unboxFlag: boolean,
+        generics: Array<FunctionType>,
+        bindings: Map<number, Array<FunctionType>>,
+    };
+
+    interface HighlightedFunctionType extends FunctionType {
+        generics: HighlightedFunctionType[],
+        bindings: Map<number, HighlightedFunctionType[]>,
+        highlighted?: boolean;
+    }
+
+    interface FingerprintableType {
+        id: number|null;
+        generics: FingerprintableType[];
+        bindings: Map<number, FingerprintableType[]>;
+    };
+
+    /**
+     * The raw search data for a given crate. `n`, `t`, `d`, `i`, and `f`
+     * are arrays with the same length. `q`, `a`, and `c` use a sparse
+     * representation for compactness.
+     *
+     * `n[i]` contains the name of an item.
+     *
+     * `t[i]` contains the type of that item
+     * (as a string of characters that represent an offset in `itemTypes`).
+     *
+     * `d[i]` contains the description of that item.
+     *
+     * `q` contains the full paths of the items. For compactness, it is a set of
+     * (index, path) pairs used to create a map. If a given index `i` is
+     * not present, this indicates "same as the last index present".
+     *
+     * `i[i]` contains an item's parent, usually a module. For compactness,
+     * it is a set of indexes into the `p` array.
+     *
+     * `f` contains function signatures, or `0` if the item isn't a function.
+     * More information on how they're encoded can be found in rustc-dev-guide
+     *
+     * Functions are themselves encoded as arrays. The first item is a list of
+     * types representing the function's inputs, and the second list item is a list
+     * of types representing the function's output. Tuples are flattened.
+     * Types are also represented as arrays; the first item is an index into the `p`
+     * array, while the second is a list of types representing any generic parameters.
+     *
+     * b[i] contains an item's impl disambiguator. This is only present if an item
+     * is defined in an impl block and, the impl block's type has more than one associated
+     * item with the same name.
+     *
+     * `a` defines aliases with an Array of pairs: [name, offset], where `offset`
+     * points into the n/t/d/q/i/f arrays.
+     *
+     * `doc` contains the description of the crate.
+     *
+     * `p` is a list of path/type pairs. It is used for parents and function parameters.
+     * The first item is the type, the second is the name, the third is the visible path (if any) and
+     * the fourth is the canonical path used for deduplication (if any).
+     *
+     * `r` is the canonical path used for deduplication of re-exported items.
+     * It is not used for associated items like methods (that's the fourth element
+     * of `p`) but is used for modules items like free functions.
+     *
+     * `c` is an array of item indices that are deprecated.
+     */
+    type RawSearchIndexCrate = {
+    doc: string,
+    a: Object,
+    n: Array<string>,
+    t: string,
+    D: string,
+    e: string,
+    q: Array<[number, string]>,
+    i: string,
+    f: string,
+    p: Array<[number, string] | [number, string, number] | [number, string, number, number] | [number, string, number, number, string]>,
+    b: Array<[number, String]>,
+    c: string,
+    r: Array<[number, number]>,
+    P: Array<[number, string]>,
+    };
+
+    type VlqData = VlqData[] | number;
+}
diff --git a/src/librustdoc/html/static/js/scrape-examples.js b/src/librustdoc/html/static/js/scrape-examples.js
index 98c53b8656f..d08f15a5bfa 100644
--- a/src/librustdoc/html/static/js/scrape-examples.js
+++ b/src/librustdoc/html/static/js/scrape-examples.js
@@ -1,5 +1,8 @@
 /* global addClass, hasClass, removeClass, onEachLazy */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js
index 660484c133c..1ad32721e06 100644
--- a/src/librustdoc/html/static/js/search.js
+++ b/src/librustdoc/html/static/js/search.js
@@ -10,11 +10,19 @@ if (!Array.prototype.toSpliced) {
     // Can't use arrow functions, because we want `this`
     Array.prototype.toSpliced = function() {
         const me = this.slice();
+        // @ts-expect-error
         Array.prototype.splice.apply(me, arguments);
         return me;
     };
 }
 
+/**
+ *
+ * @template T
+ * @param {Iterable<T>} arr
+ * @param {function(T): any} func
+ * @param {function(T): boolean} funcBtwn
+ */
 function onEachBtwn(arr, func, funcBtwn) {
     let skipped = true;
     for (const value of arr) {
@@ -98,9 +106,24 @@ const NO_TYPE_FILTER = -1;
  * documentation.
  */
 const editDistanceState = {
+    /**
+     * @type {number[]}
+     */
     current: [],
+    /**
+     * @type {number[]}
+     */
     prev: [],
+    /**
+     * @type {number[]}
+     */
     prevPrev: [],
+    /**
+     * @param {string} a
+     * @param {string} b
+     * @param {number} limit
+     * @returns
+     */
     calculate: function calculate(a, b, limit) {
         // Ensure that `b` is the shorter string, minimizing memory use.
         if (a.length < b.length) {
@@ -186,14 +209,28 @@ const editDistanceState = {
     },
 };
 
+/**
+ * @param {string} a
+ * @param {string} b
+ * @param {number} limit
+ * @returns
+ */
 function editDistance(a, b, limit) {
     return editDistanceState.calculate(a, b, limit);
 }
 
+/**
+ * @param {string} c
+ * @returns {boolean}
+ */
 function isEndCharacter(c) {
     return "=,>-])".indexOf(c) !== -1;
 }
 
+/**
+ * @param {number} ty
+ * @returns
+ */
 function isFnLikeTy(ty) {
     return ty === TY_FN || ty === TY_METHOD || ty === TY_TYMETHOD;
 }
@@ -212,7 +249,7 @@ function isSeparatorCharacter(c) {
 /**
  * Returns `true` if the current parser position is starting with "->".
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -223,7 +260,7 @@ function isReturnArrow(parserState) {
 /**
  * Increase current parser position until it doesn't find a whitespace anymore.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  */
 function skipWhitespace(parserState) {
     while (parserState.pos < parserState.userQuery.length) {
@@ -238,7 +275,7 @@ function skipWhitespace(parserState) {
 /**
  * Returns `true` if the previous character is `lookingFor`.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  * @param {String} lookingFor
  *
  * @return {boolean}
@@ -260,8 +297,8 @@ function prevIs(parserState, lookingFor) {
 /**
  * Returns `true` if the last element in the `elems` argument has generics.
  *
- * @param {Array<QueryElement>} elems
- * @param {ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -270,6 +307,13 @@ function isLastElemGeneric(elems, parserState) {
         prevIs(parserState, ">");
 }
 
+/**
+ *
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {rustdoc.ParserQueryElement[]} elems
+ * @param {boolean} isInGenerics
+ */
 function getFilteredNextElem(query, parserState, elems, isInGenerics) {
     const start = parserState.pos;
     if (parserState.userQuery[parserState.pos] === ":" && !isPathStart(parserState)) {
@@ -294,6 +338,8 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) {
         // The type filter doesn't count as an element since it's a modifier.
         const typeFilterElem = elems.pop();
         checkExtraTypeFilterCharacters(start, parserState);
+        // typeFilterElem is not null. If it was, the elems.length check would have fired.
+        // @ts-expect-error
         parserState.typeFilter = typeFilterElem.normalizedPathLast;
         parserState.pos += 1;
         parserState.totalElems -= 1;
@@ -309,12 +355,13 @@ function getFilteredNextElem(query, parserState, elems, isInGenerics) {
  * If there is no `endChar`, this function will implicitly stop at the end
  * without raising an error.
  *
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
- * @param {string} endChar            - This function will stop when it'll encounter this
- *                                      character.
- * @returns {{foundSeparator: bool}}
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ *     - This is where the new {QueryElement} will be added.
+ * @param {string} endChar - This function will stop when it'll encounter this
+ *                           character.
+ * @returns {{foundSeparator: boolean}}
  */
 function getItemsBefore(query, parserState, elems, endChar) {
     let foundStopChar = true;
@@ -385,6 +432,7 @@ function getItemsBefore(query, parserState, elems, endChar) {
             throw ["Unexpected ", c, " after ", extra];
         }
         if (!foundStopChar) {
+            /** @type {string[]} */
             let extra = [];
             if (isLastElemGeneric(query.elems, parserState)) {
                 extra = [" after ", ">"];
@@ -463,12 +511,14 @@ function getItemsBefore(query, parserState, elems, endChar) {
 }
 
 /**
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {Array<QueryElement>} elems - This is where the new {QueryElement} will be added.
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {Array<rustdoc.ParserQueryElement>} elems
+ *     - This is where the new {QueryElement} will be added.
  * @param {boolean} isInGenerics
  */
 function getNextElem(query, parserState, elems, isInGenerics) {
+    /** @type {rustdoc.ParserQueryElement[]} */
     const generics = [];
 
     skipWhitespace(parserState);
@@ -588,6 +638,7 @@ function getNextElem(query, parserState, elems, isInGenerics) {
                 getFilteredNextElem(query, parserState, generics, isInGenerics);
                 generics[generics.length - 1].bindingName = makePrimitiveElement("output");
             } else {
+                // @ts-expect-error
                 generics.push(makePrimitiveElement(null, {
                     bindingName: makePrimitiveElement("output"),
                     typeFilter: null,
@@ -640,7 +691,8 @@ function getNextElem(query, parserState, elems, isInGenerics) {
  * Checks that the type filter doesn't have unwanted characters like `<>` (which are ignored
  * if empty).
  *
- * @param {ParserState} parserState
+ * @param {number} start
+ * @param {rustdoc.ParserState} parserState
  */
 function checkExtraTypeFilterCharacters(start, parserState) {
     const query = parserState.userQuery.slice(start, parserState.pos).trim();
@@ -658,12 +710,13 @@ function checkExtraTypeFilterCharacters(start, parserState) {
 }
 
 /**
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
- * @param {string} name                  - Name of the query element.
- * @param {Array<QueryElement>} generics - List of generics of this query element.
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
+ * @param {string} name - Name of the query element.
+ * @param {Array<rustdoc.ParserQueryElement>} generics - List of generics of this query element.
+ * @param {boolean} isInGenerics
  *
- * @return {QueryElement}                - The newly created `QueryElement`.
+ * @return {rustdoc.ParserQueryElement} - The newly created `QueryElement`.
  */
 function createQueryElement(query, parserState, name, generics, isInGenerics) {
     const path = name.trim();
@@ -756,9 +809,15 @@ function createQueryElement(query, parserState, name, generics, isInGenerics) {
     };
 }
 
+/**
+ *
+ * @param {string} name
+ * @param {Object=} extra
+ * @returns {rustdoc.ParserQueryElement}
+ */
 function makePrimitiveElement(name, extra) {
     return Object.assign({
-        name,
+        name: name,
         id: null,
         fullPath: [name],
         pathWithoutLast: [],
@@ -781,8 +840,8 @@ function makePrimitiveElement(name, extra) {
  * * There is more than one element.
  * * There is no closing `"`.
  *
- * @param {ParsedQuery} query
- * @param {ParserState} parserState
+ * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+ * @param {rustdoc.ParserState} parserState
  * @param {boolean} isInGenerics
  */
 function getStringElem(query, parserState, isInGenerics) {
@@ -813,9 +872,9 @@ function getStringElem(query, parserState, isInGenerics) {
  * character or the end of the query. It returns the position of the last
  * character of the ident.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
- * @return {integer}
+ * @return {number}
  */
 function getIdentEndPosition(parserState) {
     let afterIdent = consumeIdent(parserState);
@@ -890,6 +949,10 @@ function getIdentEndPosition(parserState) {
     return end;
 }
 
+/**
+ * @param {string} c
+ * @returns
+ */
 function isSpecialStartCharacter(c) {
     return "<\"".indexOf(c) !== -1;
 }
@@ -897,7 +960,7 @@ function isSpecialStartCharacter(c) {
 /**
  * Returns `true` if the current parser position is starting with "::".
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -909,7 +972,7 @@ function isPathStart(parserState) {
  * If the current parser position is at the beginning of an identifier,
  * move the position to the end of it and return `true`. Otherwise, return `false`.
  *
- * @param {ParserState} parserState
+ * @param {rustdoc.ParserState} parserState
  *
  * @return {boolean}
  */
@@ -935,14 +998,25 @@ function isPathSeparator(c) {
     return c === ":" || c === " ";
 }
 
+/**
+ * @template T
+ */
 class VlqHexDecoder {
+    /**
+     * @param {string} string
+     * @param {function(rustdoc.VlqData): T} cons
+     */
     constructor(string, cons) {
         this.string = string;
         this.cons = cons;
         this.offset = 0;
+        /** @type {T[]} */
         this.backrefQueue = [];
     }
-    // call after consuming `{`
+    /**
+     * call after consuming `{`
+     * @returns {rustdoc.VlqData[]}
+     */
     decodeList() {
         let c = this.string.charCodeAt(this.offset);
         const ret = [];
@@ -953,7 +1027,10 @@ class VlqHexDecoder {
         this.offset += 1; // eat cb
         return ret;
     }
-    // consumes and returns a list or integer
+    /**
+     * consumes and returns a list or integer
+     * @returns {rustdoc.VlqData}
+     */
     decode() {
         let n = 0;
         let c = this.string.charCodeAt(this.offset);
@@ -972,6 +1049,9 @@ class VlqHexDecoder {
         this.offset += 1;
         return sign ? -value : value;
     }
+    /**
+     * @returns {T}
+     */
     next() {
         const c = this.string.charCodeAt(this.offset);
         // sixteen characters after "0" are backref
@@ -994,6 +1074,7 @@ class VlqHexDecoder {
     }
 }
 class RoaringBitmap {
+    /** @param {string} str */
     constructor(str) {
         // https://github.com/RoaringBitmap/RoaringFormatSpec
         //
@@ -1063,6 +1144,7 @@ class RoaringBitmap {
             }
         }
     }
+    /** @param {number} keyvalue */
     contains(keyvalue) {
         const key = keyvalue >> 16;
         const value = keyvalue & 0xFFFF;
@@ -1091,10 +1173,15 @@ class RoaringBitmap {
 }
 
 class RoaringBitmapRun {
+    /**
+     * @param {number} runcount
+     * @param {Uint8Array} array
+     */
     constructor(runcount, array) {
         this.runcount = runcount;
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         // Binary search algorithm copied from
         // https://en.wikipedia.org/wiki/Binary_search#Procedure
@@ -1120,10 +1207,15 @@ class RoaringBitmapRun {
     }
 }
 class RoaringBitmapArray {
+    /**
+     * @param {number} cardinality
+     * @param {Uint8Array} array
+     */
     constructor(cardinality, array) {
         this.cardinality = cardinality;
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         // Binary search algorithm copied from
         // https://en.wikipedia.org/wiki/Binary_search#Procedure
@@ -1148,9 +1240,13 @@ class RoaringBitmapArray {
     }
 }
 class RoaringBitmapBits {
+    /**
+     * @param {Uint8Array} array
+     */
     constructor(array) {
         this.array = array;
     }
+    /** @param {number} value */
     contains(value) {
         return !!(this.array[value >> 3] & (1 << (value & 7)));
     }
@@ -1176,9 +1272,9 @@ class RoaringBitmapBits {
  * matches
  * : A list of search index IDs for this node.
  *
- * @typedef {{
- *     children: [NameTrie],
- *     matches: [number],
+ * @type {{
+ *     children: NameTrie[],
+ *     matches: number[],
  * }}
  */
 class NameTrie {
@@ -1186,9 +1282,20 @@ class NameTrie {
         this.children = [];
         this.matches = [];
     }
+    /**
+     * @param {string} name
+     * @param {number} id
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     insert(name, id, tailTable) {
         this.insertSubstring(name, 0, id, tailTable);
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {number} id
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     insertSubstring(name, substart, id, tailTable) {
         const l = name.length;
         if (substart === l) {
@@ -1201,10 +1308,13 @@ class NameTrie {
             } else {
                 child = new NameTrie();
                 this.children[sb] = child;
+                /** @type {NameTrie[]} */
                 let sste;
                 if (substart >= 2) {
                     const tail = name.substring(substart - 2, substart + 1);
                     if (tailTable.has(tail)) {
+                        // it's not undefined
+                        // @ts-expect-error
                         sste = tailTable.get(tail);
                     } else {
                         sste = [];
@@ -1216,6 +1326,10 @@ class NameTrie {
             child.insertSubstring(name, substart + 1, id, tailTable);
         }
     }
+    /**
+     * @param {string} name
+     * @param {Map<string, NameTrie[]>} tailTable
+     */
     search(name, tailTable) {
         const results = new Set();
         this.searchSubstringPrefix(name, 0, results);
@@ -1226,6 +1340,8 @@ class NameTrie {
             this.searchLev(name, 0, levParams, results);
             const tail = name.substring(0, 3);
             if (tailTable.has(tail)) {
+                // it's not undefined
+                // @ts-expect-error
                 for (const entry of tailTable.get(tail)) {
                     entry.searchSubstringPrefix(name, 3, results);
                 }
@@ -1233,6 +1349,11 @@ class NameTrie {
         }
         return [...results];
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {Set<number>} results
+     */
     searchSubstringPrefix(name, substart, results) {
         const l = name.length;
         if (substart === l) {
@@ -1240,14 +1361,18 @@ class NameTrie {
                 results.add(match);
             }
             // breadth-first traversal orders prefix matches by length
+            /** @type {NameTrie[]} */
             let unprocessedChildren = [];
             for (const child of this.children) {
                 if (child) {
                     unprocessedChildren.push(child);
                 }
             }
+            /** @type {NameTrie[]} */
             let nextSet = [];
             while (unprocessedChildren.length !== 0) {
+                /** @type {NameTrie} */
+                // @ts-expect-error
                 const next = unprocessedChildren.pop();
                 for (const child of next.children) {
                     if (child) {
@@ -1270,10 +1395,18 @@ class NameTrie {
             }
         }
     }
+    /**
+     * @param {string} name
+     * @param {number} substart
+     * @param {Lev2TParametricDescription|Lev1TParametricDescription} levParams
+     * @param {Set<number>} results
+     */
     searchLev(name, substart, levParams, results) {
         const stack = [[this, 0]];
         const n = levParams.n;
         while (stack.length !== 0) {
+            // It's not empty
+            //@ts-expect-error
             const [trie, levState] = stack.pop();
             for (const [charCode, child] of trie.children.entries()) {
                 if (!child) {
@@ -1305,6 +1438,11 @@ class NameTrie {
 }
 
 class DocSearch {
+    /**
+     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
+     * @param {string} rootPath
+     * @param {rustdoc.SearchState} searchState
+     */
     constructor(rawSearchIndex, rootPath, searchState) {
         /**
          * @type {Map<String, RoaringBitmap>}
@@ -1317,19 +1455,19 @@ class DocSearch {
         /**
          *  @type {Uint32Array}
          */
-        this.functionTypeFingerprint = null;
+        this.functionTypeFingerprint = new Uint32Array(0);
         /**
          * Map from normalized type names to integers. Used to make type search
          * more efficient.
          *
-         * @type {Map<string, {id: integer, assocOnly: boolean}>}
+         * @type {Map<string, {id: number, assocOnly: boolean}>}
          */
         this.typeNameIdMap = new Map();
         /**
          * Map from type ID to associated type name. Used for display,
          * not for search.
          *
-         * @type {Map<integer, string>}
+         * @type {Map<number, string>}
          */
         this.assocTypeIdNameMap = new Map();
         this.ALIASES = new Map();
@@ -1338,64 +1476,88 @@ class DocSearch {
 
         /**
          * Special type name IDs for searching by array.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfArray = this.buildTypeMapIndex("array");
         /**
          * Special type name IDs for searching by slice.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfSlice = this.buildTypeMapIndex("slice");
         /**
          * Special type name IDs for searching by both array and slice (`[]` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfArrayOrSlice = this.buildTypeMapIndex("[]");
         /**
          * Special type name IDs for searching by tuple.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfTuple = this.buildTypeMapIndex("tuple");
         /**
          * Special type name IDs for searching by unit.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfUnit = this.buildTypeMapIndex("unit");
         /**
          * Special type name IDs for searching by both tuple and unit (`()` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfTupleOrUnit = this.buildTypeMapIndex("()");
         /**
          * Special type name IDs for searching `fn`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFn = this.buildTypeMapIndex("fn");
         /**
          * Special type name IDs for searching `fnmut`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFnMut = this.buildTypeMapIndex("fnmut");
         /**
          * Special type name IDs for searching `fnonce`.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfFnOnce = this.buildTypeMapIndex("fnonce");
         /**
          * Special type name IDs for searching higher order functions (`->` syntax).
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfHof = this.buildTypeMapIndex("->");
         /**
          * Special type name IDs the output assoc type.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfOutput = this.buildTypeMapIndex("output", true);
         /**
          * Special type name IDs for searching by reference.
+         * @type {number}
          */
+        // @ts-expect-error
         this.typeNameIdOfReference = this.buildTypeMapIndex("reference");
 
         /**
          * Empty, immutable map used in item search types with no bindings.
          *
-         * @type {Map<number, Array<FunctionType>>}
+         * @type {Map<number, Array<any>>}
          */
         this.EMPTY_BINDINGS_MAP = new Map();
 
         /**
          * Empty, immutable map used in item search types with no bindings.
          *
-         * @type {Array<FunctionType>}
+         * @type {Array<any>}
          */
         this.EMPTY_GENERICS_ARRAY = [];
 
@@ -1403,7 +1565,7 @@ class DocSearch {
          * Object pool for function types with no bindings or generics.
          * This is reset after loading the index.
          *
-         * @type {Map<number|null, FunctionType>}
+         * @type {Map<number|null, rustdoc.FunctionType>}
          */
         this.TYPES_POOL = new Map();
 
@@ -1422,8 +1584,9 @@ class DocSearch {
         this.tailTable = new Map();
 
         /**
-         *  @type {Array<Row>}
+         *  @type {Array<rustdoc.Row>}
          */
+        // @ts-expect-error
         this.searchIndex = this.buildIndex(rawSearchIndex);
     }
 
@@ -1436,9 +1599,9 @@ class DocSearch {
      * get the same ID.
      *
      * @param {string} name
-     * @param {boolean} isAssocType - True if this is an assoc type
+     * @param {boolean=} isAssocType - True if this is an assoc type
      *
-     * @returns {integer}
+     * @returns {number?}
      */
     buildTypeMapIndex(name, isAssocType) {
         if (name === "" || name === null) {
@@ -1446,12 +1609,14 @@ class DocSearch {
         }
 
         if (this.typeNameIdMap.has(name)) {
+            /** @type {{id: number, assocOnly: boolean}} */
+            // @ts-expect-error
             const obj = this.typeNameIdMap.get(name);
-            obj.assocOnly = isAssocType && obj.assocOnly;
+            obj.assocOnly = !!(isAssocType && obj.assocOnly);
             return obj.id;
         } else {
             const id = this.typeNameIdMap.size;
-            this.typeNameIdMap.set(name, { id, assocOnly: isAssocType });
+            this.typeNameIdMap.set(name, { id, assocOnly: !!isAssocType });
             return id;
         }
     }
@@ -1469,13 +1634,26 @@ class DocSearch {
      * The format for individual function types is encoded in
      * librustdoc/html/render/mod.rs: impl Serialize for RenderType
      *
-     * @param {null|Array<RawFunctionType>} types
-     * @param {Array<{name: string, ty: number}>} lowercasePaths
+     * @param {null|Array<rustdoc.RawFunctionType>} types
+     * @param {Array<{
+     *     name: string,
+    *     ty: number,
+    *     path: string|null,
+    *     exactPath: string|null,
+    *     unboxFlag: boolean
+    * }>} paths
+    * @param {Array<{
+    *     name: string,
+    *     ty: number,
+    *     path: string|null,
+    *     exactPath: string|null,
+    *     unboxFlag: boolean,
+    * }>} lowercasePaths
      *
-     * @return {Array<FunctionSearchType>}
+     * @return {Array<rustdoc.FunctionType>}
      */
     buildItemSearchTypeAll(types, paths, lowercasePaths) {
-        return types.length > 0 ?
+        return types && types.length > 0 ?
             types.map(type => this.buildItemSearchType(type, paths, lowercasePaths)) :
             this.EMPTY_GENERICS_ARRAY;
     }
@@ -1483,7 +1661,22 @@ class DocSearch {
     /**
      * Converts a single type.
      *
-     * @param {RawFunctionType} type
+     * @param {rustdoc.RawFunctionType} type
+     * @param {Array<{
+     *     name: string,
+     *     ty: number,
+     *     path: string|null,
+     *     exactPath: string|null,
+     *     unboxFlag: boolean
+     * }>} paths
+     * @param {Array<{
+     *     name: string,
+     *     ty: number,
+     *     path: string|null,
+     *     exactPath: string|null,
+     *     unboxFlag: boolean,
+     * }>} lowercasePaths
+     * @param {boolean=} isAssocType
      */
     buildItemSearchType(type, paths, lowercasePaths, isAssocType) {
         const PATH_INDEX_DATA = 0;
@@ -1501,7 +1694,9 @@ class DocSearch {
                 paths,
                 lowercasePaths,
             );
+            // @ts-expect-error
             if (type.length > BINDINGS_DATA && type[BINDINGS_DATA].length > 0) {
+                // @ts-expect-error
                 bindings = new Map(type[BINDINGS_DATA].map(binding => {
                     const [assocType, constraints] = binding;
                     // Associated type constructors are represented sloppily in rustdoc's
@@ -1524,7 +1719,7 @@ class DocSearch {
             }
         }
         /**
-         * @type {FunctionType}
+         * @type {rustdoc.FunctionType}
          */
         let result;
         if (pathIndex < 0) {
@@ -1555,7 +1750,7 @@ class DocSearch {
         } else {
             const item = lowercasePaths[pathIndex - 1];
             const id = this.buildTypeMapIndex(item.name, isAssocType);
-            if (isAssocType) {
+            if (isAssocType && id !== null) {
                 this.assocTypeIdNameMap.set(id, paths[pathIndex - 1].name);
             }
             result = {
@@ -1585,6 +1780,7 @@ class DocSearch {
             if (cr.bindings.size === result.bindings.size && cr.bindings !== result.bindings) {
                 let ok = true;
                 for (const [k, v] of cr.bindings.entries()) {
+                    // @ts-expect-error
                     const v2 = result.bindings.get(v);
                     if (!v2) {
                         ok = false;
@@ -1629,7 +1825,7 @@ class DocSearch {
      * [^1]: Distance is the relatively naive metric of counting the number of distinct items in
      * the function that are not present in the query.
      *
-     * @param {FunctionType|QueryElement} type - a single type
+     * @param {rustdoc.FingerprintableType} type - a single type
      * @param {Uint32Array} output - write the fingerprint to this data structure: uses 128 bits
      */
     buildFunctionTypeFingerprint(type, output) {
@@ -1647,9 +1843,12 @@ class DocSearch {
             input === this.typeNameIdOfFnOnce) {
             input = this.typeNameIdOfHof;
         }
-        // http://burtleburtle.net/bob/hash/integer.html
-        // ~~ is toInt32. It's used before adding, so
-        // the number stays in safe integer range.
+        /**
+         * http://burtleburtle.net/bob/hash/integer.html
+         * ~~ is toInt32. It's used before adding, so
+         * the number stays in safe integer range.
+         * @param {number} k
+         */
         const hashint1 = k => {
             k = (~~k + 0x7ed55d16) + (k << 12);
             k = (k ^ 0xc761c23c) ^ (k >>> 19);
@@ -1658,6 +1857,7 @@ class DocSearch {
             k = (~~k + 0xfd7046c5) + (k << 3);
             return (k ^ 0xb55a4f09) ^ (k >>> 16);
         };
+        /** @param {number} k */
         const hashint2 = k => {
             k = ~k + (k << 15);
             k ^= k >>> 12;
@@ -1684,6 +1884,14 @@ class DocSearch {
         for (const g of type.generics) {
             this.buildFunctionTypeFingerprint(g, output);
         }
+        /**
+         * @type {{
+         *   id: number|null,
+         *   ty: number,
+         *   generics: rustdoc.FingerprintableType[],
+         *   bindings: Map<number, rustdoc.FingerprintableType[]>
+         * }}
+         */
         const fb = {
             id: null,
             ty: 0,
@@ -1700,7 +1908,7 @@ class DocSearch {
     /**
      * Convert raw search index into in-memory search index.
      *
-     * @param {[string, RawSearchIndexCrate][]} rawSearchIndex
+     * @param {Map<string, rustdoc.RawSearchIndexCrate>} rawSearchIndex
      */
     buildIndex(rawSearchIndex) {
         /**
@@ -1714,19 +1922,37 @@ class DocSearch {
          * The raw function search type format is generated using serde in
          * librustdoc/html/render/mod.rs: IndexItemFunctionType::write_to_string
          *
-         * @param {Array<{name: string, ty: number}>} paths
-         * @param {Array<{name: string, ty: number}>} lowercasePaths
+         * @param {Array<{
+         *     name: string,
+         *     ty: number,
+         *     path: string|null,
+         *     exactPath: string|null,
+         *     unboxFlag: boolean
+         * }>} paths
+         * @param {Array<{
+         *     name: string,
+         *     ty: number,
+         *     path: string|null,
+         *     exactPath: string|null,
+         *     unboxFlag: boolean
+         * }>} lowercasePaths
          *
-         * @return {null|FunctionSearchType}
+         * @return {function(rustdoc.RawFunctionSearchType): null|rustdoc.FunctionSearchType}
          */
         const buildFunctionSearchTypeCallback = (paths, lowercasePaths) => {
-            return functionSearchType => {
+            /**
+             * @param {rustdoc.RawFunctionSearchType} functionSearchType
+             */
+            const cb = functionSearchType => {
                 if (functionSearchType === 0) {
                     return null;
                 }
                 const INPUTS_DATA = 0;
                 const OUTPUT_DATA = 1;
-                let inputs, output;
+                /** @type {rustdoc.FunctionType[]} */
+                let inputs;
+                /** @type {rustdoc.FunctionType[]} */
+                let output;
                 if (typeof functionSearchType[INPUTS_DATA] === "number") {
                     inputs = [
                         this.buildItemSearchType(
@@ -1753,6 +1979,7 @@ class DocSearch {
                         ];
                     } else {
                         output = this.buildItemSearchTypeAll(
+                            // @ts-expect-error
                             functionSearchType[OUTPUT_DATA],
                             paths,
                             lowercasePaths,
@@ -1765,8 +1992,10 @@ class DocSearch {
                 const l = functionSearchType.length;
                 for (let i = 2; i < l; ++i) {
                     where_clause.push(typeof functionSearchType[i] === "number"
+                        // @ts-expect-error
                         ? [this.buildItemSearchType(functionSearchType[i], paths, lowercasePaths)]
                         : this.buildItemSearchTypeAll(
+                            // @ts-expect-error
                             functionSearchType[i],
                             paths,
                             lowercasePaths,
@@ -1776,6 +2005,7 @@ class DocSearch {
                     inputs, output, where_clause,
                 };
             };
+            return cb;
         };
 
         const searchIndex = [];
@@ -1798,7 +2028,12 @@ class DocSearch {
         for (const [crate, crateCorpus] of rawSearchIndex) {
             // a string representing the lengths of each description shard
             // a string representing the list of function types
-            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => noop);
+            const itemDescShardDecoder = new VlqHexDecoder(crateCorpus.D, noop => {
+                /** @type {number} */
+                // @ts-expect-error
+                const n = noop;
+                return n;
+            });
             let descShard = {
                 crate,
                 shard: 0,
@@ -1817,7 +2052,7 @@ class DocSearch {
             /**
              * List of generic function type parameter names.
              * Used for display, not for searching.
-             * @type {[string]}
+             * @type {string[]}
              */
             let lastParamNames = [];
 
@@ -1847,6 +2082,8 @@ class DocSearch {
             id += 1;
             searchIndex.push(crateRow);
             currentIndex += 1;
+            // it's not undefined
+            // @ts-expect-error
             if (!this.searchIndexEmptyDesc.get(crate).contains(0)) {
                 descIndex += 1;
             }
@@ -1870,7 +2107,7 @@ class DocSearch {
             const implDisambiguator = new Map(crateCorpus.b);
             // an array of [(Number) item type,
             //              (String) name]
-            const paths = crateCorpus.p;
+            const rawPaths = crateCorpus.p;
             // an array of [(String) alias name
             //             [Number] index to items]
             const aliases = crateCorpus.a;
@@ -1879,33 +2116,61 @@ class DocSearch {
             // an item whose index is not present will fall back to the previous present path
             const itemParamNames = new Map(crateCorpus.P);
 
-            // an array of [{name: String, ty: Number}]
+            /**
+             * @type {Array<{
+             *     name: string,
+             *     ty: number,
+             *     path: string|null,
+             *     exactPath: string|null,
+             *     unboxFlag: boolean
+             * }>}
+             */
             const lowercasePaths = [];
+            /**
+             * @type {Array<{
+             *     name: string,
+             *     ty: number,
+             *     path: string|null,
+             *     exactPath: string|null,
+             *     unboxFlag: boolean
+             * }>}
+             */
+            const paths = [];
 
             // a string representing the list of function types
             const itemFunctionDecoder = new VlqHexDecoder(
                 crateCorpus.f,
+                // @ts-expect-error
                 buildFunctionSearchTypeCallback(paths, lowercasePaths),
             );
 
             // convert `rawPaths` entries into object form
             // generate normalizedPaths for function search mode
-            let len = paths.length;
+            let len = rawPaths.length;
             let lastPath = itemPaths.get(0);
             for (let i = 0; i < len; ++i) {
-                const elem = paths[i];
+                const elem = rawPaths[i];
                 const ty = elem[0];
                 const name = elem[1];
                 let path = null;
                 if (elem.length > 2 && elem[2] !== null) {
+                    // @ts-expect-error
                     path = itemPaths.has(elem[2]) ? itemPaths.get(elem[2]) : lastPath;
                     lastPath = path;
                 }
-                const exactPath = elem.length > 3 && elem[3] !== null ?
+                let exactPath = elem.length > 3 && elem[3] !== null ?
+                    // @ts-expect-error
                     itemPaths.get(elem[3]) :
                     path;
                 const unboxFlag = elem.length > 4 && !!elem[4];
 
+                if (path === undefined) {
+                    path = null;
+                }
+                if (exactPath === undefined) {
+                    exactPath = null;
+                }
+
                 lowercasePaths.push({ ty, name: name.toLowerCase(), path, exactPath, unboxFlag });
                 paths[i] = { ty, name, path, exactPath, unboxFlag };
             }
@@ -1924,6 +2189,7 @@ class DocSearch {
             for (let i = 0; i < len; ++i) {
                 const bitIndex = i + 1;
                 if (descIndex >= descShard.len &&
+                    // @ts-expect-error
                     !this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
                     descShard = {
                         crate,
@@ -1938,8 +2204,11 @@ class DocSearch {
                 }
                 const name = itemNames[i] === "" ? lastName : itemNames[i];
                 const word = itemNames[i] === "" ? lastWord : itemNames[i].toLowerCase();
+                /** @type {string} */
+                // @ts-expect-error
                 const path = itemPaths.has(i) ? itemPaths.get(i) : lastPath;
                 const paramNames = itemParamNames.has(i) ?
+                    // @ts-expect-error
                     itemParamNames.get(i).split(",") :
                     lastParamNames;
                 const type = itemFunctionDecoder.next();
@@ -1971,7 +2240,9 @@ class DocSearch {
                     descShard,
                     descIndex,
                     exactPath: itemReexports.has(i) ?
+                        // @ts-expect-error
                         itemPaths.get(itemReexports.get(i)) : path,
+                    // @ts-expect-error
                     parent: itemParentIdx > 0 ? paths[itemParentIdx - 1] : undefined,
                     type,
                     paramNames,
@@ -1987,6 +2258,7 @@ class DocSearch {
                 searchIndex.push(row);
                 lastPath = row.path;
                 lastParamNames = row.paramNames;
+                // @ts-expect-error
                 if (!this.searchIndexEmptyDesc.get(crate).contains(bitIndex)) {
                     descIndex += 1;
                 }
@@ -2002,13 +2274,16 @@ class DocSearch {
                         continue;
                     }
 
+                    // @ts-expect-error
                     let currentNameAliases;
                     if (currentCrateAliases.has(alias_name)) {
                         currentNameAliases = currentCrateAliases.get(alias_name);
                     } else {
                         currentNameAliases = [];
+                        // @ts-expect-error
                         currentCrateAliases.set(alias_name, currentNameAliases);
                     }
+                    // @ts-expect-error
                     for (const local_alias of aliases[alias_name]) {
                         currentNameAliases.push(local_alias + currentIndex);
                     }
@@ -2030,11 +2305,15 @@ class DocSearch {
      *
      * When adding new things to the parser, add them there, too!
      *
-     * @param  {string} val     - The user query
+     * @param  {string} userQuery - The user query
      *
-     * @return {ParsedQuery}    - The parsed query
+     * @return {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} - The parsed query
      */
     static parseQuery(userQuery) {
+        /**
+         * @param {string} typename
+         * @returns {number}
+         */
         function itemTypeFromName(typename) {
             const index = itemTypes.findIndex(i => i === typename);
             if (index < 0) {
@@ -2043,14 +2322,19 @@ class DocSearch {
             return index;
         }
 
+        /**
+         * @param {rustdoc.ParserQueryElement} elem
+         */
         function convertTypeFilterOnElem(elem) {
             if (elem.typeFilter !== null) {
                 let typeFilter = elem.typeFilter;
                 if (typeFilter === "const") {
                     typeFilter = "constant";
                 }
+                // @ts-expect-error
                 elem.typeFilter = itemTypeFromName(typeFilter);
             } else {
+                // @ts-expect-error
                 elem.typeFilter = NO_TYPE_FILTER;
             }
             for (const elem2 of elem.generics) {
@@ -2068,7 +2352,7 @@ class DocSearch {
          *
          * @param {string} userQuery
          *
-         * @return {ParsedQuery}
+         * @return {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>}
          */
         function newParsedQuery(userQuery) {
             return {
@@ -2094,8 +2378,8 @@ class DocSearch {
         * Parses the provided `query` input to fill `parserState`. If it encounters an error while
         * parsing `query`, it'll throw an error.
         *
-        * @param {ParsedQuery} query
-        * @param {ParserState} parserState
+        * @param {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} query
+        * @param {rustdoc.ParserState} parserState
         */
         function parseInput(query, parserState) {
             let foundStopChar = true;
@@ -2125,6 +2409,7 @@ class DocSearch {
                 if (!foundStopChar) {
                     let extra = "";
                     if (isLastElemGeneric(query.elems, parserState)) {
+                        // @ts-expect-error
                         extra = [" after ", ">"];
                     } else if (prevIs(parserState, "\"")) {
                         throw ["Cannot have more than one element if you use quotes"];
@@ -2208,6 +2493,8 @@ class DocSearch {
             }
         } catch (err) {
             query = newParsedQuery(userQuery);
+            // is string list
+            // @ts-expect-error
             query.error = err;
             return query;
         }
@@ -2224,25 +2511,167 @@ class DocSearch {
     /**
      * Executes the parsed query and builds a {ResultsTable}.
      *
-     * @param  {ParsedQuery} parsedQuery - The parsed user query
-     * @param  {Object} [filterCrates]   - Crate to search in if defined
-     * @param  {Object} [currentCrate]   - Current crate, to rank results from this crate higher
+     * @param  {rustdoc.ParsedQuery<rustdoc.ParserQueryElement>} origParsedQuery
+     *     - The parsed user query
+     * @param  {Object} [filterCrates] - Crate to search in if defined
+     * @param  {Object} [currentCrate] - Current crate, to rank results from this crate higher
      *
-     * @return {ResultsTable}
+     * @return {Promise<rustdoc.ResultsTable>}
      */
-    async execQuery(parsedQuery, filterCrates, currentCrate) {
+    async execQuery(origParsedQuery, filterCrates, currentCrate) {
         const results_others = new Map(), results_in_args = new Map(),
             results_returned = new Map();
 
+        /** @type {rustdoc.ParsedQuery<rustdoc.QueryElement>} */
+        // @ts-expect-error
+        const parsedQuery = origParsedQuery;
+
+        const queryLen =
+            parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
+            parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
+        const maxEditDistance = Math.floor(queryLen / 3);
+
+        /**
+         * @type {Map<string, number>}
+         */
+        const genericSymbols = new Map();
+
+        /**
+         * Convert names to ids in parsed query elements.
+         * This is not used for the "In Names" tab, but is used for the
+         * "In Params", "In Returns", and "In Function Signature" tabs.
+         *
+         * If there is no matching item, but a close-enough match, this
+         * function also that correction.
+         *
+         * See `buildTypeMapIndex` for more information.
+         *
+         * @param {rustdoc.QueryElement} elem
+         * @param {boolean} isAssocType
+         */
+        const convertNameToId = (elem, isAssocType) => {
+            const loweredName = elem.pathLast.toLowerCase();
+            if (this.typeNameIdMap.has(loweredName) &&
+                // @ts-expect-error
+                (isAssocType || !this.typeNameIdMap.get(loweredName).assocOnly)) {
+                // @ts-expect-error
+                elem.id = this.typeNameIdMap.get(loweredName).id;
+            } else if (!parsedQuery.literalSearch) {
+                let match = null;
+                let matchDist = maxEditDistance + 1;
+                let matchName = "";
+                for (const [name, { id, assocOnly }] of this.typeNameIdMap) {
+                    const dist = Math.min(
+                        editDistance(name, loweredName, maxEditDistance),
+                        editDistance(name, elem.normalizedPathLast, maxEditDistance),
+                    );
+                    if (dist <= matchDist && dist <= maxEditDistance &&
+                        (isAssocType || !assocOnly)) {
+                        if (dist === matchDist && matchName > name) {
+                            continue;
+                        }
+                        match = id;
+                        matchDist = dist;
+                        matchName = name;
+                    }
+                }
+                if (match !== null) {
+                    parsedQuery.correction = matchName;
+                }
+                elem.id = match;
+            }
+            if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
+                && elem.generics.length === 0 && elem.bindings.size === 0)
+                || elem.typeFilter === TY_GENERIC) {
+                if (genericSymbols.has(elem.normalizedPathLast)) {
+                    // @ts-expect-error
+                    elem.id = genericSymbols.get(elem.normalizedPathLast);
+                } else {
+                    elem.id = -(genericSymbols.size + 1);
+                    genericSymbols.set(elem.normalizedPathLast, elem.id);
+                }
+                if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
+                    // Silly heuristic to catch if the user probably meant
+                    // to not write a generic parameter. We don't use it,
+                    // just bring it up.
+                    const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
+                    let matchDist = maxPartDistance + 1;
+                    let matchName = "";
+                    for (const name of this.typeNameIdMap.keys()) {
+                        const dist = editDistance(
+                            name,
+                            elem.normalizedPathLast,
+                            maxPartDistance,
+                        );
+                        if (dist <= matchDist && dist <= maxPartDistance) {
+                            if (dist === matchDist && matchName > name) {
+                                continue;
+                            }
+                            matchDist = dist;
+                            matchName = name;
+                        }
+                    }
+                    if (matchName !== "") {
+                        parsedQuery.proposeCorrectionFrom = elem.name;
+                        parsedQuery.proposeCorrectionTo = matchName;
+                    }
+                }
+                elem.typeFilter = TY_GENERIC;
+            }
+            if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
+                // Rust does not have HKT
+                parsedQuery.error = [
+                    "Generic type parameter ",
+                    elem.name,
+                    " does not accept generic parameters",
+                ];
+            }
+            for (const elem2 of elem.generics) {
+                // @ts-expect-error
+                convertNameToId(elem2);
+            }
+            elem.bindings = new Map(Array.from(elem.bindings.entries())
+                .map(entry => {
+                    const [name, constraints] = entry;
+                    // @ts-expect-error
+                    if (!this.typeNameIdMap.has(name)) {
+                        parsedQuery.error = [
+                            "Type parameter ",
+                            // @ts-expect-error
+                            name,
+                            " does not exist",
+                        ];
+                        return [0, []];
+                    }
+                    for (const elem2 of constraints) {
+                        convertNameToId(elem2, false);
+                    }
+
+                    // @ts-expect-error
+                    return [this.typeNameIdMap.get(name).id, constraints];
+                }),
+            );
+        };
+
+        for (const elem of parsedQuery.elems) {
+            convertNameToId(elem, false);
+            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+        }
+        for (const elem of parsedQuery.returned) {
+            convertNameToId(elem, false);
+            this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
+        }
+
+
         /**
          * Creates the query results.
          *
-         * @param {Array<Result>} results_in_args
-         * @param {Array<Result>} results_returned
-         * @param {Array<Result>} results_others
-         * @param {ParsedQuery} parsedQuery
+         * @param {Array<rustdoc.ResultObject>} results_in_args
+         * @param {Array<rustdoc.ResultObject>} results_returned
+         * @param {Array<rustdoc.ResultObject>} results_others
+         * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} parsedQuery
          *
-         * @return {ResultsTable}
+         * @return {rustdoc.ResultsTable}
          */
         function createQueryResults(
             results_in_args,
@@ -2257,6 +2686,7 @@ class DocSearch {
             };
         }
 
+        // @ts-expect-error
         const buildHrefAndPath = item => {
             let displayPath;
             let href;
@@ -2320,6 +2750,7 @@ class DocSearch {
             return [displayPath, href, `${exactPath}::${name}`];
         };
 
+        // @ts-expect-error
         function pathSplitter(path) {
             const tmp = "<span>" + path.replace(/::/g, "::</span><span>");
             if (tmp.endsWith("<span>")) {
@@ -2332,10 +2763,9 @@ class DocSearch {
          * Add extra data to result objects, and filter items that have been
          * marked for removal.
          *
-         * @param {[ResultObject]} results
+         * @param {[rustdoc.ResultObject]} results
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @param {ParsedQuery} query
-         * @returns {[ResultObject]}
+         * @returns {[rustdoc.ResultObject]}
          */
         const transformResults = (results, typeInfo) => {
             const duplicates = new Set();
@@ -2350,7 +2780,9 @@ class DocSearch {
                     }, this.searchIndex[result.id]);
 
                     // To be sure than it some items aren't considered as duplicate.
+                    // @ts-expect-error
                     obj.fullPath = res[2] + "|" + obj.ty;
+                    // @ts-expect-error
                     if (duplicates.has(obj.fullPath)) {
                         continue;
                     }
@@ -2363,14 +2795,18 @@ class DocSearch {
                     if (duplicates.has(res[2] + "|" + TY_IMPORT)) {
                         continue;
                     }
+                    // @ts-expect-error
                     duplicates.add(obj.fullPath);
                     duplicates.add(res[2]);
 
                     if (typeInfo !== null) {
+                        // @ts-expect-error
                         obj.displayTypeSignature =
+                            // @ts-expect-error
                             this.formatDisplayTypeSignature(obj, typeInfo);
                     }
 
+                    // @ts-expect-error
                     obj.href = res[1];
                     out.push(obj);
                     if (out.length >= MAX_RESULTS) {
@@ -2378,6 +2814,7 @@ class DocSearch {
                     }
                 }
             }
+            // @ts-expect-error
             return out;
         };
 
@@ -2388,30 +2825,34 @@ class DocSearch {
          * The output is formatted as an array of hunks, where odd numbered
          * hunks are highlighted and even numbered ones are not.
          *
-         * @param {ResultObject} obj
+         * @param {rustdoc.ResultObject} obj
          * @param {"sig"|"elems"|"returned"|null} typeInfo
-         * @param {ParsedQuery} query
-         * @returns Promise<
+         * @returns {Promise<{
          *   "type": Array<string>,
          *   "mappedNames": Map<string, string>,
          *   "whereClause": Map<string, Array<string>>,
-         * >
+         * }>}
          */
         this.formatDisplayTypeSignature = async(obj, typeInfo) => {
+            const objType = obj.type;
+            if (!objType) {
+                return {type: [], mappedNames: new Map(), whereClause: new Map()};
+            }
             let fnInputs = null;
             let fnOutput = null;
+            // @ts-expect-error
             let mgens = null;
             if (typeInfo !== "elems" && typeInfo !== "returned") {
                 fnInputs = unifyFunctionTypes(
-                    obj.type.inputs,
+                    objType.inputs,
                     parsedQuery.elems,
-                    obj.type.where_clause,
+                    objType.where_clause,
                     null,
                     mgensScratch => {
                         fnOutput = unifyFunctionTypes(
-                            obj.type.output,
+                            objType.output,
                             parsedQuery.returned,
-                            obj.type.where_clause,
+                            objType.where_clause,
                             mgensScratch,
                             mgensOut => {
                                 mgens = mgensOut;
@@ -2424,11 +2865,11 @@ class DocSearch {
                     0,
                 );
             } else {
-                const arr = typeInfo === "elems" ? obj.type.inputs : obj.type.output;
+                const arr = typeInfo === "elems" ? objType.inputs : objType.output;
                 const highlighted = unifyFunctionTypes(
                     arr,
                     parsedQuery.elems,
-                    obj.type.where_clause,
+                    objType.where_clause,
                     null,
                     mgensOut => {
                         mgens = mgensOut;
@@ -2443,15 +2884,16 @@ class DocSearch {
                 }
             }
             if (!fnInputs) {
-                fnInputs = obj.type.inputs;
+                fnInputs = objType.inputs;
             }
             if (!fnOutput) {
-                fnOutput = obj.type.output;
+                fnOutput = objType.output;
             }
             const mappedNames = new Map();
             const whereClause = new Map();
 
-            const fnParamNames = obj.paramNames;
+            const fnParamNames = obj.paramNames || [];
+            // @ts-expect-error
             const queryParamNames = [];
             /**
              * Recursively writes a map of IDs to query generic names,
@@ -2461,10 +2903,10 @@ class DocSearch {
              * mapping `(-1, "X")`, and the writeFn function looks up the entry
              * for -1 to form the final, user-visible mapping of "X is T".
              *
-             * @param {QueryElement} queryElem
+             * @param {rustdoc.QueryElement} queryElem
              */
             const remapQuery = queryElem => {
-                if (queryElem.id < 0) {
+                if (queryElem.id !== null && queryElem.id < 0) {
                     queryParamNames[-1 - queryElem.id] = queryElem.name;
                 }
                 if (queryElem.generics.length > 0) {
@@ -2483,7 +2925,7 @@ class DocSearch {
              * Index 0 is not highlighted, index 1 is highlighted,
              * index 2 is not highlighted, etc.
              *
-             * @param {{name: string, highlighted: bool|undefined}} fnType - input
+             * @param {{name?: string, highlighted?: boolean}} fnType - input
              * @param {[string]} result
              */
             const pushText = (fnType, result) => {
@@ -2496,6 +2938,7 @@ class DocSearch {
                 // needs coerced to a boolean.
                 if (!!(result.length % 2) === !!fnType.highlighted) {
                     result.push("");
+                // @ts-expect-error
                 } else if (result.length === 0 && !!fnType.highlighted) {
                     result.push("");
                     result.push("");
@@ -2508,7 +2951,7 @@ class DocSearch {
              * Write a higher order function type: either a function pointer
              * or a trait bound on Fn, FnMut, or FnOnce.
              *
-             * @param {FunctionType} fnType - input
+             * @param {rustdoc.HighlightedFunctionType} fnType - input
              * @param {[string]} result
              */
             const writeHof = (fnType, result) => {
@@ -2548,7 +2991,7 @@ class DocSearch {
              * Write a primitive type with special syntax, like `!` or `[T]`.
              * Returns `false` if the supplied type isn't special.
              *
-             * @param {FunctionType} fnType
+             * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {[string]} result
              */
             const writeSpecialPrimitive = (fnType, result) => {
@@ -2563,6 +3006,7 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         nested => writeFn(nested, result),
+                        // @ts-expect-error
                         () => pushText({ name: ", ", highlighted: false }, result),
                     );
                     pushText({ name: sb, highlighted: fnType.highlighted }, result);
@@ -2573,9 +3017,10 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         value => {
-                            prevHighlighted = value.highlighted;
+                            prevHighlighted = !!value.highlighted;
                             writeFn(value, result);
                         },
+                        // @ts-expect-error
                         value => pushText({
                             name: " ",
                             highlighted: prevHighlighted && value.highlighted,
@@ -2593,25 +3038,27 @@ class DocSearch {
              * like slices, with their own formatting. It also handles
              * updating the where clause and generic type param map.
              *
-             * @param {FunctionType} fnType
+             * @param {rustdoc.HighlightedFunctionType} fnType
              * @param {[string]} result
              */
             const writeFn = (fnType, result) => {
-                if (fnType.id < 0) {
+                if (fnType.id !== null && fnType.id < 0) {
                     if (fnParamNames[-1 - fnType.id] === "") {
                         // Normally, there's no need to shown an unhighlighted
                         // where clause, but if it's impl Trait, then we do.
                         const generics = fnType.generics.length > 0 ?
                             fnType.generics :
-                            obj.type.where_clause[-1 - fnType.id];
+                            objType.where_clause[-1 - fnType.id];
                         for (const nested of generics) {
                             writeFn(nested, result);
                         }
                         return;
+                    // @ts-expect-error
                     } else if (mgens) {
                         for (const [queryId, fnId] of mgens) {
                             if (fnId === fnType.id) {
                                 mappedNames.set(
+                                    // @ts-expect-error
                                     queryParamNames[-1 - queryId],
                                     fnParamNames[-1 - fnType.id],
                                 );
@@ -2622,13 +3069,17 @@ class DocSearch {
                         name: fnParamNames[-1 - fnType.id],
                         highlighted: !!fnType.highlighted,
                     }, result);
+                    // @ts-expect-error
                     const where = [];
                     onEachBtwn(
                         fnType.generics,
+                        // @ts-expect-error
                         nested => writeFn(nested, where),
+                        // @ts-expect-error
                         () => pushText({ name: " + ", highlighted: false }, where),
                     );
                     if (where.length > 0) {
+                        // @ts-expect-error
                         whereClause.set(fnParamNames[-1 - fnType.id], where);
                     }
                 } else {
@@ -2650,12 +3101,15 @@ class DocSearch {
                             fnType.bindings,
                             ([key, values]) => {
                                 const name = this.assocTypeIdNameMap.get(key);
+                                // @ts-expect-error
                                 if (values.length === 1 && values[0].id < 0 &&
+                                    // @ts-expect-error
                                     `${fnType.name}::${name}` === fnParamNames[-1 - values[0].id]) {
                                     // the internal `Item=Iterator::Item` type variable should be
                                     // shown in the where clause and name mapping output, but is
                                     // redundant in this spot
                                     for (const value of values) {
+                                        // @ts-expect-error
                                         writeFn(value, []);
                                     }
                                     return true;
@@ -2672,12 +3126,14 @@ class DocSearch {
                                 onEachBtwn(
                                     values || [],
                                     value => writeFn(value, result),
+                                    // @ts-expect-error
                                     () => pushText({ name: " + ",  highlighted: false }, result),
                                 );
                                 if (values.length !== 1) {
                                     pushText({ name: ")", highlighted: false }, result);
                                 }
                             },
+                            // @ts-expect-error
                             () => pushText({ name: ", ",  highlighted: false }, result),
                         );
                     }
@@ -2687,6 +3143,7 @@ class DocSearch {
                     onEachBtwn(
                         fnType.generics,
                         value => writeFn(value, result),
+                        // @ts-expect-error
                         () => pushText({ name: ", ",  highlighted: false }, result),
                     );
                     if (hasBindings || fnType.generics.length > 0) {
@@ -2694,19 +3151,26 @@ class DocSearch {
                     }
                 }
             };
+            // @ts-expect-error
             const type = [];
             onEachBtwn(
                 fnInputs,
+                // @ts-expect-error
                 fnType => writeFn(fnType, type),
+                // @ts-expect-error
                 () => pushText({ name: ", ",  highlighted: false }, type),
             );
+            // @ts-expect-error
             pushText({ name: " -> ", highlighted: false }, type);
             onEachBtwn(
                 fnOutput,
+                // @ts-expect-error
                 fnType => writeFn(fnType, type),
+                // @ts-expect-error
                 () => pushText({ name: ", ",  highlighted: false }, type),
             );
 
+            // @ts-expect-error
             return {type, mappedNames, whereClause};
         };
 
@@ -2714,10 +3178,10 @@ class DocSearch {
          * This function takes a result map, and sorts it by various criteria, including edit
          * distance, substring match, and the crate it comes from.
          *
-         * @param {Results} results
-         * @param {boolean} isType
+         * @param {rustdoc.Results} results
+         * @param {"sig"|"elems"|"returned"|null} typeInfo
          * @param {string} preferredCrate
-         * @returns {Promise<[ResultObject]>}
+         * @returns {Promise<[rustdoc.ResultObject]>}
          */
         const sortResults = async(results, typeInfo, preferredCrate) => {
             const userQuery = parsedQuery.userQuery;
@@ -2733,12 +3197,12 @@ class DocSearch {
                     // we are doing a return-type based search,
                     // deprioritize "clone-like" results,
                     // ie. functions that also take the queried type as an argument.
-                    const hasType = result.item && result.item.type;
-                    if (!hasType) {
+                    const resultItemType = result.item && result.item.type;
+                    if (!resultItemType) {
                         continue;
                     }
-                    const inputs = result.item.type.inputs;
-                    const where_clause = result.item.type.where_clause;
+                    const inputs = resultItemType.inputs;
+                    const where_clause = resultItemType.where_clause;
                     if (containsTypeFromQuery(inputs, where_clause)) {
                         result.path_dist *= 100;
                         result.dist *= 100;
@@ -2748,35 +3212,38 @@ class DocSearch {
             }
 
             result_list.sort((aaa, bbb) => {
-                let a, b;
+                /** @type {number} */
+                let a;
+                /** @type {number} */
+                let b;
 
                 // sort by exact case-sensitive match
                 if (isMixedCase) {
-                    a = (aaa.item.name !== userQuery);
-                    b = (bbb.item.name !== userQuery);
+                    a = Number(aaa.item.name !== userQuery);
+                    b = Number(bbb.item.name !== userQuery);
                     if (a !== b) {
                         return a - b;
                     }
                 }
 
                 // sort by exact match with regard to the last word (mismatch goes later)
-                a = (aaa.word !== normalizedUserQuery);
-                b = (bbb.word !== normalizedUserQuery);
+                a = Number(aaa.word !== normalizedUserQuery);
+                b = Number(bbb.word !== normalizedUserQuery);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by index of keyword in item name (no literal occurrence goes later)
-                a = (aaa.index < 0);
-                b = (bbb.index < 0);
+                a = Number(aaa.index < 0);
+                b = Number(bbb.index < 0);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // in type based search, put functions first
                 if (parsedQuery.hasReturnArrow) {
-                    a = !isFnLikeTy(aaa.item.ty);
-                    b = !isFnLikeTy(bbb.item.ty);
+                    a = Number(!isFnLikeTy(aaa.item.ty));
+                    b = Number(!isFnLikeTy(bbb.item.ty));
                     if (a !== b) {
                         return a - b;
                     }
@@ -2784,80 +3251,93 @@ class DocSearch {
 
                 // Sort by distance in the path part, if specified
                 // (less changes required to match means higher rankings)
-                a = aaa.path_dist;
-                b = bbb.path_dist;
+                a = Number(aaa.path_dist);
+                b = Number(bbb.path_dist);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // (later literal occurrence, if any, goes later)
-                a = aaa.index;
-                b = bbb.index;
+                a = Number(aaa.index);
+                b = Number(bbb.index);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // Sort by distance in the name part, the last part of the path
                 // (less changes required to match means higher rankings)
-                a = (aaa.dist);
-                b = (bbb.dist);
+                a = Number(aaa.dist);
+                b = Number(bbb.dist);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort deprecated items later
-                a = this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex);
-                b = this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex);
+                a = Number(
+                    // @ts-expect-error
+                    this.searchIndexDeprecated.get(aaa.item.crate).contains(aaa.item.bitIndex),
+                );
+                b = Number(
+                    // @ts-expect-error
+                    this.searchIndexDeprecated.get(bbb.item.crate).contains(bbb.item.bitIndex),
+                );
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by crate (current crate comes first)
-                a = (aaa.item.crate !== preferredCrate);
-                b = (bbb.item.crate !== preferredCrate);
+                a = Number(aaa.item.crate !== preferredCrate);
+                b = Number(bbb.item.crate !== preferredCrate);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by item name length (longer goes later)
-                a = aaa.word.length;
-                b = bbb.word.length;
+                a = Number(aaa.word.length);
+                b = Number(bbb.word.length);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by item name (lexicographically larger goes later)
-                a = aaa.word;
-                b = bbb.word;
-                if (a !== b) {
-                    return (a > b ? +1 : -1);
+                let aw = aaa.word;
+                let bw = bbb.word;
+                if (aw !== bw) {
+                    return (aw > bw ? +1 : -1);
                 }
 
                 // sort by description (no description goes later)
-                a = this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex);
-                b = this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex);
+                a = Number(
+                    // @ts-expect-error
+                    this.searchIndexEmptyDesc.get(aaa.item.crate).contains(aaa.item.bitIndex),
+                );
+                b = Number(
+                    // @ts-expect-error
+                    this.searchIndexEmptyDesc.get(bbb.item.crate).contains(bbb.item.bitIndex),
+                );
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by type (later occurrence in `itemTypes` goes later)
-                a = aaa.item.ty;
-                b = bbb.item.ty;
+                a = Number(aaa.item.ty);
+                b = Number(bbb.item.ty);
                 if (a !== b) {
                     return a - b;
                 }
 
                 // sort by path (lexicographically larger goes later)
-                a = aaa.item.path;
-                b = bbb.item.path;
-                if (a !== b) {
-                    return (a > b ? +1 : -1);
+                aw = aaa.item.path;
+                bw = bbb.item.path;
+                if (aw !== bw) {
+                    return (aw > bw ? +1 : -1);
                 }
 
                 // que sera, sera
                 return 0;
             });
 
+            // @ts-expect-error
             return transformResults(result_list, typeInfo);
         };
 
@@ -2871,17 +3351,19 @@ class DocSearch {
          * then this function will try with a different solution, or bail with null if it
          * runs out of candidates.
          *
-         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
-         * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} fnTypesIn - The objects to check.
+         * @param {rustdoc.QueryElement[]} queryElems - The elements from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
          *     - Map query generics to function generics (never modified).
-         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {function(Map<number,number>?): boolean} solutionCb
+         *     - Called for each `mgens` solution.
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
-         * @return {[FunctionType]|null} - Returns highlighted results if a match, null otherwise.
+         * @return {rustdoc.HighlightedFunctionType[]|null}
+         *     - Returns highlighted results if a match, null otherwise.
          */
         function unifyFunctionTypes(
             fnTypesIn,
@@ -2895,7 +3377,7 @@ class DocSearch {
                 return null;
             }
             /**
-             * @type Map<integer, integer>|null
+             * @type {Map<number, number>|null}
              */
             const mgens = mgensIn === null ? null : new Map(mgensIn);
             if (queryElems.length === 0) {
@@ -2915,7 +3397,11 @@ class DocSearch {
                     if (!unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
                         continue;
                     }
-                    if (fnType.id < 0 && queryElem.id < 0) {
+                    if (fnType.id !== null &&
+                        fnType.id < 0 &&
+                        queryElem.id !== null &&
+                        queryElem.id < 0
+                    ) {
                         if (mgens && mgens.has(queryElem.id) &&
                             mgens.get(queryElem.id) !== fnType.id) {
                             continue;
@@ -2959,8 +3445,10 @@ class DocSearch {
                     )) {
                         continue;
                     }
+                    // @ts-expect-error
                     if (fnType.id < 0) {
                         const highlightedGenerics = unifyFunctionTypes(
+                            // @ts-expect-error
                             whereClause[(-fnType.id) - 1],
                             queryElems,
                             whereClause,
@@ -2998,12 +3486,13 @@ class DocSearch {
                         }
                     }
                 }
+                // @ts-expect-error
                 return false;
             }
 
             // Multiple element recursive case
             /**
-             * @type Array<FunctionType>
+             * @type {Array<rustdoc.FunctionType>}
              */
             const fnTypes = fnTypesIn.slice();
             /**
@@ -3033,7 +3522,7 @@ class DocSearch {
                     continue;
                 }
                 let mgensScratch;
-                if (fnType.id < 0) {
+                if (fnType.id !== null && queryElem.id !== null && fnType.id < 0) {
                     mgensScratch = new Map(mgens);
                     if (mgensScratch.has(queryElem.id)
                         && mgensScratch.get(queryElem.id) !== fnType.id) {
@@ -3052,8 +3541,11 @@ class DocSearch {
                 if (!queryElemsTmp) {
                     queryElemsTmp = queryElems.slice(0, qlast);
                 }
+                /** @type {rustdoc.HighlightedFunctionType[]|null} */
                 let unifiedGenerics = [];
+                // @ts-expect-error
                 let unifiedGenericsMgens = null;
+                /** @type {rustdoc.HighlightedFunctionType[]|null} */
                 const passesUnification = unifyFunctionTypes(
                     fnTypes,
                     queryElemsTmp,
@@ -3102,11 +3594,14 @@ class DocSearch {
                         bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
                             return [k, queryElem.bindings.has(k) ? unifyFunctionTypes(
                                 v,
+                                // @ts-expect-error
                                 queryElem.bindings.get(k),
                                 whereClause,
+                                // @ts-expect-error
                                 unifiedGenericsMgens,
                                 solutionCb,
                                 unboxingDepth,
+                            // @ts-expect-error
                             ) : unifiedGenerics.splice(0, v.length)];
                         })),
                     });
@@ -3128,7 +3623,7 @@ class DocSearch {
                 )) {
                     continue;
                 }
-                const generics = fnType.id < 0 ?
+                const generics = fnType.id !== null && fnType.id < 0 ?
                     whereClause[(-fnType.id) - 1] :
                     fnType.generics;
                 const bindings = fnType.bindings ?
@@ -3171,17 +3666,19 @@ class DocSearch {
          * `Vec` of `Allocators` and not the implicit `Allocator` parameter that every
          * `Vec` has.
          *
-         * @param {Array<FunctionType>} fnTypesIn - The objects to check.
-         * @param {Array<QueryElement>} queryElems - The elements from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {Array<rustdoc.FunctionType>} fnTypesIn - The objects to check.
+         * @param {Array<rustdoc.QueryElement>} queryElems - The elements from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgensIn
          *     - Map functions generics to query generics (never modified).
-         * @param {Map<number,number> -> bool} solutionCb - Called for each `mgens` solution.
+         * @param {function(Map<number,number>): boolean} solutionCb
+         *     - Called for each `mgens` solution.
          * @param {number} unboxingDepth
          *     - Limit checks that Ty matches Vec<Ty>,
          *       but not Vec<ParamEnvAnd<WithInfcx<ConstTy<Interner<Ty=Ty>>>>>
          *
-         * @return {[FunctionType]|null} - Returns highlighted results if a match, null otherwise.
+         * @return {rustdoc.HighlightedFunctionType[]|null}
+         *     - Returns highlighted results if a match, null otherwise.
          */
         function unifyGenericTypes(
             fnTypesIn,
@@ -3195,10 +3692,11 @@ class DocSearch {
                 return null;
             }
             /**
-             * @type Map<integer, integer>|null
+             * @type {Map<number, number>|null}
              */
             const mgens = mgensIn === null ? null : new Map(mgensIn);
             if (queryElems.length === 0) {
+                // @ts-expect-error
                 return solutionCb(mgens) ? fnTypesIn : null;
             }
             if (!fnTypesIn || fnTypesIn.length === 0) {
@@ -3207,7 +3705,11 @@ class DocSearch {
             const fnType = fnTypesIn[0];
             const queryElem = queryElems[0];
             if (unifyFunctionTypeIsMatchCandidate(fnType, queryElem, mgens)) {
-                if (fnType.id < 0 && queryElem.id < 0) {
+                if (fnType.id !== null &&
+                    fnType.id < 0 &&
+                    queryElem.id !== null &&
+                    queryElem.id < 0
+                ) {
                     if (!mgens || !mgens.has(queryElem.id) ||
                         mgens.get(queryElem.id) === fnType.id
                     ) {
@@ -3238,6 +3740,7 @@ class DocSearch {
                         queryElems.slice(1),
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const solution = unifyFunctionTypeCheckBindings(
                                 fnType,
@@ -3285,7 +3788,7 @@ class DocSearch {
                 unboxingDepth + 1,
             )) {
                 let highlightedRemaining;
-                if (fnType.id < 0) {
+                if (fnType.id !== null && fnType.id < 0) {
                     // Where clause corresponds to `F: A + B`
                     //                                 ^^^^^
                     // The order of the constraints doesn't matter, so
@@ -3295,6 +3798,7 @@ class DocSearch {
                         [queryElem],
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const hl = unifyGenericTypes(
                                 fnTypesIn.slice(1),
@@ -3316,6 +3820,7 @@ class DocSearch {
                             highlighted: true,
                         }, fnType, {
                             generics: highlightedGenerics,
+                        // @ts-expect-error
                         }), ...highlightedRemaining];
                     }
                 } else {
@@ -3327,6 +3832,7 @@ class DocSearch {
                         [queryElem],
                         whereClause,
                         mgens,
+                        // @ts-expect-error
                         mgensScratch => {
                             const hl = unifyGenericTypes(
                                 fnTypesIn.slice(1),
@@ -3349,6 +3855,7 @@ class DocSearch {
                             bindings: new Map([...fnType.bindings.entries()].map(([k, v]) => {
                                 return [k, highlightedGenerics.splice(0, v.length)];
                             })),
+                        // @ts-expect-error
                         }), ...highlightedRemaining];
                     }
                 }
@@ -3364,8 +3871,8 @@ class DocSearch {
          * or associated type bindings: that's not load-bearing, but it prevents unnecessary
          * backtracking later.
          *
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
          * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          * @returns {boolean}
          */
@@ -3377,7 +3884,7 @@ class DocSearch {
             // fnType.id < 0 means generic
             // queryElem.id < 0 does too
             // mgensIn[queryElem.id] = fnType.id
-            if (fnType.id < 0 && queryElem.id < 0) {
+            if (fnType.id !== null && fnType.id < 0 && queryElem.id !== null && queryElem.id < 0) {
                 if (
                     mgensIn && mgensIn.has(queryElem.id) &&
                     mgensIn.get(queryElem.id) !== fnType.id
@@ -3456,13 +3963,15 @@ class DocSearch {
          * ID of u32 in it, and the rest of the matching engine acts as if `Iterator<u32>` were
          * the type instead.
          *
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
-         * @param {Map<number,number>} mgensIn - Map query generics to function generics.
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
+         * @param {Map<number,number>|null} mgensIn - Map query generics to function generics.
          *                                            Never modified.
          * @param {number} unboxingDepth
-         * @returns {false|{mgens: [Map<number,number>], simplifiedGenerics: [FunctionType]}}
+         * @returns {false|{
+         *     mgens: [Map<number,number>|null], simplifiedGenerics: rustdoc.FunctionType[]
+         * }}
          */
         function unifyFunctionTypeCheckBindings(
             fnType,
@@ -3486,8 +3995,10 @@ class DocSearch {
                     }
                     const fnTypeBindings = fnType.bindings.get(name);
                     mgensSolutionSet = mgensSolutionSet.flatMap(mgens => {
+                        // @ts-expect-error
                         const newSolutions = [];
                         unifyFunctionTypes(
+                            // @ts-expect-error
                             fnTypeBindings,
                             constraints,
                             whereClause,
@@ -3500,6 +4011,7 @@ class DocSearch {
                             },
                             unboxingDepth,
                         );
+                        // @ts-expect-error
                         return newSolutions;
                     });
                 }
@@ -3519,14 +4031,15 @@ class DocSearch {
                 } else {
                     simplifiedGenerics = binds;
                 }
+                // @ts-expect-error
                 return { simplifiedGenerics, mgens: mgensSolutionSet };
             }
             return { simplifiedGenerics, mgens: [mgensIn] };
         }
         /**
-         * @param {FunctionType} fnType
-         * @param {QueryElement} queryElem
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType} fnType
+         * @param {rustdoc.QueryElement} queryElem
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          * @param {number} unboxingDepth
          * @returns {boolean}
@@ -3541,7 +4054,7 @@ class DocSearch {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (fnType.id < 0) {
+            if (fnType.id !== null && fnType.id < 0) {
                 if (!whereClause) {
                     return false;
                 }
@@ -3577,14 +4090,14 @@ class DocSearch {
          * This function checks if the given list contains any
          * (non-generic) types mentioned in the query.
          *
-         * @param {Array<FunctionType>} list    - A list of function types.
-         * @param {[FunctionType]} where_clause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} list    - A list of function types.
+         * @param {rustdoc.FunctionType[][]} where_clause - Trait bounds for generic items.
          */
         function containsTypeFromQuery(list, where_clause) {
             if (!list) return false;
             for (const ty of parsedQuery.returned) {
                 // negative type ids are generics
-                if (ty.id < 0) {
+                if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
                 if (checkIfInList(list, ty, where_clause, null, 0)) {
@@ -3592,7 +4105,7 @@ class DocSearch {
                 }
             }
             for (const ty of parsedQuery.elems) {
-                if (ty.id < 0) {
+                if (ty.id !== null && ty.id < 0) {
                     continue;
                 }
                 if (checkIfInList(list, ty, where_clause, null, 0)) {
@@ -3606,9 +4119,9 @@ class DocSearch {
          * This function checks if the object (`row`) matches the given type (`elem`) and its
          * generics (if any).
          *
-         * @param {Array<FunctionType>} list
-         * @param {QueryElement} elem          - The element from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType[]} list
+         * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map functions generics to query generics.
          * @param {number} unboxingDepth
          *
@@ -3627,18 +4140,20 @@ class DocSearch {
          * This function checks if the object (`row`) matches the given type (`elem`) and its
          * generics (if any).
          *
-         * @param {Row} row
-         * @param {QueryElement} elem          - The element from the parsed query.
-         * @param {[FunctionType]} whereClause - Trait bounds for generic items.
+         * @param {rustdoc.FunctionType} row
+         * @param {rustdoc.QueryElement} elem          - The element from the parsed query.
+         * @param {rustdoc.FunctionType[][]} whereClause - Trait bounds for generic items.
          * @param {Map<number,number>|null} mgens - Map query generics to function generics.
          *
          * @return {boolean} - Returns true if the type matches, false otherwise.
          */
+        // @ts-expect-error
         const checkType = (row, elem, whereClause, mgens, unboxingDepth) => {
             if (unboxingDepth >= UNBOXING_LIMIT) {
                 return false;
             }
-            if (row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
+            if (row.id !== null && elem.id !== null &&
+                row.id > 0 && elem.id > 0 && elem.pathWithoutLast.length === 0 &&
                 row.generics.length === 0 && elem.generics.length === 0 &&
                 row.bindings.size === 0 && elem.bindings.size === 0 &&
                 // special case
@@ -3648,6 +4163,7 @@ class DocSearch {
             ) {
                 return row.id === elem.id && typePassesFilter(elem.typeFilter, row.ty);
             } else {
+                // @ts-expect-error
                 return unifyFunctionTypes(
                     [row],
                     [elem],
@@ -3662,6 +4178,7 @@ class DocSearch {
         /**
          * Check a query solution for conflicting generics.
          */
+        // @ts-expect-error
         const checkTypeMgensForConflict = mgens => {
             if (!mgens) {
                 return true;
@@ -3679,7 +4196,7 @@ class DocSearch {
         /**
          * Compute an "edit distance" that ignores missing path elements.
          * @param {string[]} contains search query path
-         * @param {Row} ty indexed item
+         * @param {rustdoc.Row} ty indexed item
          * @returns {null|number} edit distance
          */
         function checkPath(contains, ty) {
@@ -3720,6 +4237,7 @@ class DocSearch {
             return ret_dist > maxPathEditDistance ? null : ret_dist;
         }
 
+        // @ts-expect-error
         function typePassesFilter(filter, type) {
             // No filter or Exact mach
             if (filter <= NO_TYPE_FILTER || filter === type) return true;
@@ -3741,6 +4259,7 @@ class DocSearch {
             return false;
         }
 
+        // @ts-expect-error
         function createAliasFromItem(item) {
             return {
                 crate: item.crate,
@@ -3758,11 +4277,14 @@ class DocSearch {
             };
         }
 
+        // @ts-expect-error
         const handleAliases = async(ret, query, filterCrates, currentCrate) => {
             const lowerQuery = query.toLowerCase();
             // We separate aliases and crate aliases because we want to have current crate
             // aliases to be before the others in the displayed results.
+            // @ts-expect-error
             const aliases = [];
+            // @ts-expect-error
             const crateAliases = [];
             if (filterCrates !== null) {
                 if (this.ALIASES.has(filterCrates)
@@ -3775,6 +4297,7 @@ class DocSearch {
             } else {
                 for (const [crate, crateAliasesIndex] of this.ALIASES) {
                     if (crateAliasesIndex.has(lowerQuery)) {
+                        // @ts-expect-error
                         const pushTo = crate === currentCrate ? crateAliases : aliases;
                         const query_aliases = crateAliasesIndex.get(lowerQuery);
                         for (const alias of query_aliases) {
@@ -3784,6 +4307,7 @@ class DocSearch {
                 }
             }
 
+            // @ts-expect-error
             const sortFunc = (aaa, bbb) => {
                 if (aaa.path < bbb.path) {
                     return 1;
@@ -3792,18 +4316,23 @@ class DocSearch {
                 }
                 return -1;
             };
+            // @ts-expect-error
             crateAliases.sort(sortFunc);
             aliases.sort(sortFunc);
 
+            // @ts-expect-error
             const fetchDesc = alias => {
+                // @ts-expect-error
                 return this.searchIndexEmptyDesc.get(alias.crate).contains(alias.bitIndex) ?
                     "" : this.searchState.loadDesc(alias);
             };
             const [crateDescs, descs] = await Promise.all([
+                // @ts-expect-error
                 Promise.all(crateAliases.map(fetchDesc)),
                 Promise.all(aliases.map(fetchDesc)),
             ]);
 
+            // @ts-expect-error
             const pushFunc = alias => {
                 alias.alias = query;
                 const res = buildHrefAndPath(alias);
@@ -3818,12 +4347,15 @@ class DocSearch {
             };
 
             aliases.forEach((alias, i) => {
+                // @ts-expect-error
                 alias.desc = descs[i];
             });
             aliases.forEach(pushFunc);
+            // @ts-expect-error
             crateAliases.forEach((alias, i) => {
                 alias.desc = crateDescs[i];
             });
+            // @ts-expect-error
             crateAliases.forEach(pushFunc);
         };
 
@@ -3843,21 +4375,24 @@ class DocSearch {
          * * `path_dist` is zero if a single-component search query is used, otherwise it's the
          *   distance computed for everything other than the last path component.
          *
-         * @param {Results} results
+         * @param {rustdoc.Results} results
          * @param {string} fullId
-         * @param {integer} id
-         * @param {integer} index
-         * @param {integer} dist
-         * @param {integer} path_dist
+         * @param {number} id
+         * @param {number} index
+         * @param {number} dist
+         * @param {number} path_dist
          */
+        // @ts-expect-error
         function addIntoResults(results, fullId, id, index, dist, path_dist, maxEditDistance) {
             if (dist <= maxEditDistance || index !== -1) {
                 if (results.has(fullId)) {
                     const result = results.get(fullId);
+                    // @ts-expect-error
                     if (result.dontValidate || result.dist <= dist) {
                         return;
                     }
                 }
+                // @ts-expect-error
                 results.set(fullId, {
                     id: id,
                     index: index,
@@ -3873,12 +4408,16 @@ class DocSearch {
          * try to match the items which validates all the elements. For `aa -> bb` will look for
          * functions which have a parameter `aa` and has `bb` in its returned values.
          *
-         * @param {Row} row
-         * @param {integer} pos      - Position in the `searchIndex`.
-         * @param {Object} results
+         * @param {rustdoc.Row} row
+         * @param {number} pos      - Position in the `searchIndex`.
+         * @param {rustdoc.Results} results
          */
         function handleArgs(row, pos, results) {
-            if (!row || (filterCrates !== null && row.crate !== filterCrates) || !row.type) {
+            if (!row || (filterCrates !== null && row.crate !== filterCrates)) {
+                return;
+            }
+            const rowType = row.type;
+            if (!rowType) {
                 return;
             }
 
@@ -3889,21 +4428,23 @@ class DocSearch {
             if (tfpDist === null) {
                 return;
             }
+            // @ts-expect-error
             if (results.size >= MAX_RESULTS && tfpDist > results.max_dist) {
                 return;
             }
 
             // If the result is too "bad", we return false and it ends this search.
             if (!unifyFunctionTypes(
-                row.type.inputs,
+                rowType.inputs,
                 parsedQuery.elems,
-                row.type.where_clause,
+                rowType.where_clause,
                 null,
+                // @ts-expect-error
                 mgens => {
                     return unifyFunctionTypes(
-                        row.type.output,
+                        rowType.output,
                         parsedQuery.returned,
-                        row.type.where_clause,
+                        rowType.where_clause,
                         mgens,
                         checkTypeMgensForConflict,
                         0, // unboxing depth
@@ -3914,15 +4455,16 @@ class DocSearch {
                 return;
             }
 
+            // @ts-expect-error
             results.max_dist = Math.max(results.max_dist || 0, tfpDist);
-            addIntoResults(results, row.id, pos, 0, tfpDist, 0, Number.MAX_VALUE);
+            addIntoResults(results, row.id.toString(), pos, 0, tfpDist, 0, Number.MAX_VALUE);
         }
 
         /**
          * Compare the query fingerprint with the function fingerprint.
          *
-         * @param {{number}} fullId - The function
-         * @param {{Uint32Array}} queryFingerprint - The query
+         * @param {number} fullId - The function
+         * @param {Uint32Array} queryFingerprint - The query
          * @returns {number|null} - Null if non-match, number if distance
          *                          This function might return 0!
          */
@@ -3953,138 +4495,10 @@ class DocSearch {
 
 
         const innerRunQuery = () => {
-            const queryLen =
-                parsedQuery.elems.reduce((acc, next) => acc + next.pathLast.length, 0) +
-                parsedQuery.returned.reduce((acc, next) => acc + next.pathLast.length, 0);
-            const maxEditDistance = Math.floor(queryLen / 3);
-
-            /**
-             * @type {Map<string, integer>}
-             */
-            const genericSymbols = new Map();
-
-            /**
-             * Convert names to ids in parsed query elements.
-             * This is not used for the "In Names" tab, but is used for the
-             * "In Params", "In Returns", and "In Function Signature" tabs.
-             *
-             * If there is no matching item, but a close-enough match, this
-             * function also that correction.
-             *
-             * See `buildTypeMapIndex` for more information.
-             *
-             * @param {QueryElement} elem
-             * @param {boolean} isAssocType
-             */
-            const convertNameToId = (elem, isAssocType) => {
-                const loweredName = elem.pathLast.toLowerCase();
-                if (this.typeNameIdMap.has(loweredName) &&
-                    (isAssocType || !this.typeNameIdMap.get(loweredName).assocOnly)) {
-                    elem.id = this.typeNameIdMap.get(loweredName).id;
-                } else if (!parsedQuery.literalSearch) {
-                    let match = null;
-                    let matchDist = maxEditDistance + 1;
-                    let matchName = "";
-                    for (const [name, { id, assocOnly }] of this.typeNameIdMap) {
-                        const dist = Math.min(
-                            editDistance(name, loweredName, maxEditDistance),
-                            editDistance(name, elem.normalizedPathLast, maxEditDistance),
-                        );
-                        if (dist <= matchDist && dist <= maxEditDistance &&
-                            (isAssocType || !assocOnly)) {
-                            if (dist === matchDist && matchName > name) {
-                                continue;
-                            }
-                            match = id;
-                            matchDist = dist;
-                            matchName = name;
-                        }
-                    }
-                    if (match !== null) {
-                        parsedQuery.correction = matchName;
-                    }
-                    elem.id = match;
-                }
-                if ((elem.id === null && parsedQuery.totalElems > 1 && elem.typeFilter === -1
-                    && elem.generics.length === 0 && elem.bindings.size === 0)
-                    || elem.typeFilter === TY_GENERIC) {
-                    if (genericSymbols.has(elem.normalizedPathLast)) {
-                        elem.id = genericSymbols.get(elem.normalizedPathLast);
-                    } else {
-                        elem.id = -(genericSymbols.size + 1);
-                        genericSymbols.set(elem.normalizedPathLast, elem.id);
-                    }
-                    if (elem.typeFilter === -1 && elem.normalizedPathLast.length >= 3) {
-                        // Silly heuristic to catch if the user probably meant
-                        // to not write a generic parameter. We don't use it,
-                        // just bring it up.
-                        const maxPartDistance = Math.floor(elem.normalizedPathLast.length / 3);
-                        let matchDist = maxPartDistance + 1;
-                        let matchName = "";
-                        for (const name of this.typeNameIdMap.keys()) {
-                            const dist = editDistance(
-                                name,
-                                elem.normalizedPathLast,
-                                maxPartDistance,
-                            );
-                            if (dist <= matchDist && dist <= maxPartDistance) {
-                                if (dist === matchDist && matchName > name) {
-                                    continue;
-                                }
-                                matchDist = dist;
-                                matchName = name;
-                            }
-                        }
-                        if (matchName !== "") {
-                            parsedQuery.proposeCorrectionFrom = elem.name;
-                            parsedQuery.proposeCorrectionTo = matchName;
-                        }
-                    }
-                    elem.typeFilter = TY_GENERIC;
-                }
-                if (elem.generics.length > 0 && elem.typeFilter === TY_GENERIC) {
-                    // Rust does not have HKT
-                    parsedQuery.error = [
-                        "Generic type parameter ",
-                        elem.name,
-                        " does not accept generic parameters",
-                    ];
-                }
-                for (const elem2 of elem.generics) {
-                    convertNameToId(elem2);
-                }
-                elem.bindings = new Map(Array.from(elem.bindings.entries())
-                    .map(entry => {
-                        const [name, constraints] = entry;
-                        if (!this.typeNameIdMap.has(name)) {
-                            parsedQuery.error = [
-                                "Type parameter ",
-                                name,
-                                " does not exist",
-                            ];
-                            return [null, []];
-                        }
-                        for (const elem2 of constraints) {
-                            convertNameToId(elem2);
-                        }
-
-                        return [this.typeNameIdMap.get(name).id, constraints];
-                    }),
-                );
-            };
-
-            for (const elem of parsedQuery.elems) {
-                convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
-            }
-            for (const elem of parsedQuery.returned) {
-                convertNameToId(elem);
-                this.buildFunctionTypeFingerprint(elem, parsedQuery.typeFingerprint);
-            }
-
             if (parsedQuery.foundElems === 1 && !parsedQuery.hasReturnArrow) {
                 const elem = parsedQuery.elems[0];
                 // use arrow functions to preserve `this`.
+                // @ts-expect-error
                 const handleNameSearch = id => {
                     const row = this.searchIndex[id];
                     if (!typePassesFilter(elem.typeFilter, row.ty) ||
@@ -4094,6 +4508,7 @@ class DocSearch {
 
                     let pathDist = 0;
                     if (elem.fullPath.length > 1) {
+                        // @ts-expect-error
                         pathDist = checkPath(elem.pathWithoutLast, row);
                         if (pathDist === null) {
                             return;
@@ -4102,11 +4517,13 @@ class DocSearch {
 
                     if (parsedQuery.literalSearch) {
                         if (row.word === elem.pathLast) {
+                            // @ts-expect-error
                             addIntoResults(results_others, row.id, id, 0, 0, pathDist);
                         }
                     } else {
                         addIntoResults(
                             results_others,
+                            // @ts-expect-error
                             row.id,
                             id,
                             row.normalizedName.indexOf(elem.normalizedPathLast),
@@ -4147,23 +4564,31 @@ class DocSearch {
                         const returned = row.type && row.type.output
                             && checkIfInList(row.type.output, elem, row.type.where_clause, null, 0);
                         if (in_args) {
+                            // @ts-expect-error
                             results_in_args.max_dist = Math.max(
+                                // @ts-expect-error
                                 results_in_args.max_dist || 0,
                                 tfpDist,
                             );
                             const maxDist = results_in_args.size < MAX_RESULTS ?
                                 (tfpDist + 1) :
+                                // @ts-expect-error
                                 results_in_args.max_dist;
+                            // @ts-expect-error
                             addIntoResults(results_in_args, row.id, i, -1, tfpDist, 0, maxDist);
                         }
                         if (returned) {
+                            // @ts-expect-error
                             results_returned.max_dist = Math.max(
+                                // @ts-expect-error
                                 results_returned.max_dist || 0,
                                 tfpDist,
                             );
                             const maxDist = results_returned.size < MAX_RESULTS ?
                                 (tfpDist + 1) :
+                                // @ts-expect-error
                                 results_returned.max_dist;
+                            // @ts-expect-error
                             addIntoResults(results_returned, row.id, i, -1, tfpDist, 0, maxDist);
                         }
                     }
@@ -4173,14 +4598,17 @@ class DocSearch {
                 // types with generic parameters go last.
                 // That's because of the way unification is structured: it eats off
                 // the end, and hits a fast path if the last item is a simple atom.
+                // @ts-expect-error
                 const sortQ = (a, b) => {
                     const ag = a.generics.length === 0 && a.bindings.size === 0;
                     const bg = b.generics.length === 0 && b.bindings.size === 0;
                     if (ag !== bg) {
+                        // @ts-expect-error
                         return ag - bg;
                     }
                     const ai = a.id > 0;
                     const bi = b.id > 0;
+                    // @ts-expect-error
                     return ai - bi;
                 };
                 parsedQuery.elems.sort(sortQ);
@@ -4197,8 +4625,11 @@ class DocSearch {
 
         const isType = parsedQuery.foundElems !== 1 || parsedQuery.hasReturnArrow;
         const [sorted_in_args, sorted_returned, sorted_others] = await Promise.all([
+            // @ts-expect-error
             sortResults(results_in_args, "elems", currentCrate),
+            // @ts-expect-error
             sortResults(results_returned, "returned", currentCrate),
+            // @ts-expect-error
             sortResults(results_others, (isType ? "query" : null), currentCrate),
         ]);
         const ret = createQueryResults(
@@ -4210,11 +4641,14 @@ class DocSearch {
             filterCrates, currentCrate);
         await Promise.all([ret.others, ret.returned, ret.in_args].map(async list => {
             const descs = await Promise.all(list.map(result => {
+                // @ts-expect-error
                 return this.searchIndexEmptyDesc.get(result.crate).contains(result.bitIndex) ?
                     "" :
+                    // @ts-expect-error
                     this.searchState.loadDesc(result);
             }));
             for (const [i, result] of list.entries()) {
+                // @ts-expect-error
                 result.desc = descs[i];
             }
         }));
@@ -4229,7 +4663,9 @@ class DocSearch {
 
 // ==================== Core search logic end ====================
 
+/** @type {Map<string, rustdoc.RawSearchIndexCrate>} */
 let rawSearchIndex;
+// @ts-expect-error
 let docSearch;
 const longItemTypes = [
     "keyword",
@@ -4259,13 +4695,16 @@ const longItemTypes = [
     "derive macro",
     "trait alias",
 ];
+// @ts-expect-error
 let currentResults;
 
 // In the search display, allows to switch between tabs.
+// @ts-expect-error
 function printTab(nb) {
     let iter = 0;
     let foundCurrentTab = false;
     let foundCurrentResultSet = false;
+    // @ts-expect-error
     onEachLazy(document.getElementById("search-tabs").childNodes, elem => {
         if (nb === iter) {
             addClass(elem, "selected");
@@ -4277,6 +4716,7 @@ function printTab(nb) {
     });
     const isTypeSearch = (nb > 0 || iter === 1);
     iter = 0;
+    // @ts-expect-error
     onEachLazy(document.getElementById("results").childNodes, elem => {
         if (nb === iter) {
             addClass(elem, "active");
@@ -4287,12 +4727,15 @@ function printTab(nb) {
         iter += 1;
     });
     if (foundCurrentTab && foundCurrentResultSet) {
+        // @ts-expect-error
         searchState.currentTab = nb;
         // Corrections only kick in on type-based searches.
         const correctionsElem = document.getElementsByClassName("search-corrections");
         if (isTypeSearch) {
+            // @ts-expect-error
             removeClass(correctionsElem[0], "hidden");
         } else {
+            // @ts-expect-error
             addClass(correctionsElem[0], "hidden");
         }
     } else if (nb !== 0) {
@@ -4326,16 +4769,22 @@ function getFilterCrates() {
     const elem = document.getElementById("crate-search");
 
     if (elem &&
+        // @ts-expect-error
         elem.value !== "all crates" &&
+        // @ts-expect-error
         window.searchIndex.has(elem.value)
     ) {
+        // @ts-expect-error
         return elem.value;
     }
     return null;
 }
 
+// @ts-expect-error
 function nextTab(direction) {
+    // @ts-expect-error
     const next = (searchState.currentTab + direction + 3) % searchState.focusedByTab.length;
+    // @ts-expect-error
     searchState.focusedByTab[searchState.currentTab] = document.activeElement;
     printTab(next);
     focusSearchResult();
@@ -4344,9 +4793,12 @@ function nextTab(direction) {
 // Focus the first search result on the active tab, or the result that
 // was focused last time this tab was active.
 function focusSearchResult() {
+    // @ts-expect-error
     const target = searchState.focusedByTab[searchState.currentTab] ||
         document.querySelectorAll(".search-results.active a").item(0) ||
+        // @ts-expect-error
         document.querySelectorAll("#search-tabs button").item(searchState.currentTab);
+    // @ts-expect-error
     searchState.focusedByTab[searchState.currentTab] = null;
     if (target) {
         target.focus();
@@ -4356,9 +4808,8 @@ function focusSearchResult() {
 /**
  * Render a set of search results for a single tab.
  * @param {Array<?>}    array   - The search results for this tab
- * @param {ParsedQuery} query
+ * @param {rustdoc.ParsedQuery<rustdoc.QueryElement>} query
  * @param {boolean}     display - True if this is the active tab
- * @param {"sig"|"elems"|"returned"|null} typeInfo
  */
 async function addTab(array, query, display) {
     const extraClass = display ? " active" : "";
@@ -4405,6 +4856,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
             if (item.displayTypeSignature) {
                 const {type, mappedNames, whereClause} = await item.displayTypeSignature;
                 const displayType = document.createElement("div");
+                // @ts-expect-error
                 type.forEach((value, index) => {
                     if (index % 2 !== 0) {
                         const highlight = document.createElement("strong");
@@ -4445,6 +4897,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
                         const line = document.createElement("div");
                         line.className = "where";
                         line.appendChild(document.createTextNode(`    ${name}: `));
+                        // @ts-expect-error
                         innerType.forEach((value, index) => {
                             if (index % 2 !== 0) {
                                 const highlight = document.createElement("strong");
@@ -4488,6 +4941,7 @@ ${item.displayPath}<span class="${type}">${name}</span>\
     return output;
 }
 
+// @ts-expect-error
 function makeTabHeader(tabNb, text, nbElems) {
     // https://blog.horizon-eda.org/misc/2020/02/19/ui.html
     //
@@ -4497,6 +4951,7 @@ function makeTabHeader(tabNb, text, nbElems) {
     const fmtNbElems =
         nbElems < 10  ? `\u{2007}(${nbElems})\u{2007}\u{2007}` :
         nbElems < 100 ? `\u{2007}(${nbElems})\u{2007}` : `\u{2007}(${nbElems})`;
+    // @ts-expect-error
     if (searchState.currentTab === tabNb) {
         return "<button class=\"selected\">" + text +
             "<span class=\"count\">" + fmtNbElems + "</span></button>";
@@ -4505,11 +4960,12 @@ function makeTabHeader(tabNb, text, nbElems) {
 }
 
 /**
- * @param {ResultsTable} results
+ * @param {rustdoc.ResultsTable} results
  * @param {boolean} go_to_first
  * @param {string} filterCrates
  */
 async function showResults(results, go_to_first, filterCrates) {
+    // @ts-expect-error
     const search = searchState.outputElement();
     if (go_to_first || (results.others.length === 1
         && getSettingValue("go-to-only-result") === "true")
@@ -4527,6 +4983,7 @@ async function showResults(results, go_to_first, filterCrates) {
         // will be used, starting search again since the search input is not empty, leading you
         // back to the previous page again.
         window.onunload = () => { };
+        // @ts-expect-error
         searchState.removeQueryParameters();
         const elem = document.createElement("a");
         elem.href = results.others[0].href;
@@ -4537,6 +4994,7 @@ async function showResults(results, go_to_first, filterCrates) {
         return;
     }
     if (results.query === undefined) {
+        // @ts-expect-error
         results.query = DocSearch.parseQuery(searchState.input.value);
     }
 
@@ -4545,6 +5003,7 @@ async function showResults(results, go_to_first, filterCrates) {
     // Navigate to the relevant tab if the current tab is empty, like in case users search
     // for "-> String". If they had selected another tab previously, they have to click on
     // it again.
+    // @ts-expect-error
     let currentTab = searchState.currentTab;
     if ((currentTab === 0 && results.others.length === 0) ||
         (currentTab === 1 && results.in_args.length === 0) ||
@@ -4572,6 +5031,7 @@ async function showResults(results, go_to_first, filterCrates) {
         <h1 class="search-results-title">Results</h1>${crates}</div>`;
     if (results.query.error !== null) {
         const error = results.query.error;
+        // @ts-expect-error
         error.forEach((value, index) => {
             value = value.split("<").join("&lt;").split(">").join("&gt;");
             if (index % 2 !== 0) {
@@ -4632,7 +5092,9 @@ async function showResults(results, go_to_first, filterCrates) {
     resultsElem.appendChild(ret_returned);
 
     search.innerHTML = output;
+    // @ts-expect-error
     if (searchState.rustdocToolbar) {
+        // @ts-expect-error
         search.querySelector(".main-heading").appendChild(searchState.rustdocToolbar);
     }
     const crateSearch = document.getElementById("crate-search");
@@ -4641,23 +5103,30 @@ async function showResults(results, go_to_first, filterCrates) {
     }
     search.appendChild(resultsElem);
     // Reset focused elements.
+    // @ts-expect-error
     searchState.showResults(search);
+    // @ts-expect-error
     const elems = document.getElementById("search-tabs").childNodes;
+    // @ts-expect-error
     searchState.focusedByTab = [];
     let i = 0;
     for (const elem of elems) {
         const j = i;
+        // @ts-expect-error
         elem.onclick = () => printTab(j);
+        // @ts-expect-error
         searchState.focusedByTab.push(null);
         i += 1;
     }
     printTab(currentTab);
 }
 
+// @ts-expect-error
 function updateSearchHistory(url) {
     if (!browserSupportsHistoryApi()) {
         return;
     }
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
     if (!history.state && !params.search) {
         history.pushState(null, "", url);
@@ -4672,9 +5141,11 @@ function updateSearchHistory(url) {
  * @param {boolean} [forced]
  */
 async function search(forced) {
+    // @ts-expect-error
     const query = DocSearch.parseQuery(searchState.input.value.trim());
     let filterCrates = getFilterCrates();
 
+    // @ts-expect-error
     if (!forced && query.userQuery === currentResults) {
         if (query.userQuery.length > 0) {
             putBackSearch();
@@ -4682,8 +5153,10 @@ async function search(forced) {
         return;
     }
 
+    // @ts-expect-error
     searchState.setLoadingSearch();
 
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
 
     // In case we have no information about the saved crate and there is a URL query parameter,
@@ -4693,6 +5166,7 @@ async function search(forced) {
     }
 
     // Update document title to maintain a meaningful browser history
+    // @ts-expect-error
     searchState.title = "\"" + query.userQuery + "\" Search - Rust";
 
     // Because searching is incremental by character, only the most
@@ -4700,8 +5174,10 @@ async function search(forced) {
     updateSearchHistory(buildUrl(query.userQuery, filterCrates));
 
     await showResults(
+        // @ts-expect-error
         await docSearch.execQuery(query, filterCrates, window.currentCrate),
         params.go_to_first,
+        // @ts-expect-error
         filterCrates);
 }
 
@@ -4710,62 +5186,83 @@ async function search(forced) {
  * @param {Event} [e] - The event that triggered this call, if any
  */
 function onSearchSubmit(e) {
+    // @ts-expect-error
     e.preventDefault();
+    // @ts-expect-error
     searchState.clearInputTimeout();
     search();
 }
 
 function putBackSearch() {
+    // @ts-expect-error
     const search_input = searchState.input;
+    // @ts-expect-error
     if (!searchState.input) {
         return;
     }
+    // @ts-expect-error
     if (search_input.value !== "" && !searchState.isDisplayed()) {
+        // @ts-expect-error
         searchState.showResults();
         if (browserSupportsHistoryApi()) {
             history.replaceState(null, "",
                 buildUrl(search_input.value, getFilterCrates()));
         }
+        // @ts-expect-error
         document.title = searchState.title;
     }
 }
 
 function registerSearchEvents() {
+    // @ts-expect-error
     const params = searchState.getQueryStringParams();
 
     // Populate search bar with query string search term when provided,
     // but only if the input bar is empty. This avoid the obnoxious issue
     // where you start trying to do a search, and the index loads, and
     // suddenly your search is gone!
+    // @ts-expect-error
     if (searchState.input.value === "") {
+        // @ts-expect-error
         searchState.input.value = params.search || "";
     }
 
     const searchAfter500ms = () => {
+        // @ts-expect-error
         searchState.clearInputTimeout();
+        // @ts-expect-error
         if (searchState.input.value.length === 0) {
+            // @ts-expect-error
             searchState.hideResults();
         } else {
+            // @ts-expect-error
             searchState.timeout = setTimeout(search, 500);
         }
     };
+    // @ts-expect-error
     searchState.input.onkeyup = searchAfter500ms;
+    // @ts-expect-error
     searchState.input.oninput = searchAfter500ms;
+    // @ts-expect-error
     document.getElementsByClassName("search-form")[0].onsubmit = onSearchSubmit;
+    // @ts-expect-error
     searchState.input.onchange = e => {
         if (e.target !== document.activeElement) {
             // To prevent doing anything when it's from a blur event.
             return;
         }
         // Do NOT e.preventDefault() here. It will prevent pasting.
+        // @ts-expect-error
         searchState.clearInputTimeout();
         // zero-timeout necessary here because at the time of event handler execution the
         // pasted content is not in the input field yet. Shouldn’t make any difference for
         // change, though.
         setTimeout(search, 0);
     };
+    // @ts-expect-error
     searchState.input.onpaste = searchState.input.onchange;
 
+    // @ts-expect-error
     searchState.outputElement().addEventListener("keydown", e => {
         // We only handle unmodified keystrokes here. We don't want to interfere with,
         // for instance, alt-left and alt-right for history navigation.
@@ -4775,18 +5272,24 @@ function registerSearchEvents() {
         // up and down arrow select next/previous search result, or the
         // search box if we're already at the top.
         if (e.which === 38) { // up
+            // @ts-expect-error
             const previous = document.activeElement.previousElementSibling;
             if (previous) {
+                // @ts-expect-error
                 previous.focus();
             } else {
+                // @ts-expect-error
                 searchState.focus();
             }
             e.preventDefault();
         } else if (e.which === 40) { // down
+            // @ts-expect-error
             const next = document.activeElement.nextElementSibling;
             if (next) {
+                // @ts-expect-error
                 next.focus();
             }
+            // @ts-expect-error
             const rect = document.activeElement.getBoundingClientRect();
             if (window.innerHeight - rect.bottom < rect.height) {
                 window.scrollBy(0, rect.height);
@@ -4801,6 +5304,7 @@ function registerSearchEvents() {
         }
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("keydown", e => {
         if (e.which === 40) { // down
             focusSearchResult();
@@ -4808,11 +5312,14 @@ function registerSearchEvents() {
         }
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("focus", () => {
         putBackSearch();
     });
 
+    // @ts-expect-error
     searchState.input.addEventListener("blur", () => {
+        // @ts-expect-error
         searchState.input.placeholder = searchState.input.origPlaceholder;
     });
 
@@ -4823,6 +5330,7 @@ function registerSearchEvents() {
         const previousTitle = document.title;
 
         window.addEventListener("popstate", e => {
+            // @ts-expect-error
             const params = searchState.getQueryStringParams();
             // Revert to the previous title manually since the History
             // API ignores the title parameter.
@@ -4836,6 +5344,7 @@ function registerSearchEvents() {
             // nothing there, which lets you really go back to a
             // previous state with nothing in the bar.
             if (params.search && params.search.length > 0) {
+                // @ts-expect-error
                 searchState.input.value = params.search;
                 // Some browsers fire "onpopstate" for every page load
                 // (Chrome), while others fire the event only when actually
@@ -4845,9 +5354,11 @@ function registerSearchEvents() {
                 e.preventDefault();
                 search();
             } else {
+                // @ts-expect-error
                 searchState.input.value = "";
                 // When browsing back from search results the main page
                 // visibility must be reset.
+                // @ts-expect-error
                 searchState.hideResults();
             }
         });
@@ -4860,17 +5371,22 @@ function registerSearchEvents() {
     // that try to sync state between the URL and the search input. To work around it,
     // do a small amount of re-init on page show.
     window.onpageshow = () => {
+        // @ts-expect-error
         const qSearch = searchState.getQueryStringParams().search;
+        // @ts-expect-error
         if (searchState.input.value === "" && qSearch) {
+            // @ts-expect-error
             searchState.input.value = qSearch;
         }
         search();
     };
 }
 
+// @ts-expect-error
 function updateCrate(ev) {
     if (ev.target.value === "all crates") {
         // If we don't remove it from the URL, it'll be picked up again by the search.
+        // @ts-expect-error
         const query = searchState.input.value.trim();
         updateSearchHistory(buildUrl(query, null));
     }
@@ -4881,9 +5397,11 @@ function updateCrate(ev) {
     search(true);
 }
 
+// @ts-expect-error
 function initSearch(searchIndx) {
     rawSearchIndex = searchIndx;
     if (typeof window !== "undefined") {
+        // @ts-expect-error
         docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
         registerSearchEvents();
         // If there's a search term in the URL, execute the search now.
@@ -4891,6 +5409,7 @@ function initSearch(searchIndx) {
             search();
         }
     } else if (typeof exports !== "undefined") {
+        // @ts-expect-error
         docSearch = new DocSearch(rawSearchIndex, ROOT_PATH, searchState);
         exports.docSearch = docSearch;
         exports.parseQuery = DocSearch.parseQuery;
@@ -4902,8 +5421,11 @@ if (typeof exports !== "undefined") {
 }
 
 if (typeof window !== "undefined") {
+    // @ts-expect-error
     window.initSearch = initSearch;
+    // @ts-expect-error
     if (window.searchIndex !== undefined) {
+        // @ts-expect-error
         initSearch(window.searchIndex);
     }
 } else {
@@ -4918,19 +5440,23 @@ if (typeof window !== "undefined") {
 // https://fossies.org/linux/lucene/lucene/core/src/java/org/apache/lucene/util/automaton/
 //   LevenshteinAutomata.java
 class ParametricDescription {
+    // @ts-expect-error
     constructor(w, n, minErrors) {
         this.w = w;
         this.n = n;
         this.minErrors = minErrors;
     }
+    // @ts-expect-error
     isAccept(absState) {
         const state = Math.floor(absState / (this.w + 1));
         const offset = absState % (this.w + 1);
         return this.w - offset + this.minErrors[state] <= this.n;
     }
+    // @ts-expect-error
     getPosition(absState) {
         return absState % (this.w + 1);
     }
+    // @ts-expect-error
     getVector(name, charCode, pos, end) {
         let vector = 0;
         for (let i = pos; i < end; i += 1) {
@@ -4941,6 +5467,7 @@ class ParametricDescription {
         }
         return vector;
     }
+    // @ts-expect-error
     unpack(data, index, bitsPerValue) {
         const bitLoc = (bitsPerValue * index);
         const dataLoc = bitLoc >> 5;
diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js
index 183663b94fc..d7b0e4b4f54 100644
--- a/src/librustdoc/html/static/js/settings.js
+++ b/src/librustdoc/html/static/js/settings.js
@@ -3,6 +3,9 @@
 /* global addClass, removeClass, onEach, onEachLazy */
 /* global MAIN_ID, getVar, getSettingsButton, getHelpButton */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
diff --git a/src/librustdoc/html/static/js/src-script.js b/src/librustdoc/html/static/js/src-script.js
index 3003f4c1503..8f712f4c20c 100644
--- a/src/librustdoc/html/static/js/src-script.js
+++ b/src/librustdoc/html/static/js/src-script.js
@@ -5,6 +5,9 @@
 /* global addClass, onEachLazy, removeClass, browserSupportsHistoryApi */
 /* global updateLocalStorage, getVar */
 
+// Eventually fix this.
+// @ts-nocheck
+
 "use strict";
 
 (function() {
diff --git a/src/librustdoc/html/static/js/storage.js b/src/librustdoc/html/static/js/storage.js
index d77804d045e..4770ccc1279 100644
--- a/src/librustdoc/html/static/js/storage.js
+++ b/src/librustdoc/html/static/js/storage.js
@@ -5,15 +5,28 @@
 // the page, so we don't see major layout changes during the load of the page.
 "use strict";
 
+/**
+ * @import * as rustdoc from "./rustdoc.d.ts";
+ */
+
 const builtinThemes = ["light", "dark", "ayu"];
 const darkThemes = ["dark", "ayu"];
-window.currentTheme = document.getElementById("themeStyle");
+window.currentTheme = (function() {
+    const currentTheme = document.getElementById("themeStyle");
+    return currentTheme instanceof HTMLLinkElement ? currentTheme : null;
+})();
 
 const settingsDataset = (function() {
     const settingsElement = document.getElementById("default-settings");
     return settingsElement && settingsElement.dataset ? settingsElement.dataset : null;
 })();
 
+/**
+ * Get a configuration value. If it's not set, get the default.
+ *
+ * @param {string} settingName
+ * @returns
+ */
 function getSettingValue(settingName) {
     const current = getCurrentValue(settingName);
     if (current === null && settingsDataset !== null) {
@@ -29,17 +42,39 @@ function getSettingValue(settingName) {
 
 const localStoredTheme = getSettingValue("theme");
 
+/**
+ * Check if a DOM Element has the given class set.
+ * If `elem` is null, returns false.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ * @returns {boolean}
+ */
 // eslint-disable-next-line no-unused-vars
 function hasClass(elem, className) {
-    return elem && elem.classList && elem.classList.contains(className);
+    return !!elem && !!elem.classList && elem.classList.contains(className);
 }
 
+/**
+ * Add a class to a DOM Element. If `elem` is null,
+ * does nothing. This function is idempotent.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ */
 function addClass(elem, className) {
     if (elem && elem.classList) {
         elem.classList.add(className);
     }
 }
 
+/**
+ * Remove a class from a DOM Element. If `elem` is null,
+ * does nothing. This function is idempotent.
+ *
+ * @param {HTMLElement|null} elem
+ * @param {string} className
+ */
 // eslint-disable-next-line no-unused-vars
 function removeClass(elem, className) {
     if (elem && elem.classList) {
@@ -49,8 +84,8 @@ function removeClass(elem, className) {
 
 /**
  * Run a callback for every element of an Array.
- * @param {Array<?>}    arr        - The array to iterate over
- * @param {function(?)} func       - The callback
+ * @param {Array<?>}                       arr  - The array to iterate over
+ * @param {function(?): boolean|undefined} func - The callback
  */
 function onEach(arr, func) {
     for (const elem of arr) {
@@ -67,8 +102,8 @@ function onEach(arr, func) {
  * or a "live" NodeList while modifying it can be very slow.
  * https://developer.mozilla.org/en-US/docs/Web/API/HTMLCollection
  * https://developer.mozilla.org/en-US/docs/Web/API/NodeList
- * @param {NodeList<?>|HTMLCollection<?>} lazyArray  - An array to iterate over
- * @param {function(?)}                   func       - The callback
+ * @param {NodeList|HTMLCollection} lazyArray  - An array to iterate over
+ * @param {function(?): boolean}    func       - The callback
  */
 // eslint-disable-next-line no-unused-vars
 function onEachLazy(lazyArray, func) {
@@ -77,6 +112,15 @@ function onEachLazy(lazyArray, func) {
         func);
 }
 
+/**
+ * Set a configuration value. This uses localstorage,
+ * with a `rustdoc-` prefix, to avoid clashing with other
+ * web apps that may be running in the same domain (for example, mdBook).
+ * If localStorage is disabled, this function does nothing.
+ *
+ * @param {string} name
+ * @param {string} value
+ */
 function updateLocalStorage(name, value) {
     try {
         window.localStorage.setItem("rustdoc-" + name, value);
@@ -85,6 +129,15 @@ function updateLocalStorage(name, value) {
     }
 }
 
+/**
+ * Get a configuration value. If localStorage is disabled,
+ * this function returns null. If the setting was never
+ * changed by the user, it also returns null; if you want to
+ * be able to use a default value, call `getSettingValue` instead.
+ *
+ * @param {string} name
+ * @returns {string|null}
+ */
 function getCurrentValue(name) {
     try {
         return window.localStorage.getItem("rustdoc-" + name);
@@ -93,19 +146,29 @@ function getCurrentValue(name) {
     }
 }
 
-// Get a value from the rustdoc-vars div, which is used to convey data from
-// Rust to the JS. If there is no such element, return null.
-const getVar = (function getVar(name) {
+/**
+ * Get a value from the rustdoc-vars div, which is used to convey data from
+ * Rust to the JS. If there is no such element, return null.
+ *
+ * @param {string} name
+ * @returns {string|null}
+ */
+function getVar(name) {
     const el = document.querySelector("head > meta[name='rustdoc-vars']");
-    return el ? el.attributes["data-" + name].value : null;
-});
+    return el ? el.getAttribute("data-" + name) : null;
+}
 
+/**
+ * Change the current theme.
+ * @param {string|null} newThemeName
+ * @param {boolean} saveTheme
+ */
 function switchTheme(newThemeName, saveTheme) {
-    const themeNames = getVar("themes").split(",").filter(t => t);
+    const themeNames = (getVar("themes") || "").split(",").filter(t => t);
     themeNames.push(...builtinThemes);
 
     // Ensure that the new theme name is among the defined themes
-    if (themeNames.indexOf(newThemeName) === -1) {
+    if (newThemeName === null || themeNames.indexOf(newThemeName) === -1) {
         return;
     }
 
@@ -118,7 +181,7 @@ function switchTheme(newThemeName, saveTheme) {
     document.documentElement.setAttribute("data-theme", newThemeName);
 
     if (builtinThemes.indexOf(newThemeName) !== -1) {
-        if (window.currentTheme) {
+        if (window.currentTheme && window.currentTheme.parentNode) {
             window.currentTheme.parentNode.removeChild(window.currentTheme);
             window.currentTheme = null;
         }
@@ -130,7 +193,10 @@ function switchTheme(newThemeName, saveTheme) {
             // rendering, but if we are done, it would blank the page.
             if (document.readyState === "loading") {
                 document.write(`<link rel="stylesheet" id="themeStyle" href="${newHref}">`);
-                window.currentTheme = document.getElementById("themeStyle");
+                window.currentTheme = (function() {
+                    const currentTheme = document.getElementById("themeStyle");
+                    return currentTheme instanceof HTMLLinkElement ? currentTheme : null;
+                })();
             } else {
                 window.currentTheme = document.createElement("link");
                 window.currentTheme.rel = "stylesheet";
@@ -179,11 +245,13 @@ const updateTheme = (function() {
     return updateTheme;
 })();
 
+// @ts-ignore
 if (getSettingValue("use-system-theme") !== "false" && window.matchMedia) {
     // update the preferred dark theme if the user is already using a dark theme
     // See https://github.com/rust-lang/rust/pull/77809#issuecomment-707875732
     if (getSettingValue("use-system-theme") === null
         && getSettingValue("preferred-dark-theme") === null
+        && localStoredTheme !== null
         && darkThemes.indexOf(localStoredTheme) >= 0) {
         updateLocalStorage("preferred-dark-theme", localStoredTheme);
     }
diff --git a/src/librustdoc/html/static/js/tsconfig.json b/src/librustdoc/html/static/js/tsconfig.json
new file mode 100644
index 00000000000..b81099bb9df
--- /dev/null
+++ b/src/librustdoc/html/static/js/tsconfig.json
@@ -0,0 +1,15 @@
+{
+  "compilerOptions": {
+    "target": "es2023",
+    "module": "esnext",
+    "rootDir": "./",
+    "allowJs": true,
+    "checkJs": true,
+    "noEmit": true,
+    "strict": true,
+    "skipLibCheck": true
+  },
+  "typeAcquisition": {
+    "include": ["./rustdoc.d.ts"]
+  }
+}
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index 8a5cf7f56d5..7ca2c953699 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -56,7 +56,7 @@ fn unary_pattern(pat: &Pat<'_>) -> bool {
         PatKind::Struct(_, a, etc) => !etc && a.iter().all(|x| unary_pattern(x.pat)),
         PatKind::Tuple(a, etc) | PatKind::TupleStruct(_, a, etc) => etc.as_opt_usize().is_none() && array_rec(a),
         PatKind::Ref(x, _) | PatKind::Box(x) | PatKind::Deref(x) | PatKind::Guard(x, _) => unary_pattern(x),
-        PatKind::Path(_) | PatKind::Expr(_) => true,
+        PatKind::Expr(_) => true,
     }
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index bb2dc9995df..3ccfa51ab70 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -79,7 +79,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend {
             && let Some(future_trait) = cx.tcx.lang_items().future_trait()
             && let Some(send_trait) = cx.tcx.get_diagnostic_item(sym::Send)
         {
-            let preds = cx.tcx.explicit_item_super_predicates(def_id);
+            let preds = cx.tcx.explicit_item_self_bounds(def_id);
             let is_future = preds.iter_instantiated_copied(cx.tcx, args).any(|(p, _)| {
                 p.as_trait_clause()
                     .is_some_and(|trait_pred| trait_pred.skip_binder().trait_ref.def_id == future_trait)
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index 8503dde3fb6..274785061b3 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -7,7 +7,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_lint_allowed, is_never_expr, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
 use rustc_data_structures::fx::{FxHashMap, FxHashSet};
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatKind, QPath, Stmt, StmtKind};
+use rustc_hir::{Expr, ExprKind, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath, Stmt, StmtKind};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::lint::in_external_macro;
 
@@ -292,7 +292,12 @@ fn pat_allowed_for_else(cx: &LateContext<'_>, pat: &'_ Pat<'_>, check_types: boo
         // Only do the check if the type is "spelled out" in the pattern
         if !matches!(
             pat.kind,
-            PatKind::Struct(..) | PatKind::TupleStruct(..) | PatKind::Path(..)
+            PatKind::Struct(..)
+                | PatKind::TupleStruct(..)
+                | PatKind::Expr(PatExpr {
+                    kind: PatExprKind::Path(..),
+                    ..
+                },)
         ) {
             return;
         }
diff --git a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
index 8f8390b6f3f..7b95399c907 100644
--- a/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_unwrap_or_default.rs
@@ -1,6 +1,6 @@
 use rustc_errors::Applicability;
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatKind, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, HirId, LangItem, MatchSource, Pat, PatExpr, PatExprKind, PatKind, QPath};
 use rustc_lint::{LateContext, LateLintPass, LintContext};
 use rustc_middle::ty::GenericArgKind;
 use rustc_session::declare_lint_pass;
@@ -68,7 +68,7 @@ fn get_some<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<HirId> {
 }
 
 fn get_none<'tcx>(cx: &LateContext<'tcx>, arm: &Arm<'tcx>) -> Option<&'tcx Expr<'tcx>> {
-    if let PatKind::Path(QPath::Resolved(_, path)) = arm.pat.kind
+    if let PatKind::Expr(PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. }) = arm.pat.kind
         && let Some(def_id) = path.res.opt_def_id()
         // Since it comes from a pattern binding, we need to get the parent to actually match
         // against it.
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 99a7b8c74be..97e8423695d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -8,7 +8,7 @@ use clippy_utils::{
 };
 use rustc_errors::MultiSpan;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, Expr, HirId, Pat, PatKind};
+use rustc_hir::{Arm, Expr, HirId, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_span::Span;
 
@@ -119,7 +119,11 @@ fn arm_is_wild_like(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     }
     match arm.pat.kind {
         PatKind::Binding(..) | PatKind::Wild => true,
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         _ => false,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
index b1a555b91d1..3deaaf96c1e 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_ok_err.rs
@@ -6,7 +6,7 @@ use rustc_ast::BindingMode;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Pat, PatKind, Path, QPath};
+use rustc_hir::{Arm, Expr, ExprKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty::Ty;
 use rustc_span::symbol::Ident;
@@ -60,7 +60,16 @@ pub(crate) fn check_match(cx: &LateContext<'_>, expr: &Expr<'_>, scrutinee: &Exp
 /// accepted.
 fn is_variant_or_wildcard(cx: &LateContext<'_>, pat: &Pat<'_>, can_be_wild: bool, must_match_err: bool) -> bool {
     match pat.kind {
-        PatKind::Wild | PatKind::Path(..) | PatKind::Binding(_, _, _, None) if can_be_wild => true,
+        PatKind::Wild
+        | PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(_),
+            ..
+        })
+        | PatKind::Binding(_, _, _, None)
+            if can_be_wild =>
+        {
+            true
+        },
         PatKind::TupleStruct(qpath, ..) => {
             is_res_lang_ctor(cx, cx.qpath_res(&qpath, pat.hir_id), ResultErr) == must_match_err
         },
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
index 59d37520011..b69294d567d 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_unwrap_or.rs
@@ -7,7 +7,7 @@ use clippy_utils::{is_res_lang_ctor, path_to_local_id, peel_blocks, sugg};
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, ResultErr};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, Pat, PatKind};
+use rustc_hir::{Arm, Expr, Pat, PatExpr, PatExprKind, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::Ty;
 use rustc_span::sym;
@@ -89,7 +89,11 @@ fn applicable_or_arm<'a>(cx: &LateContext<'_>, arms: &'a [Arm<'a>]) -> Option<(&
     if arms.len() == 2
         && arms.iter().all(|arm| arm.guard.is_none())
         && let Some((idx, or_arm)) = arms.iter().enumerate().find(|(_, arm)| match arm.pat.kind {
-            PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+            PatKind::Expr(PatExpr {
+                hir_id,
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
             PatKind::TupleStruct(ref qpath, [pat], _) => {
                 matches!(pat.kind, PatKind::Wild)
                     && is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 0b57740064c..2ad55d9bf1f 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -11,7 +11,7 @@ use rustc_ast::util::parser::ExprPrecedence;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome};
 use rustc_hir::def::Res;
-use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatKind, Path, QPath};
+use rustc_hir::{BindingMode, Expr, ExprKind, HirId, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath};
 use rustc_lint::LateContext;
 use rustc_span::{SyntaxContext, sym};
 
@@ -256,9 +256,11 @@ pub(super) fn try_parse_pattern<'tcx>(
         match pat.kind {
             PatKind::Wild => Some(OptionPat::Wild),
             PatKind::Ref(pat, _) => f(cx, pat, ref_count + 1, ctxt),
-            PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionNone) => {
-                Some(OptionPat::None)
-            },
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                hir_id,
+                ..
+            }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone) => Some(OptionPat::None),
             PatKind::TupleStruct(ref qpath, [pattern], _)
                 if is_res_lang_ctor(cx, cx.qpath_res(qpath, pat.hir_id), OptionSome) && pat.span.ctxt() == ctxt =>
             {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
index 6c123649afc..b1889d26c93 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_as_ref.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_with_applicability;
 use clippy_utils::{is_res_lang_ctor, path_res, peel_blocks};
 use rustc_errors::Applicability;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatKind, QPath};
+use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, LangItem, Mutability, PatExpr, PatExprKind, PatKind, QPath};
 use rustc_lint::LateContext;
 use rustc_middle::ty;
 
@@ -59,7 +59,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
 fn is_none_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     matches!(
         arm.pat.kind,
-        PatKind::Path(ref qpath) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
+        PatKind::Expr(PatExpr { kind: PatExprKind::Path(qpath), .. }) if is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), LangItem::OptionNone)
     )
 }
 
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
index 28e05c273d5..41e4c75f843 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs
@@ -7,7 +7,7 @@ use rustc_arena::DroplessArena;
 use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::def_id::DefId;
-use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExprKind, PatKind, RangeEnd};
+use rustc_hir::{Arm, Expr, HirId, HirIdMap, HirIdMapEntry, HirIdSet, Pat, PatExpr, PatExprKind, PatKind, RangeEnd};
 use rustc_lint::builtin::NON_EXHAUSTIVE_OMITTED_PATTERNS;
 use rustc_lint::{LateContext, LintContext};
 use rustc_middle::ty;
@@ -292,7 +292,11 @@ impl<'a> NormalizedPat<'a> {
                 Self::Tuple(var_id, pats)
             },
             PatKind::Or(pats) => Self::Or(arena.alloc_from_iter(pats.iter().map(|pat| Self::from_pat(cx, arena, pat)))),
-            PatKind::Path(ref path) => Self::Path(cx.qpath_res(path, pat.hir_id).opt_def_id()),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path),
+                hir_id,
+                ..
+            }) => Self::Path(cx.qpath_res(path, *hir_id).opt_def_id()),
             PatKind::Tuple(pats, wild_idx) => {
                 let field_count = match cx.typeck_results().pat_ty(pat).kind() {
                     ty::Tuple(subs) => subs.len(),
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
index 59565560089..11b588b3355 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_enum.rs
@@ -3,7 +3,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
 use clippy_utils::{is_refutable, peel_hir_pat_refs, recurse_or_patterns};
 use rustc_errors::Applicability;
 use rustc_hir::def::{CtorKind, DefKind, Res};
-use rustc_hir::{Arm, Expr, PatKind, PathSegment, QPath, Ty, TyKind};
+use rustc_hir::{Arm, Expr, PatExpr, PatExprKind, PatKind, PathSegment, QPath, Ty, TyKind};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, VariantDef};
 use rustc_span::sym;
@@ -60,8 +60,13 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>]) {
         // covered by the set of guards that cover it, but that's really hard to do.
         recurse_or_patterns(arm.pat, |pat| {
             let path = match &peel_hir_pat_refs(pat).0.kind {
-                PatKind::Path(path) => {
-                    let id = match cx.qpath_res(path, pat.hir_id) {
+                PatKind::Expr(PatExpr {
+                    hir_id,
+                    kind: PatExprKind::Path(path),
+                    ..
+                }) => {
+                    // FIXME(clippy): don't you want to use the hir id of the peeled pat?
+                    let id = match cx.qpath_res(path, *hir_id) {
                         Res::Def(
                             DefKind::Const | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst,
                             _,
diff --git a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
index 0d5575efc22..7e65d586110 100644
--- a/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/needless_match.rs
@@ -8,7 +8,9 @@ use clippy_utils::{
 };
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::OptionNone;
-use rustc_hir::{Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExprKind, PatKind, Path, QPath};
+use rustc_hir::{
+    Arm, BindingMode, ByRef, Expr, ExprKind, ItemKind, Node, Pat, PatExpr, PatExprKind, PatKind, Path, QPath,
+};
 use rustc_lint::LateContext;
 use rustc_span::sym;
 
@@ -183,7 +185,13 @@ fn pat_same_as_expr(pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
             return !matches!(annot, BindingMode(ByRef::Yes(_), _)) && pat_ident.name == first_seg.ident.name;
         },
         // Example: `Custom::TypeA => Custom::TypeB`, or `None => None`
-        (PatKind::Path(QPath::Resolved(_, p_path)), ExprKind::Path(QPath::Resolved(_, e_path))) => {
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(QPath::Resolved(_, p_path)),
+                ..
+            }),
+            ExprKind::Path(QPath::Resolved(_, e_path)),
+        ) => {
             return over(p_path.segments, e_path.segments, |p_seg, e_seg| {
                 p_seg.ident.name == e_seg.ident.name
             });
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
index edac97344a0..39339966013 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs
@@ -9,7 +9,7 @@ use rustc_ast::ast::LitKind;
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{self, OptionNone, OptionSome, PollPending, PollReady, ResultErr, ResultOk};
 use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExprKind, PatKind, QPath, UnOp};
+use rustc_hir::{Arm, Expr, ExprKind, Node, Pat, PatExpr, PatExprKind, PatKind, QPath, UnOp};
 use rustc_lint::LateContext;
 use rustc_middle::ty::{self, GenericArgKind, Ty};
 use rustc_span::{Span, Symbol, sym};
@@ -149,8 +149,12 @@ fn find_method_and_type<'tcx>(
                 None
             }
         },
-        PatKind::Path(ref path) => {
-            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, check_pat.hir_id)
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(path),
+            hir_id,
+            ..
+        }) => {
+            if let Res::Def(DefKind::Ctor(..), ctor_id) = cx.qpath_res(path, *hir_id)
                 && let Some(variant_id) = cx.tcx.opt_parent(ctor_id)
             {
                 let method = if cx.tcx.lang_items().option_none_variant() == Some(variant_id) {
@@ -351,10 +355,20 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::TupleStruct(path_left, patterns, _), PatKind::Path(path_right))
-        | (PatKind::Path(path_left), PatKind::TupleStruct(path_right, patterns, _))
-            if patterns.len() == 1 =>
-        {
+        (
+            PatKind::TupleStruct(path_left, patterns, _),
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_right),
+                ..
+            }),
+        )
+        | (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::TupleStruct(path_right, patterns, _),
+        ) if patterns.len() == 1 => {
             if let PatKind::Wild = patterns[0].kind {
                 find_good_method_for_match(
                     cx,
@@ -389,7 +403,13 @@ fn found_good_method<'tcx>(
                 None
             }
         },
-        (PatKind::Path(path_left), PatKind::Wild) => get_good_method(cx, arms, path_left),
+        (
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(path_left),
+                ..
+            }),
+            PatKind::Wild,
+        ) => get_good_method(cx, arms, path_left),
         _ => None,
     }
 }
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 38f876fed80..2f46eaaabb3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -114,7 +114,7 @@ fn report_single_pattern(cx: &LateContext<'_>, ex: &Expr<'_>, arm: &Arm<'_>, exp
     }
 
     let (pat, pat_ref_count) = peel_hir_pat_refs(arm.pat);
-    let (msg, sugg) = if let PatKind::Path(_) | PatKind::Expr(_) = pat.kind
+    let (msg, sugg) = if let PatKind::Expr(_) = pat.kind
         && let (ty, ty_ref_count) = peel_middle_ty_refs(cx.typeck_results().expr_ty(ex))
         && let Some(spe_trait_id) = cx.tcx.lang_items().structural_peq_trait()
         && let Some(pe_trait_id) = cx.tcx.lang_items().eq_trait()
@@ -331,14 +331,16 @@ impl<'a> PatState<'a> {
     #[expect(clippy::similar_names)]
     fn add_pat<'tcx>(&mut self, cx: &'a PatCtxt<'tcx>, pat: &'tcx Pat<'_>) -> bool {
         match pat.kind {
-            PatKind::Path(_)
-                if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
-                    ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
-                    ty::Tuple(tys) => !tys.is_empty(),
-                    ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
-                    ty::Slice(..) => true,
-                    _ => false,
-                } =>
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(_),
+                ..
+            }) if match *cx.typeck.pat_ty(pat).peel_refs().kind() {
+                ty::Adt(adt, _) => adt.is_enum() || (adt.is_struct() && !adt.non_enum_variant().fields.is_empty()),
+                ty::Tuple(tys) => !tys.is_empty(),
+                ty::Array(_, len) => len.try_to_target_usize(cx.tcx) != Some(1),
+                ty::Slice(..) => true,
+                _ => false,
+            } =>
             {
                 matches!(self, Self::Wild)
             },
@@ -386,7 +388,6 @@ impl<'a> PatState<'a> {
             | PatKind::Binding(_, _, _, None)
             | PatKind::Expr(_)
             | PatKind::Range(..)
-            | PatKind::Path(_)
             | PatKind::Never
             | PatKind::Err(_) => {
                 *self = PatState::Wild;
diff --git a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
index 882ab2dda7a..0e1980a6acb 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_bound_locations.rs
@@ -1,5 +1,5 @@
 use rustc_ast::visit::FnKind;
-use rustc_ast::{NodeId, WherePredicateKind};
+use rustc_ast::{Fn, NodeId, WherePredicateKind};
 use rustc_data_structures::fx::FxHashMap;
 use rustc_lint::{EarlyContext, EarlyLintPass};
 use rustc_session::declare_lint_pass;
@@ -39,7 +39,7 @@ declare_lint_pass!(MultipleBoundLocations => [MULTIPLE_BOUND_LOCATIONS]);
 
 impl EarlyLintPass for MultipleBoundLocations {
     fn check_fn(&mut self, cx: &EarlyContext<'_>, kind: FnKind<'_>, _: Span, _: NodeId) {
-        if let FnKind::Fn(_, _, _, _, generics, _) = kind
+        if let FnKind::Fn(_, _, _, Fn { generics, .. }) = kind
             && !generics.params.is_empty()
             && !generics.where_clause.predicates.is_empty()
         {
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index 6d9e75f51d6..de9f055863c 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -7,7 +7,9 @@ use clippy_utils::{
 use rustc_errors::Applicability;
 use rustc_hir::LangItem::{OptionNone, OptionSome, ResultErr, ResultOk};
 use rustc_hir::def::Res;
-use rustc_hir::{Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatKind, Path, QPath, UnOp};
+use rustc_hir::{
+    Arm, BindingMode, Expr, ExprKind, MatchSource, Mutability, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, UnOp,
+};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::declare_lint_pass;
 use rustc_span::SyntaxContext;
@@ -281,7 +283,11 @@ fn try_convert_match<'tcx>(
 
 fn is_none_or_err_arm(cx: &LateContext<'_>, arm: &Arm<'_>) -> bool {
     match arm.pat.kind {
-        PatKind::Path(ref qpath) => is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), OptionNone),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_res_lang_ctor(cx, cx.qpath_res(qpath, *hir_id), OptionNone),
         PatKind::TupleStruct(ref qpath, [first_pat], _) => {
             is_res_lang_ctor(cx, cx.qpath_res(qpath, arm.pat.hir_id), ResultErr)
                 && matches!(first_pat.kind, PatKind::Wild)
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 84b6430294f..47ce2243aa0 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -10,7 +10,7 @@ use rustc_hir::def_id::LocalDefId;
 use rustc_hir::intravisit::{InferKind, Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
     self as hir, AmbigArg, Expr, ExprKind, FnRetTy, FnSig, GenericArgsParentheses, GenericParam, GenericParamKind,
-    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatKind, Path, QPath, Ty, TyKind,
+    HirId, Impl, ImplItemKind, Item, ItemKind, Pat, PatExpr, PatExprKind, PatKind, Path, QPath, Ty, TyKind,
 };
 use rustc_hir_analysis::lower_ty;
 use rustc_lint::{LateContext, LateLintPass};
@@ -258,7 +258,7 @@ impl<'tcx> LateLintPass<'tcx> for UseSelf {
             && self.msrv.meets(msrvs::TYPE_ALIAS_ENUM_VARIANTS)
             && let Some(&StackItem::Check { impl_id, .. }) = self.stack.last()
             // get the path from the pattern
-            && let PatKind::Path(QPath::Resolved(_, path))
+            && let PatKind::Expr(&PatExpr { kind: PatExprKind::Path(QPath::Resolved(_, path)), .. })
                  | PatKind::TupleStruct(QPath::Resolved(_, path), _, _)
                  | PatKind::Struct(QPath::Resolved(_, path), _, _) = pat.kind
             && cx.typeck_results().pat_ty(pat) == cx.tcx.type_of(impl_id).instantiate_identity()
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index 4dcc8ac7fb0..6bad78cf871 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -708,11 +708,6 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
                 self.qpath(qpath);
                 self.slice(fields, |pat| self.pat(pat));
             },
-            PatKind::Path(ref qpath) => {
-                bind!(self, qpath);
-                kind!("Path(ref {qpath})");
-                self.qpath(qpath);
-            },
             PatKind::Tuple(fields, skip_pos) => {
                 bind!(self, fields);
                 kind!("Tuple({fields}, {skip_pos:?})");
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index d76231a6eea..d0eb5318e64 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -524,7 +524,6 @@ impl HirEqInterExpr<'_, '_, '_> {
                 }
                 eq
             },
-            (PatKind::Path(l), PatKind::Path(r)) => self.eq_qpath(l, r),
             (&PatKind::Expr(l), &PatKind::Expr(r)) => self.eq_pat_expr(l, r),
             (&PatKind::Tuple(l, ls), &PatKind::Tuple(r, rs)) => ls == rs && over(l, r, |l, r| self.eq_pat(l, r)),
             (&PatKind::Range(ref ls, ref le, li), &PatKind::Range(ref rs, ref re, ri)) => {
@@ -1120,7 +1119,6 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> {
                     self.hash_pat(pat);
                 }
             },
-            PatKind::Path(ref qpath) => self.hash_qpath(qpath),
             PatKind::Range(s, e, i) => {
                 if let Some(s) = s {
                     self.hash_pat_expr(s);
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index e471dfb6ef1..5a5227af907 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -106,8 +106,8 @@ use rustc_hir::{
     self as hir, Arm, BindingMode, Block, BlockCheckMode, Body, ByRef, Closure, ConstArgKind, ConstContext,
     Destination, Expr, ExprField, ExprKind, FnDecl, FnRetTy, GenericArgs, HirId, Impl, ImplItem, ImplItemKind,
     ImplItemRef, Item, ItemKind, LangItem, LetStmt, MatchSource, Mutability, Node, OwnerId, OwnerNode, Param, Pat,
-    PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitItemRef, TraitRef,
-    TyKind, UnOp, def,
+    PatExpr, PatExprKind, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind,
+    TraitItemRef, TraitRef, TyKind, UnOp, def,
 };
 use rustc_lexer::{TokenKind, tokenize};
 use rustc_lint::{LateContext, Level, Lint, LintContext};
@@ -560,7 +560,20 @@ macro_rules! maybe_path {
     };
 }
 maybe_path!(Expr, ExprKind);
-maybe_path!(Pat, PatKind);
+impl<'hir> MaybePath<'hir> for Pat<'hir> {
+    fn hir_id(&self) -> HirId {
+        self.hir_id
+    }
+    fn qpath_opt(&self) -> Option<&QPath<'hir>> {
+        match &self.kind {
+            PatKind::Expr(PatExpr {
+                kind: PatExprKind::Path(qpath),
+                ..
+            }) => Some(qpath),
+            _ => None,
+        }
+    }
+}
 maybe_path!(Ty, TyKind);
 
 /// If `maybe_path` is a path node, resolves it, otherwise returns `Res::Err`
@@ -1753,7 +1766,11 @@ pub fn is_refutable(cx: &LateContext<'_>, pat: &Pat<'_>) -> bool {
         PatKind::Wild | PatKind::Never => false, // If `!` typechecked then the type is empty, so not refutable.
         PatKind::Binding(_, _, _, pat) => pat.is_some_and(|pat| is_refutable(cx, pat)),
         PatKind::Box(pat) | PatKind::Ref(pat, _) => is_refutable(cx, pat),
-        PatKind::Path(ref qpath) => is_enum_variant(cx, qpath, pat.hir_id),
+        PatKind::Expr(PatExpr {
+            kind: PatExprKind::Path(qpath),
+            hir_id,
+            ..
+        }) => is_enum_variant(cx, qpath, *hir_id),
         PatKind::Or(pats) => {
             // TODO: should be the honest check, that pats is exhaustive set
             are_refutable(cx, pats)
diff --git a/src/tools/clippy/clippy_utils/src/ty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/mod.rs
index f2bbdda7058..e9a05c45747 100644
--- a/src/tools/clippy/clippy_utils/src/ty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/mod.rs
@@ -96,7 +96,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
                         return false;
                     }
 
-                    for (predicate, _span) in cx.tcx.explicit_item_super_predicates(def_id).iter_identity_copied() {
+                    for (predicate, _span) in cx.tcx.explicit_item_self_bounds(def_id).iter_identity_copied() {
                         match predicate.kind().skip_binder() {
                             // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through
                             // and check substitutions to find `U`.
@@ -322,7 +322,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
         },
         ty::Tuple(args) => args.iter().any(|ty| is_must_use_ty(cx, ty)),
         ty::Alias(ty::Opaque, AliasTy { def_id, .. }) => {
-            for (predicate, _) in cx.tcx.explicit_item_super_predicates(def_id).skip_binder() {
+            for (predicate, _) in cx.tcx.explicit_item_self_bounds(def_id).skip_binder() {
                 if let ty::ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder() {
                     if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) {
                         return true;
@@ -712,7 +712,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<ExprFnSig<'t
         ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) => sig_from_bounds(
             cx,
             ty,
-            cx.tcx.item_super_predicates(def_id).iter_instantiated(cx.tcx, args),
+            cx.tcx.item_self_bounds(def_id).iter_instantiated(cx.tcx, args),
             cx.tcx.opt_parent(def_id),
         ),
         ty::FnPtr(sig_tys, hdr) => Some(ExprFnSig::Sig(sig_tys.with(hdr), None)),
diff --git a/src/tools/miri/src/shims/alloc.rs b/src/tools/miri/src/shims/alloc.rs
index 25c0b52d061..0fda13e0616 100644
--- a/src/tools/miri/src/shims/alloc.rs
+++ b/src/tools/miri/src/shims/alloc.rs
@@ -1,5 +1,3 @@
-use std::iter;
-
 use rustc_abi::{Align, Size};
 use rustc_ast::expand::allocator::AllocatorKind;
 
@@ -80,18 +78,10 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         }
     }
 
-    fn malloc(&mut self, size: u64, zero_init: bool) -> InterpResult<'tcx, Pointer> {
+    fn malloc(&mut self, size: u64, init: AllocInit) -> InterpResult<'tcx, Pointer> {
         let this = self.eval_context_mut();
         let align = this.malloc_align(size);
-        let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into())?;
-        if zero_init {
-            // We just allocated this, the access is definitely in-bounds and fits into our address space.
-            this.write_bytes_ptr(
-                ptr.into(),
-                iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-            )
-            .unwrap();
-        }
+        let ptr = this.allocate_ptr(Size::from_bytes(size), align, MiriMemoryKind::C.into(), init)?;
         interp_ok(ptr.into())
     }
 
@@ -115,6 +105,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 Size::from_bytes(size),
                 Align::from_bytes(align).unwrap(),
                 MiriMemoryKind::C.into(),
+                AllocInit::Uninit
             )?;
             this.write_pointer(ptr, &memptr)?;
             interp_ok(Scalar::from_i32(0))
@@ -134,7 +125,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
         let new_align = this.malloc_align(new_size);
         if this.ptr_is_null(old_ptr)? {
             // Here we must behave like `malloc`.
-            self.malloc(new_size, /*zero_init*/ false)
+            self.malloc(new_size, AllocInit::Uninit)
         } else {
             if new_size == 0 {
                 // C, in their infinite wisdom, made this UB.
@@ -147,6 +138,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(new_size),
                     new_align,
                     MiriMemoryKind::C.into(),
+                    AllocInit::Uninit
                 )?;
                 interp_ok(new_ptr.into())
             }
@@ -187,6 +179,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::C.into(),
+                    AllocInit::Uninit
                 )?;
                 interp_ok(ptr.into())
             }
diff --git a/src/tools/miri/src/shims/foreign_items.rs b/src/tools/miri/src/shims/foreign_items.rs
index 6c8ccc83985..1ce0c209de9 100644
--- a/src/tools/miri/src/shims/foreign_items.rs
+++ b/src/tools/miri/src/shims/foreign_items.rs
@@ -1,6 +1,5 @@
 use std::collections::hash_map::Entry;
 use std::io::Write;
-use std::iter;
 use std::path::Path;
 
 use rustc_abi::{Align, AlignFromBytesError, Size};
@@ -9,6 +8,7 @@ use rustc_ast::expand::allocator::alloc_error_handler_name;
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::CrateNum;
 use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use rustc_middle::mir::interpret::AllocInit;
 use rustc_middle::ty::Ty;
 use rustc_middle::{mir, ty};
 use rustc_span::Symbol;
@@ -442,7 +442,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let [size] = this.check_shim(abi, Conv::C, link_name, args)?;
                 let size = this.read_target_usize(size)?;
                 if size <= this.max_size_of_val().bytes() {
-                    let res = this.malloc(size, /*zero_init:*/ false)?;
+                    let res = this.malloc(size, AllocInit::Uninit)?;
                     this.write_pointer(res, dest)?;
                 } else {
                     // If this does not fit in an isize, return null and, on Unix, set errno.
@@ -457,7 +457,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 let items = this.read_target_usize(items)?;
                 let elem_size = this.read_target_usize(elem_size)?;
                 if let Some(size) = this.compute_size_in_bytes(Size::from_bytes(elem_size), items) {
-                    let res = this.malloc(size.bytes(), /*zero_init:*/ true)?;
+                    let res = this.malloc(size.bytes(), AllocInit::Zero)?;
                     this.write_pointer(res, dest)?;
                 } else {
                     // On size overflow, return null and, on Unix, set errno.
@@ -509,6 +509,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(size),
                         Align::from_bytes(align).unwrap(),
                         memory_kind.into(),
+                        AllocInit::Uninit
                     )?;
 
                     ecx.write_pointer(ptr, dest)
@@ -537,14 +538,8 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(size),
                         Align::from_bytes(align).unwrap(),
                         MiriMemoryKind::Rust.into(),
+                        AllocInit::Zero
                     )?;
-
-                    // We just allocated this, the access is definitely in-bounds.
-                    this.write_bytes_ptr(
-                        ptr.into(),
-                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-                    )
-                    .unwrap();
                     this.write_pointer(ptr, dest)
                 });
             }
@@ -604,6 +599,7 @@ trait EvalContextExtPriv<'tcx>: crate::MiriInterpCxExt<'tcx> {
                         Size::from_bytes(new_size),
                         align,
                         MiriMemoryKind::Rust.into(),
+                        AllocInit::Uninit
                     )?;
                     this.write_pointer(new_ptr, dest)
                 });
diff --git a/src/tools/miri/src/shims/unix/fs.rs b/src/tools/miri/src/shims/unix/fs.rs
index d3777a3f7a3..3874cda2697 100644
--- a/src/tools/miri/src/shims/unix/fs.rs
+++ b/src/tools/miri/src/shims/unix/fs.rs
@@ -1112,6 +1112,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     dirent_layout.align.abi,
                     MiriMemoryKind::Runtime.into(),
+                    AllocInit::Uninit
                 )?;
                 let entry: Pointer = entry.into();
 
diff --git a/src/tools/miri/src/shims/unix/linux/mem.rs b/src/tools/miri/src/shims/unix/linux/mem.rs
index 8e796d5dce5..6418d749d3d 100644
--- a/src/tools/miri/src/shims/unix/linux/mem.rs
+++ b/src/tools/miri/src/shims/unix/linux/mem.rs
@@ -49,16 +49,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             Size::from_bytes(new_size),
             align,
             MiriMemoryKind::Mmap.into(),
+            AllocInit::Zero
         )?;
-        if let Some(increase) = new_size.checked_sub(old_size) {
-            // We just allocated this, the access is definitely in-bounds and fits into our address space.
-            // mmap guarantees new mappings are zero-init.
-            this.write_bytes_ptr(
-                ptr.wrapping_offset(Size::from_bytes(old_size), this).into(),
-                std::iter::repeat(0u8).take(usize::try_from(increase).unwrap()),
-            )
-            .unwrap();
-        }
 
         interp_ok(Scalar::from_pointer(ptr, this))
     }
diff --git a/src/tools/miri/src/shims/unix/mem.rs b/src/tools/miri/src/shims/unix/mem.rs
index 5531b944e17..2d5d3a6471a 100644
--- a/src/tools/miri/src/shims/unix/mem.rs
+++ b/src/tools/miri/src/shims/unix/mem.rs
@@ -111,15 +111,13 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
             return interp_ok(this.eval_libc("MAP_FAILED"));
         }
 
-        let ptr =
-            this.allocate_ptr(Size::from_bytes(map_length), align, MiriMemoryKind::Mmap.into())?;
-        // We just allocated this, the access is definitely in-bounds and fits into our address space.
-        // mmap guarantees new mappings are zero-init.
-        this.write_bytes_ptr(
-            ptr.into(),
-            std::iter::repeat(0u8).take(usize::try_from(map_length).unwrap()),
-        )
-        .unwrap();
+        let ptr = this.allocate_ptr(
+            Size::from_bytes(map_length),
+            align,
+            MiriMemoryKind::Mmap.into(),
+            // mmap guarantees new mappings are zero-init.
+            AllocInit::Zero
+        )?;
 
         interp_ok(Scalar::from_pointer(ptr, this))
     }
diff --git a/src/tools/miri/src/shims/windows/foreign_items.rs b/src/tools/miri/src/shims/windows/foreign_items.rs
index 0bf56c3d005..4462d025bea 100644
--- a/src/tools/miri/src/shims/windows/foreign_items.rs
+++ b/src/tools/miri/src/shims/windows/foreign_items.rs
@@ -253,8 +253,12 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                 this.read_target_isize(handle)?;
                 let flags = this.read_scalar(flags)?.to_u32()?;
                 let size = this.read_target_usize(size)?;
-                let heap_zero_memory = 0x00000008; // HEAP_ZERO_MEMORY
-                let zero_init = (flags & heap_zero_memory) == heap_zero_memory;
+                const HEAP_ZERO_MEMORY: u32 = 0x00000008;
+                let init = if (flags & HEAP_ZERO_MEMORY) == HEAP_ZERO_MEMORY {
+                    AllocInit::Zero
+                } else {
+                    AllocInit::Uninit
+                };
                 // Alignment is twice the pointer size.
                 // Source: <https://learn.microsoft.com/en-us/windows/win32/api/heapapi/nf-heapapi-heapalloc>
                 let align = this.tcx.pointer_size().bytes().strict_mul(2);
@@ -262,13 +266,8 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::WinHeap.into(),
+                    init
                 )?;
-                if zero_init {
-                    this.write_bytes_ptr(
-                        ptr.into(),
-                        iter::repeat(0u8).take(usize::try_from(size).unwrap()),
-                    )?;
-                }
                 this.write_pointer(ptr, dest)?;
             }
             "HeapFree" => {
@@ -300,6 +299,7 @@ pub trait EvalContextExt<'tcx>: crate::MiriInterpCxExt<'tcx> {
                     Size::from_bytes(size),
                     Align::from_bytes(align).unwrap(),
                     MiriMemoryKind::WinHeap.into(),
+                    AllocInit::Uninit
                 )?;
                 this.write_pointer(new_ptr, dest)?;
             }
diff --git a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs
index 4d5ddd75f38..6ca53c0eb6f 100644
--- a/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs
+++ b/src/tools/miri/tests/pass/shims/x86/intrinsics-x86-pause-without-sse2.rs
@@ -1,5 +1,5 @@
-// We're testing x86 target specific features
-//@only-target: x86_64 i686
+// We're testing x86-32 target specific features. SSE always exists on x86-64.
+//@only-target: i686
 //@compile-flags: -C target-feature=-sse2
 
 #[cfg(target_arch = "x86")]
diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs
index b4dc753ab53..70a72bd1abe 100644
--- a/src/tools/run-make-support/src/command.rs
+++ b/src/tools/run-make-support/src/command.rs
@@ -388,9 +388,13 @@ impl CompletedProcess {
         self
     }
 
+    /// Check the **exit status** of the process. On Unix, this is *not* the **wait status**.
+    ///
+    /// See [`std::process::ExitStatus::code`]. This is not to be confused with
+    /// [`std::process::ExitCode`].
     #[track_caller]
     pub fn assert_exit_code(&self, code: i32) -> &Self {
-        assert!(self.output.status.code() == Some(code));
+        assert_eq!(self.output.status.code(), Some(code));
         self
     }
 }
diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs
index 8894ea7fb20..b70db7130f6 100644
--- a/src/tools/run-make-support/src/external_deps/rustc.rs
+++ b/src/tools/run-make-support/src/external_deps/rustc.rs
@@ -1,5 +1,6 @@
 use std::ffi::{OsStr, OsString};
-use std::path::Path;
+use std::path::{Path, PathBuf};
+use std::str::FromStr as _;
 
 use crate::command::Command;
 use crate::env::env_var;
@@ -390,3 +391,10 @@ impl Rustc {
         self
     }
 }
+
+/// Query the sysroot path corresponding `rustc --print=sysroot`.
+#[track_caller]
+pub fn sysroot() -> PathBuf {
+    let path = rustc().print("sysroot").run().stdout_utf8();
+    PathBuf::from_str(path.trim()).unwrap()
+}
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index f92668a6a97..2dfca7c4803 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -846,7 +846,6 @@ dependencies = [
  "dashmap",
  "hashbrown",
  "rustc-hash 2.0.0",
- "sptr",
  "triomphe",
 ]
 
@@ -1928,12 +1927,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "sptr"
-version = "0.3.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9b39299b249ad65f3b7e96443bad61c02ca5cd3589f46cb6d610a0fd6c0d6a"
-
-[[package]]
 name = "stdx"
 version = "0.0.0"
 dependencies = [
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 1029844cd3a..c42ae171d86 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -4,7 +4,7 @@ exclude = ["crates/proc-macro-srv/proc-macro-test/imp"]
 resolver = "2"
 
 [workspace.package]
-rust-version = "1.83"
+rust-version = "1.84"
 edition = "2021"
 license = "MIT OR Apache-2.0"
 authors = ["rust-analyzer team"]
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 1327bb3ab59..16c7b5ca00a 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
@@ -1381,6 +1381,9 @@ impl ExprCollector<'_> {
                 }
             }
             ast::Stmt::Item(ast::Item::MacroDef(macro_)) => {
+                if self.check_cfg(&macro_).is_none() {
+                    return;
+                }
                 let Some(name) = macro_.name() else {
                     statements.push(Statement::Item(Item::Other));
                     return;
@@ -1390,6 +1393,9 @@ impl ExprCollector<'_> {
                 self.collect_macro_def(statements, macro_id);
             }
             ast::Stmt::Item(ast::Item::MacroRules(macro_)) => {
+                if self.check_cfg(&macro_).is_none() {
+                    return;
+                }
                 let Some(name) = macro_.name() else {
                     statements.push(Statement::Item(Item::Other));
                     return;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
index 68c7173d1e4..994ba2aa069 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
@@ -229,7 +229,7 @@ impl ExprCollector<'_> {
                     };
                     for piece in unverified_pieces {
                         match piece {
-                            rustc_parse_format::Piece::String(_) => {}
+                            rustc_parse_format::Piece::Lit(_) => {}
                             rustc_parse_format::Piece::NextArgument(arg) => {
                                 // let span = arg_spans.next();
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
index f483efa8517..e136dd18a55 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
@@ -475,7 +475,7 @@ fn outer() {
 
             block scope::tests
             name: _
-            outer: v
+            outer: vg
 
             crate
             outer: v
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 5d67902c8ac..c30ad0163b9 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
@@ -445,6 +445,10 @@ fn find_in_dep(
         };
         cov_mark::hit!(partially_imported);
         if info.is_unstable {
+            if !ctx.cfg.allow_unstable {
+                // the item is unstable and we are not allowed to use unstable items
+                continue;
+            }
             choice.stability = Unstable;
         }
 
@@ -670,6 +674,7 @@ mod tests {
         prefer_prelude: bool,
         prefer_absolute: bool,
         prefer_no_std: bool,
+        allow_unstable: bool,
         expect: Expect,
     ) {
         let (db, pos) = TestDB::with_position(ra_fixture);
@@ -711,7 +716,7 @@ mod tests {
                 module,
                 prefix,
                 ignore_local_imports,
-                ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute },
+                ImportPathConfig { prefer_no_std, prefer_prelude, prefer_absolute, allow_unstable },
             );
             format_to!(
                 res,
@@ -732,7 +737,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, false, false, expect);
+        check_found_path_(ra_fixture, path, false, false, false, false, expect);
     }
 
     fn check_found_path_prelude(
@@ -740,7 +745,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, true, false, false, expect);
+        check_found_path_(ra_fixture, path, true, false, false, false, expect);
     }
 
     fn check_found_path_absolute(
@@ -748,7 +753,7 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, true, false, expect);
+        check_found_path_(ra_fixture, path, false, true, false, false, expect);
     }
 
     fn check_found_path_prefer_no_std(
@@ -756,7 +761,15 @@ mod tests {
         path: &str,
         expect: Expect,
     ) {
-        check_found_path_(ra_fixture, path, false, false, true, expect);
+        check_found_path_(ra_fixture, path, false, false, true, false, expect);
+    }
+
+    fn check_found_path_prefer_no_std_allow_unstable(
+        #[rust_analyzer::rust_fixture] ra_fixture: &str,
+        path: &str,
+        expect: Expect,
+    ) {
+        check_found_path_(ra_fixture, path, false, false, true, true, expect);
     }
 
     #[test]
@@ -1951,7 +1964,7 @@ pub mod ops {
 
     #[test]
     fn respect_unstable_modules() {
-        check_found_path_prefer_no_std(
+        check_found_path_prefer_no_std_allow_unstable(
             r#"
 //- /main.rs crate:main deps:std,core
 extern crate std;
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
index e64e498c170..28c824fd31d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir/format_args.rs
@@ -287,7 +287,7 @@ pub(crate) fn parse(
 
     for piece in pieces {
         match piece {
-            parse::Piece::String(s) => {
+            parse::Piece::Lit(s) => {
                 unfinished_literal.push_str(s);
             }
             parse::Piece::NextArgument(arg) => {
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 ac262950f13..34635997bdf 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
@@ -10,7 +10,6 @@ use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::Edition;
 use stdx::{format_to, TupleExt};
-use syntax::ToSmolStr;
 use triomphe::Arc;
 
 use crate::{
@@ -88,9 +87,9 @@ impl ImportMap {
             .iter()
             // We've only collected items, whose name cannot be tuple field so unwrapping is fine.
             .flat_map(|(&item, (info, _))| {
-                info.iter().enumerate().map(move |(idx, info)| {
-                    (item, info.name.unescaped().display(db.upcast()).to_smolstr(), idx as u32)
-                })
+                info.iter()
+                    .enumerate()
+                    .map(move |(idx, info)| (item, info.name.as_str(), idx as u32))
             })
             .collect();
         importables.sort_by(|(_, l_info, _), (_, r_info, _)| {
@@ -168,7 +167,8 @@ impl ImportMap {
                     let attr_id = if let Some(import) = import {
                         match import {
                             ImportOrExternCrate::ExternCrate(id) => Some(id.into()),
-                            ImportOrExternCrate::Import(id) => Some(id.import.into()),
+                            ImportOrExternCrate::Import(id) => Some(id.use_.into()),
+                            ImportOrExternCrate::Glob(id) => Some(id.use_.into()),
                         }
                     } else {
                         match item {
@@ -441,7 +441,7 @@ pub fn search_dependencies(
 }
 
 fn search_maps(
-    db: &dyn DefDatabase,
+    _db: &dyn DefDatabase,
     import_maps: &[Arc<ImportMap>],
     mut stream: fst::map::Union<'_>,
     query: &Query,
@@ -464,11 +464,7 @@ fn search_maps(
                         .then(|| (item, &import_infos[info_idx as usize]))
                 })
                 .filter(|&(_, info)| {
-                    query.search_mode.check(
-                        &query.query,
-                        query.case_sensitive,
-                        &info.name.unescaped().display(db.upcast()).to_smolstr(),
-                    )
+                    query.search_mode.check(&query.query, query.case_sensitive, info.name.as_str())
                 });
             res.extend(iter.map(TupleExt::head));
         }
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 0fec7674109..65a39c56561 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
@@ -31,21 +31,62 @@ pub struct PerNsGlobImports {
 
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum ImportOrExternCrate {
+    Glob(GlobId),
     Import(ImportId),
     ExternCrate(ExternCrateId),
 }
 
+impl From<ImportOrGlob> for ImportOrExternCrate {
+    fn from(value: ImportOrGlob) -> Self {
+        match value {
+            ImportOrGlob::Glob(it) => ImportOrExternCrate::Glob(it),
+            ImportOrGlob::Import(it) => ImportOrExternCrate::Import(it),
+        }
+    }
+}
+
+impl ImportOrExternCrate {
+    pub fn import_or_glob(self) -> Option<ImportOrGlob> {
+        match self {
+            ImportOrExternCrate::Import(it) => Some(ImportOrGlob::Import(it)),
+            ImportOrExternCrate::Glob(it) => Some(ImportOrGlob::Glob(it)),
+            _ => None,
+        }
+    }
+
+    pub fn import(self) -> Option<ImportId> {
+        match self {
+            ImportOrExternCrate::Import(it) => Some(it),
+            _ => None,
+        }
+    }
+
+    pub fn glob(self) -> Option<GlobId> {
+        match self {
+            ImportOrExternCrate::Glob(id) => Some(id),
+            _ => None,
+        }
+    }
+
+    pub fn use_(self) -> Option<UseId> {
+        match self {
+            ImportOrExternCrate::Glob(id) => Some(id.use_),
+            ImportOrExternCrate::Import(id) => Some(id.use_),
+            _ => None,
+        }
+    }
+}
+
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
-pub(crate) enum ImportType {
+pub enum ImportOrGlob {
+    Glob(GlobId),
     Import(ImportId),
-    Glob(UseId),
-    ExternCrate(ExternCrateId),
 }
 
-impl ImportOrExternCrate {
+impl ImportOrGlob {
     pub fn into_import(self) -> Option<ImportId> {
         match self {
-            ImportOrExternCrate::Import(it) => Some(it),
+            ImportOrGlob::Import(it) => Some(it),
             _ => None,
         }
     }
@@ -54,12 +95,39 @@ impl ImportOrExternCrate {
 #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
 pub enum ImportOrDef {
     Import(ImportId),
+    Glob(GlobId),
     ExternCrate(ExternCrateId),
     Def(ModuleDefId),
 }
+
+impl From<ImportOrExternCrate> for ImportOrDef {
+    fn from(value: ImportOrExternCrate) -> Self {
+        match value {
+            ImportOrExternCrate::Import(it) => ImportOrDef::Import(it),
+            ImportOrExternCrate::Glob(it) => ImportOrDef::Glob(it),
+            ImportOrExternCrate::ExternCrate(it) => ImportOrDef::ExternCrate(it),
+        }
+    }
+}
+
+impl From<ImportOrGlob> for ImportOrDef {
+    fn from(value: ImportOrGlob) -> Self {
+        match value {
+            ImportOrGlob::Import(it) => ImportOrDef::Import(it),
+            ImportOrGlob::Glob(it) => ImportOrDef::Glob(it),
+        }
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
 pub struct ImportId {
-    pub import: UseId,
+    pub use_: UseId,
+    pub idx: Idx<ast::UseTree>,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
+pub struct GlobId {
+    pub use_: UseId,
     pub idx: Idx<ast::UseTree>,
 }
 
@@ -96,8 +164,8 @@ pub struct ItemScope {
 
     // the resolutions of the imports of this scope
     use_imports_types: FxHashMap<ImportOrExternCrate, ImportOrDef>,
-    use_imports_values: FxHashMap<ImportId, ImportOrDef>,
-    use_imports_macros: FxHashMap<ImportId, ImportOrDef>,
+    use_imports_values: FxHashMap<ImportOrGlob, ImportOrDef>,
+    use_imports_macros: FxHashMap<ImportOrGlob, ImportOrDef>,
 
     use_decls: Vec<UseId>,
     extern_crate_decls: Vec<ExternCrateId>,
@@ -162,7 +230,7 @@ impl ItemScope {
             .map(move |name| (name, self.get(name)))
     }
 
-    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportId>)> + '_ {
+    pub fn values(&self) -> impl Iterator<Item = (&Name, Item<ModuleDefId, ImportOrGlob>)> + '_ {
         self.values.iter().map(|(n, &i)| (n, i))
     }
 
@@ -172,7 +240,7 @@ impl ItemScope {
         self.types.iter().map(|(n, &i)| (n, i))
     }
 
-    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportId>)> + '_ {
+    pub fn macros(&self) -> impl Iterator<Item = (&Name, Item<MacroId, ImportOrGlob>)> + '_ {
         self.macros.iter().map(|(n, &i)| (n, i))
     }
 
@@ -180,9 +248,10 @@ impl ItemScope {
         self.use_imports_types
             .keys()
             .copied()
-            .filter_map(ImportOrExternCrate::into_import)
+            .filter_map(ImportOrExternCrate::import_or_glob)
             .chain(self.use_imports_values.keys().copied())
             .chain(self.use_imports_macros.keys().copied())
+            .filter_map(ImportOrGlob::into_import)
             .sorted()
             .dedup()
     }
@@ -192,10 +261,10 @@ impl ItemScope {
 
         let mut def_map;
         let mut scope = self;
-        while let Some(&m) = scope.use_imports_macros.get(&import) {
+        while let Some(&m) = scope.use_imports_macros.get(&ImportOrGlob::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -211,7 +280,7 @@ impl ItemScope {
         while let Some(&m) = scope.use_imports_types.get(&ImportOrExternCrate::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -224,10 +293,10 @@ impl ItemScope {
             }
         }
         let mut scope = self;
-        while let Some(&m) = scope.use_imports_values.get(&import) {
+        while let Some(&m) = scope.use_imports_values.get(&ImportOrGlob::Import(import)) {
             match m {
                 ImportOrDef::Import(i) => {
-                    let module_id = i.import.lookup(db).container;
+                    let module_id = i.use_.lookup(db).container;
                     def_map = module_id.def_map(db);
                     scope = &def_map[module_id.local_id].scope;
                     import = i;
@@ -488,9 +557,13 @@ impl ItemScope {
         self.unnamed_trait_imports.get(&tr).map(|trait_| trait_.vis)
     }
 
-    pub(crate) fn push_unnamed_trait(&mut self, tr: TraitId, vis: Visibility) {
-        // FIXME: import
-        self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import: None });
+    pub(crate) fn push_unnamed_trait(
+        &mut self,
+        tr: TraitId,
+        vis: Visibility,
+        import: Option<ImportId>,
+    ) {
+        self.unnamed_trait_imports.insert(tr, Item { def: (), vis, import });
     }
 
     pub(crate) fn push_res_with_import(
@@ -498,7 +571,7 @@ impl ItemScope {
         glob_imports: &mut PerNsGlobImports,
         lookup: (LocalModuleId, Name),
         def: PerNs,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
     ) -> bool {
         let mut changed = false;
 
@@ -509,41 +582,22 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.types.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.types.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::ExternCrate(extern_crate)) => {
-                            Some(ImportOrExternCrate::ExternCrate(extern_crate))
-                        }
-                        Some(ImportType::Import(import)) => {
-                            Some(ImportOrExternCrate::Import(import))
-                        }
-                        None | Some(ImportType::Glob(_)) => None,
-                    };
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
-                        self.use_imports_types.insert(
-                            import,
-                            match prev {
-                                Some(ImportOrExternCrate::Import(import)) => {
-                                    ImportOrDef::Import(import)
-                                }
-                                Some(ImportOrExternCrate::ExternCrate(import)) => {
-                                    ImportOrDef::ExternCrate(import)
-                                }
-                                None => ImportOrDef::Def(fld.def),
-                            },
-                        );
+                        self.use_imports_types
+                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                     }
                     entry.insert(fld);
                     changed = true;
                 }
                 Entry::Occupied(mut entry) => {
                     match import {
-                        Some(ImportType::Glob(..)) => {
+                        Some(ImportOrExternCrate::Glob(..)) => {
                             // Multiple globs may import the same item and they may
                             // override visibility from previously resolved globs. This is
                             // currently handled by `DefCollector`, because we need to
@@ -552,28 +606,11 @@ impl ItemScope {
                         }
                         _ => {
                             if glob_imports.types.remove(&lookup) {
-                                let import = match import {
-                                    Some(ImportType::ExternCrate(extern_crate)) => {
-                                        Some(ImportOrExternCrate::ExternCrate(extern_crate))
-                                    }
-                                    Some(ImportType::Import(import)) => {
-                                        Some(ImportOrExternCrate::Import(import))
-                                    }
-                                    None | Some(ImportType::Glob(_)) => None,
-                                };
                                 let prev = std::mem::replace(&mut fld.import, import);
                                 if let Some(import) = import {
                                     self.use_imports_types.insert(
                                         import,
-                                        match prev {
-                                            Some(ImportOrExternCrate::Import(import)) => {
-                                                ImportOrDef::Import(import)
-                                            }
-                                            Some(ImportOrExternCrate::ExternCrate(import)) => {
-                                                ImportOrDef::ExternCrate(import)
-                                            }
-                                            None => ImportOrDef::Def(fld.def),
-                                        },
+                                        prev.map_or(ImportOrDef::Def(fld.def), Into::into),
                                     );
                                 }
                                 cov_mark::hit!(import_shadowed);
@@ -591,44 +628,31 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.values.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.values.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::Import(import)) => Some(import),
-                        _ => None,
-                    };
+                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
-                        self.use_imports_values.insert(
-                            import,
-                            match prev {
-                                Some(import) => ImportOrDef::Import(import),
-                                None => ImportOrDef::Def(fld.def),
-                            },
-                        );
+                        self.use_imports_values
+                            .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                     }
                     entry.insert(fld);
                     changed = true;
                 }
-                Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+                Entry::Occupied(mut entry)
+                    if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+                {
                     if glob_imports.values.remove(&lookup) {
                         cov_mark::hit!(import_shadowed);
-                        let import = match import {
-                            Some(ImportType::Import(import)) => Some(import),
-                            _ => None,
-                        };
+
+                        let import = import.and_then(ImportOrExternCrate::import_or_glob);
                         let prev = std::mem::replace(&mut fld.import, import);
                         if let Some(import) = import {
-                            self.use_imports_values.insert(
-                                import,
-                                match prev {
-                                    Some(import) => ImportOrDef::Import(import),
-                                    None => ImportOrDef::Def(fld.def),
-                                },
-                            );
+                            self.use_imports_values
+                                .insert(import, prev.map_or(ImportOrDef::Def(fld.def), Into::into));
                         }
                         entry.insert(fld);
                         changed = true;
@@ -643,43 +667,33 @@ impl ItemScope {
             match existing {
                 Entry::Vacant(entry) => {
                     match import {
-                        Some(ImportType::Glob(_)) => {
+                        Some(ImportOrExternCrate::Glob(_)) => {
                             glob_imports.macros.insert(lookup.clone());
                         }
                         _ => _ = glob_imports.macros.remove(&lookup),
                     }
-                    let import = match import {
-                        Some(ImportType::Import(import)) => Some(import),
-                        _ => None,
-                    };
+                    let import = import.and_then(ImportOrExternCrate::import_or_glob);
                     let prev = std::mem::replace(&mut fld.import, import);
                     if let Some(import) = import {
                         self.use_imports_macros.insert(
                             import,
-                            match prev {
-                                Some(import) => ImportOrDef::Import(import),
-                                None => ImportOrDef::Def(fld.def.into()),
-                            },
+                            prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
                         );
                     }
                     entry.insert(fld);
                     changed = true;
                 }
-                Entry::Occupied(mut entry) if !matches!(import, Some(ImportType::Glob(..))) => {
+                Entry::Occupied(mut entry)
+                    if !matches!(import, Some(ImportOrExternCrate::Glob(..))) =>
+                {
                     if glob_imports.macros.remove(&lookup) {
                         cov_mark::hit!(import_shadowed);
-                        let import = match import {
-                            Some(ImportType::Import(import)) => Some(import),
-                            _ => None,
-                        };
+                        let import = import.and_then(ImportOrExternCrate::import_or_glob);
                         let prev = std::mem::replace(&mut fld.import, import);
                         if let Some(import) = import {
                             self.use_imports_macros.insert(
                                 import,
-                                match prev {
-                                    Some(import) => ImportOrDef::Import(import),
-                                    None => ImportOrDef::Def(fld.def.into()),
-                                },
+                                prev.map_or_else(|| ImportOrDef::Def(fld.def.into()), Into::into),
                             );
                         }
                         entry.insert(fld);
@@ -704,16 +718,27 @@ impl ItemScope {
             .map(|def| &mut def.vis)
             .chain(self.values.values_mut().map(|def| &mut def.vis))
             .chain(self.unnamed_trait_imports.values_mut().map(|def| &mut def.vis))
-            .for_each(|vis| {
-                *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+            .for_each(|vis| match vis {
+                &mut Visibility::Module(_, visibility_explicitness) => {
+                    *vis = Visibility::Module(this_module, visibility_explicitness)
+                }
+                Visibility::Public => {
+                    *vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+                }
             });
 
         for mac in self.macros.values_mut() {
             if matches!(mac.def, MacroId::ProcMacroId(_) if mac.import.is_none()) {
                 continue;
             }
-
-            mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit);
+            match mac.vis {
+                Visibility::Module(_, visibility_explicitness) => {
+                    mac.vis = Visibility::Module(this_module, visibility_explicitness)
+                }
+                Visibility::Public => {
+                    mac.vis = Visibility::Module(this_module, VisibilityExplicitness::Implicit)
+                }
+            }
         }
     }
 
@@ -732,20 +757,25 @@ impl ItemScope {
                 buf.push_str(" t");
                 match import {
                     Some(ImportOrExternCrate::Import(_)) => buf.push('i'),
+                    Some(ImportOrExternCrate::Glob(_)) => buf.push('g'),
                     Some(ImportOrExternCrate::ExternCrate(_)) => buf.push('e'),
                     None => (),
                 }
             }
             if let Some(Item { import, .. }) = def.values {
                 buf.push_str(" v");
-                if import.is_some() {
-                    buf.push('i');
+                match import {
+                    Some(ImportOrGlob::Import(_)) => buf.push('i'),
+                    Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+                    None => (),
                 }
             }
             if let Some(Item { import, .. }) = def.macros {
                 buf.push_str(" m");
-                if import.is_some() {
-                    buf.push('i');
+                match import {
+                    Some(ImportOrGlob::Import(_)) => buf.push('i'),
+                    Some(ImportOrGlob::Glob(_)) => buf.push('g'),
+                    None => (),
                 }
             }
             if def.is_none() {
@@ -828,7 +858,7 @@ impl PerNs {
         match def {
             ModuleDefId::ModuleId(_) => PerNs::types(def, v, import),
             ModuleDefId::FunctionId(_) => {
-                PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
             ModuleDefId::AdtId(adt) => match adt {
                 AdtId::UnionId(_) => PerNs::types(def, v, import),
@@ -843,14 +873,14 @@ impl PerNs {
             },
             ModuleDefId::EnumVariantId(_) => PerNs::both(def, def, v, import),
             ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => {
-                PerNs::values(def, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::values(def, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
             ModuleDefId::TraitId(_) => PerNs::types(def, v, import),
             ModuleDefId::TraitAliasId(_) => PerNs::types(def, v, import),
             ModuleDefId::TypeAliasId(_) => PerNs::types(def, v, import),
             ModuleDefId::BuiltinType(_) => PerNs::types(def, v, import),
             ModuleDefId::MacroId(mac) => {
-                PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::into_import))
+                PerNs::macros(mac, v, import.and_then(ImportOrExternCrate::import_or_glob))
             }
         }
     }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index afdc49a2dc5..e83ce6dc42c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -372,6 +372,7 @@ language_item_table! {
     DerefMut,                sym::deref_mut,           deref_mut_trait,            Target::Trait,          GenericRequirement::Exact(0);
     DerefTarget,             sym::deref_target,        deref_target,               Target::AssocTy,        GenericRequirement::None;
     Receiver,                sym::receiver,            receiver_trait,             Target::Trait,          GenericRequirement::None;
+    ReceiverTarget,           sym::receiver_target,     receiver_target,            Target::AssocTy,        GenericRequirement::None;
 
     Fn,                      sym::fn_,                 fn_trait,                   Target::Trait,          GenericRequirement::Exact(1);
     FnMut,                   sym::fn_mut,              fn_mut_trait,               Target::Trait,          GenericRequirement::Exact(1);
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 84c105a0a34..c78818c642c 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -114,6 +114,9 @@ pub struct ImportPathConfig {
     pub prefer_prelude: bool,
     /// If true, prefer abs path (starting with `::`) where it is available.
     pub prefer_absolute: bool,
+    /// If true, paths containing `#[unstable]` segments may be returned, but only if if there is no
+    /// stable path. This does not check, whether the item itself that is being imported is `#[unstable]`.
+    pub allow_unstable: bool,
 }
 
 #[derive(Debug)]
@@ -910,6 +913,7 @@ pub enum AssocItemId {
     ConstId(ConstId),
     TypeAliasId(TypeAliasId),
 }
+
 // FIXME: not every function, ... is actually an assoc item. maybe we should make
 // sure that you can only turn actual assoc items into AssocItemIds. This would
 // require not implementing From, and instead having some checked way of
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 1e4b42dff5f..06276335b71 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
@@ -28,7 +28,7 @@ use triomphe::Arc;
 use crate::{
     attr::Attrs,
     db::DefDatabase,
-    item_scope::{ImportId, ImportOrExternCrate, ImportType, PerNsGlobImports},
+    item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
     item_tree::{
         self, AttrOwner, FieldsShape, FileItemTreeId, ImportKind, ItemTree, ItemTreeId,
         ItemTreeNode, Macro2, MacroCall, MacroRules, Mod, ModItem, ModKind, TreeId, UseTreeKind,
@@ -208,7 +208,7 @@ struct DefCollector<'a> {
     def_map: DefMap,
     // The dependencies of the current crate, including optional deps like `test`.
     deps: FxHashMap<Name, Dependency>,
-    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, UseId)>>,
+    glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
     unresolved_imports: Vec<ImportDirective>,
     indeterminate_imports: Vec<(ImportDirective, PerNs)>,
     unresolved_macros: Vec<MacroDirective>,
@@ -524,11 +524,7 @@ impl DefCollector<'_> {
 
         match per_ns.types {
             Some(Item { def: ModuleDefId::ModuleId(m), import, .. }) => {
-                // FIXME: This should specifically look for a glob import somehow and record that here
-                self.def_map.prelude = Some((
-                    m,
-                    import.and_then(ImportOrExternCrate::into_import).map(|it| it.import),
-                ));
+                self.def_map.prelude = Some((m, import.and_then(ImportOrExternCrate::use_)));
             }
             types => {
                 tracing::debug!(
@@ -845,13 +841,14 @@ impl DefCollector<'_> {
                     def.values = None;
                     def.macros = None;
                 }
-                let imp = ImportType::Import(ImportId { import: id, idx: use_tree });
+                let imp = ImportOrExternCrate::Import(ImportId { use_: id, idx: use_tree });
                 tracing::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
 
                 self.update(module_id, &[(name.cloned(), def)], vis, Some(imp));
             }
-            ImportSource { kind: ImportKind::Glob, id, is_prelude, .. } => {
+            ImportSource { kind: ImportKind::Glob, id, is_prelude, use_tree } => {
                 tracing::debug!("glob import: {:?}", import);
+                let glob = GlobId { use_: id, idx: use_tree };
                 match def.take_types() {
                     Some(ModuleDefId::ModuleId(m)) => {
                         if is_prelude {
@@ -875,7 +872,12 @@ impl DefCollector<'_> {
                                 .filter(|(_, res)| !res.is_none())
                                 .collect::<Vec<_>>();
 
-                            self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+                            self.update(
+                                module_id,
+                                &items,
+                                vis,
+                                Some(ImportOrExternCrate::Glob(glob)),
+                            );
                         } else {
                             // glob import from same crate => we do an initial
                             // import, and then need to propagate any further
@@ -907,11 +909,16 @@ impl DefCollector<'_> {
                                 .filter(|(_, res)| !res.is_none())
                                 .collect::<Vec<_>>();
 
-                            self.update(module_id, &items, vis, Some(ImportType::Glob(id)));
+                            self.update(
+                                module_id,
+                                &items,
+                                vis,
+                                Some(ImportOrExternCrate::Glob(glob)),
+                            );
                             // record the glob import in case we add further items
-                            let glob = self.glob_imports.entry(m.local_id).or_default();
-                            match glob.iter_mut().find(|(mid, _, _)| *mid == module_id) {
-                                None => glob.push((module_id, vis, id)),
+                            let glob_imports = self.glob_imports.entry(m.local_id).or_default();
+                            match glob_imports.iter_mut().find(|(mid, _, _)| *mid == module_id) {
+                                None => glob_imports.push((module_id, vis, glob)),
                                 Some((_, old_vis, _)) => {
                                     if let Some(new_vis) = old_vis.max(vis, &self.def_map) {
                                         *old_vis = new_vis;
@@ -944,7 +951,12 @@ impl DefCollector<'_> {
                             (Some(name), res)
                         })
                         .collect::<Vec<_>>();
-                        self.update(module_id, &resolutions, vis, Some(ImportType::Glob(id)));
+                        self.update(
+                            module_id,
+                            &resolutions,
+                            vis,
+                            Some(ImportOrExternCrate::Glob(glob)),
+                        );
                     }
                     Some(d) => {
                         tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -964,7 +976,7 @@ impl DefCollector<'_> {
         resolutions: &[(Option<Name>, PerNs)],
         // Visibility this import will have
         vis: Visibility,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
     ) {
         self.db.unwind_if_cancelled();
         self.update_recursive(module_id, resolutions, vis, import, 0)
@@ -978,7 +990,7 @@ impl DefCollector<'_> {
         // All resolutions are imported with this visibility; the visibilities in
         // the `PerNs` values are ignored and overwritten
         vis: Visibility,
-        import: Option<ImportType>,
+        import: Option<ImportOrExternCrate>,
         depth: usize,
     ) {
         if GLOB_RECURSION_LIMIT.check(depth).is_err() {
@@ -994,8 +1006,10 @@ impl DefCollector<'_> {
                         self.push_res_and_update_glob_vis(module_id, name, *res, vis, import);
                 }
                 None => {
-                    let tr = match res.take_types() {
-                        Some(ModuleDefId::TraitId(tr)) => tr,
+                    let (tr, import) = match res.take_types_full() {
+                        Some(Item { def: ModuleDefId::TraitId(tr), vis: _, import }) => {
+                            (tr, import)
+                        }
                         Some(other) => {
                             tracing::debug!("non-trait `_` import of {:?}", other);
                             continue;
@@ -1021,7 +1035,11 @@ impl DefCollector<'_> {
 
                     if should_update {
                         changed = true;
-                        self.def_map.modules[module_id].scope.push_unnamed_trait(tr, vis);
+                        self.def_map.modules[module_id].scope.push_unnamed_trait(
+                            tr,
+                            vis,
+                            import.and_then(ImportOrExternCrate::import),
+                        );
                     }
                 }
             }
@@ -1043,13 +1061,13 @@ impl DefCollector<'_> {
             .cloned()
             .collect::<Vec<_>>();
 
-        for (glob_importing_module, glob_import_vis, use_) in glob_imports {
+        for (glob_importing_module, glob_import_vis, glob) in glob_imports {
             let vis = glob_import_vis.min(vis, &self.def_map).unwrap_or(glob_import_vis);
             self.update_recursive(
                 glob_importing_module,
                 resolutions,
                 vis,
-                Some(ImportType::Glob(use_)),
+                Some(ImportOrExternCrate::Glob(glob)),
                 depth + 1,
             );
         }
@@ -1061,7 +1079,7 @@ impl DefCollector<'_> {
         name: &Name,
         mut defs: PerNs,
         vis: Visibility,
-        def_import_type: Option<ImportType>,
+        def_import_type: Option<ImportOrExternCrate>,
     ) -> bool {
         // `extern crate crate_name` things can be re-exported as `pub use crate_name`.
         // But they cannot be re-exported as `pub use self::crate_name`, `pub use crate::crate_name`
@@ -1074,10 +1092,10 @@ impl DefCollector<'_> {
                 let Some(ImportOrExternCrate::ExternCrate(_)) = def.import else {
                     return false;
                 };
-                let Some(ImportType::Import(id)) = def_import_type else {
+                let Some(ImportOrExternCrate::Import(id)) = def_import_type else {
                     return false;
                 };
-                let use_id = id.import.lookup(self.db).id;
+                let use_id = id.use_.lookup(self.db).id;
                 let item_tree = use_id.item_tree(self.db);
                 let use_kind = item_tree[use_id.value].use_tree.kind();
                 let UseTreeKind::Single { path, .. } = use_kind else {
@@ -1100,7 +1118,7 @@ impl DefCollector<'_> {
 
         let mut changed = false;
 
-        if let Some(ImportType::Glob(_)) = def_import_type {
+        if let Some(ImportOrExternCrate::Glob(_)) = def_import_type {
             let prev_defs = self.def_map[module_id].scope.get(name);
 
             // Multiple globs may import the same item and they may override visibility from
@@ -1727,7 +1745,7 @@ impl ModCollector<'_, '_> {
                                 ),
                             )],
                             vis,
-                            Some(ImportType::ExternCrate(id)),
+                            Some(ImportOrExternCrate::ExternCrate(id)),
                         );
                     } else {
                         if let Some(name) = name {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
index ab4ffbb2c1e..d7e4ca41cd5 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/mod_resolution.rs
@@ -4,7 +4,6 @@ use base_db::AnchoredPath;
 use hir_expand::{name::Name, HirFileIdExt};
 use limit::Limit;
 use span::EditionedFileId;
-use syntax::ToSmolStr as _;
 
 use crate::{db::DefDatabase, HirFileId};
 
@@ -35,7 +34,7 @@ impl ModDir {
         let path = match attr_path {
             None => {
                 let mut path = self.dir_path.clone();
-                path.push(&name.unescaped().display_no_db().to_smolstr());
+                path.push(name.as_str());
                 path
             }
             Some(attr_path) => {
@@ -66,7 +65,7 @@ impl ModDir {
         name: &Name,
         attr_path: Option<&str>,
     ) -> Result<(EditionedFileId, bool, ModDir), Box<[String]>> {
-        let name = name.unescaped();
+        let name = name.as_str();
 
         let mut candidate_files = ArrayVec::<_, 2>::new();
         match attr_path {
@@ -74,16 +73,8 @@ impl ModDir {
                 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
             }
             None => {
-                candidate_files.push(format!(
-                    "{}{}.rs",
-                    self.dir_path.0,
-                    name.display(db.upcast())
-                ));
-                candidate_files.push(format!(
-                    "{}{}/mod.rs",
-                    self.dir_path.0,
-                    name.display(db.upcast())
-                ));
+                candidate_files.push(format!("{}{}.rs", self.dir_path.0, name));
+                candidate_files.push(format!("{}{}/mod.rs", self.dir_path.0, name));
             }
         };
 
@@ -97,7 +88,7 @@ impl ModDir {
                 let dir_path = if root_dir_owner {
                     DirPath::empty()
                 } else {
-                    DirPath::new(format!("{}/", name.display(db.upcast())))
+                    DirPath::new(format!("{}/", name))
                 };
                 if let Some(mod_dir) = self.child(dir_path, !root_dir_owner) {
                     return Ok((
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
index 318aee04f7b..73fc6787bfe 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs
@@ -103,8 +103,8 @@ mod a {
             c: t
 
             crate::a::b::c
-            A: v
-            b: t
+            A: vg
+            b: tg
         "#]],
     );
 }
@@ -256,8 +256,8 @@ pub enum Foo { Bar, Baz }
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
         "#]],
     );
 }
@@ -421,10 +421,10 @@ pub struct NotExported;
 "#,
         expect![[r#"
             crate
-            Exported: t v
-            PublicItem: t v
-            allowed_reexport: t
-            exported: t
+            Exported: tg vg
+            PublicItem: tg vg
+            allowed_reexport: tg
+            exported: tg
             not_allowed_reexport1: _
             not_allowed_reexport2: _
         "#]],
@@ -692,7 +692,7 @@ mod b {
             b: t
 
             crate::a
-            T: t v
+            T: t vg
 
             crate::b
             T: v
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
index 8963a576794..ddb9d4a134d 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs
@@ -18,9 +18,9 @@ pub struct Baz;
 "#,
         expect![[r#"
             crate
-            Baz: t v
-            Foo: t v
-            bar: t
+            Baz: tg vg
+            Foo: tg vg
+            bar: tg
             foo: t
 
             crate::foo
@@ -53,20 +53,20 @@ pub use super::*;
 "#,
         expect![[r#"
             crate
-            Baz: t v
-            Foo: t v
-            bar: t
+            Baz: tg vg
+            Foo: tg vg
+            bar: tg
             foo: t
 
             crate::foo
-            Baz: t v
+            Baz: tg vg
             Foo: t v
             bar: t
 
             crate::foo::bar
             Baz: t v
-            Foo: t v
-            bar: t
+            Foo: tg vg
+            bar: tg
         "#]],
     );
 }
@@ -91,20 +91,20 @@ pub use super::*;
 ",
         expect![[r#"
             crate
-            Baz: t v
-            bar: t
+            Baz: tg vg
+            bar: tg
             foo: t
 
             crate::foo
-            Baz: t v
+            Baz: tg vg
             PrivateStructFoo: t v
             bar: t
 
             crate::foo::bar
             Baz: t v
             PrivateStructBar: t v
-            PrivateStructFoo: t v
-            bar: t
+            PrivateStructFoo: tg vg
+            bar: tg
         "#]],
     );
 }
@@ -130,9 +130,9 @@ pub(crate) struct PubCrateStruct;
 ",
         expect![[r#"
             crate
-            Foo: t
-            PubCrateStruct: t v
-            bar: t
+            Foo: tg
+            PubCrateStruct: tg vg
+            bar: tg
             foo: t
 
             crate::foo
@@ -160,7 +160,7 @@ pub struct Baz;
 "#,
         expect![[r#"
             crate
-            Baz: t v
+            Baz: tg vg
         "#]],
     );
 }
@@ -178,7 +178,7 @@ struct Foo;
 "#,
         expect![[r#"
             crate
-            Baz: t v
+            Baz: tg vg
         "#]],
     );
 }
@@ -193,8 +193,8 @@ use self::Foo::*;
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
             Foo: t
         "#]],
     );
@@ -210,8 +210,8 @@ use self::Foo::{*};
 "#,
         expect![[r#"
             crate
-            Bar: t v
-            Baz: t v
+            Bar: tg vg
+            Baz: tg vg
             Foo: t
         "#]],
     );
@@ -359,7 +359,7 @@ use event::Event;
             event: t
 
             crate::event
-            Event: t v
+            Event: t vg
             serenity: t
 
             crate::event::serenity
@@ -388,10 +388,10 @@ use reexport::*;
 "#,
         expect![[r#"
             crate
-            Trait: t
+            Trait: tg
             defs: t
-            function: v
-            makro: m
+            function: vg
+            makro: mg
             reexport: t
 
             crate::defs
@@ -400,10 +400,10 @@ use reexport::*;
             makro: m
 
             crate::reexport
-            Trait: t
-            function: v
+            Trait: tg
+            function: vg
             inner: t
-            makro: m
+            makro: mg
 
             crate::reexport::inner
             Trait: ti
@@ -442,12 +442,12 @@ mod glob_target {
             ShouldBePrivate: t v
 
             crate::outer
-            ShouldBePrivate: t v
+            ShouldBePrivate: tg vg
             inner_superglob: t
 
             crate::outer::inner_superglob
-            ShouldBePrivate: t v
-            inner_superglob: t
+            ShouldBePrivate: tg vg
+            inner_superglob: tg
         "#]],
     );
 }
@@ -473,20 +473,20 @@ use reexport_2::*;
 "#,
         expect![[r#"
             crate
-            Placeholder: t v
+            Placeholder: tg vg
             libs: t
-            reexport_1: t
+            reexport_1: tg
             reexport_2: t
 
             crate::libs
             Placeholder: t v
 
             crate::reexport_2
-            Placeholder: t v
+            Placeholder: tg vg
             reexport_1: t
 
             crate::reexport_2::reexport_1
-            Placeholder: t v
+            Placeholder: tg vg
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
index a05c4dcf9bd..610886d55f4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs
@@ -97,9 +97,9 @@ macro_rules! structs {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -130,9 +130,9 @@ macro_rules! structs {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -169,9 +169,9 @@ macro_rules! inner {
             bar: t
 
             crate::bar
-            Bar: t
-            Foo: t
-            bar: t
+            Bar: tg
+            Foo: tg
+            bar: tg
         "#]],
     );
 }
@@ -794,7 +794,7 @@ pub trait Clone {}
 "#,
         expect![[r#"
             crate
-            Clone: t m
+            Clone: tg mg
         "#]],
     );
 }
@@ -1075,9 +1075,9 @@ macro_rules! mbe {
 "#,
         expect![[r#"
             crate
-            DummyTrait: m
-            attribute_macro: m
-            function_like_macro: m
+            DummyTrait: mg
+            attribute_macro: mg
+            function_like_macro: mg
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
index 899dd4afffe..c2d3f67f17e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/per_ns.rs
@@ -6,7 +6,7 @@
 use bitflags::bitflags;
 
 use crate::{
-    item_scope::{ImportId, ImportOrExternCrate, ItemInNs},
+    item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob, ItemInNs},
     visibility::Visibility,
     MacroId, ModuleDefId,
 };
@@ -36,8 +36,8 @@ pub struct Item<Def, Import = ImportId> {
 }
 
 pub type TypesItem = Item<ModuleDefId, ImportOrExternCrate>;
-pub type ValuesItem = Item<ModuleDefId>;
-pub type MacrosItem = Item<MacroId>;
+pub type ValuesItem = Item<ModuleDefId, ImportOrGlob>;
+pub type MacrosItem = Item<MacroId, ImportOrGlob>;
 
 #[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
 pub struct PerNs {
@@ -59,7 +59,7 @@ impl PerNs {
         PerNs { types: None, values: None, macros: None }
     }
 
-    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportId>) -> PerNs {
+    pub fn values(def: ModuleDefId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
         PerNs { types: None, values: Some(Item { def, vis, import }), macros: None }
     }
 
@@ -78,13 +78,13 @@ impl PerNs {
             values: Some(Item {
                 def: values,
                 vis,
-                import: import.and_then(ImportOrExternCrate::into_import),
+                import: import.and_then(ImportOrExternCrate::import_or_glob),
             }),
             macros: None,
         }
     }
 
-    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportId>) -> PerNs {
+    pub fn macros(def: MacroId, vis: Visibility, import: Option<ImportOrGlob>) -> PerNs {
         PerNs { types: None, values: None, macros: Some(Item { def, vis, import }) }
     }
 
@@ -108,7 +108,7 @@ impl PerNs {
         self.values.map(|it| it.def)
     }
 
-    pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportId>)> {
+    pub fn take_values_import(self) -> Option<(ModuleDefId, Option<ImportOrGlob>)> {
         self.values.map(|it| (it.def, it.import))
     }
 
@@ -116,7 +116,7 @@ impl PerNs {
         self.macros.map(|it| it.def)
     }
 
-    pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportId>)> {
+    pub fn take_macros_import(self) -> Option<(MacroId, Option<ImportOrGlob>)> {
         self.macros.map(|it| (it.def, it.import))
     }
 
@@ -159,14 +159,12 @@ impl PerNs {
             .map(|it| (ItemInNs::Types(it.def), it.import))
             .into_iter()
             .chain(
-                self.values.map(|it| {
-                    (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::Import))
-                }),
+                self.values
+                    .map(|it| (ItemInNs::Values(it.def), it.import.map(ImportOrExternCrate::from))),
             )
             .chain(
-                self.macros.map(|it| {
-                    (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::Import))
-                }),
+                self.macros
+                    .map(|it| (ItemInNs::Macros(it.def), it.import.map(ImportOrExternCrate::from))),
             )
     }
 }
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 0b9b6da8d51..8c556d8a8c3 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -19,7 +19,7 @@ use crate::{
     db::DefDatabase,
     generics::{GenericParams, TypeOrConstParamData},
     hir::{BindingId, ExprId, LabelId},
-    item_scope::{BuiltinShadowMode, ImportId, ImportOrExternCrate, BUILTIN_SCOPE},
+    item_scope::{BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, BUILTIN_SCOPE},
     lang_item::LangItemTarget,
     nameres::{DefMap, MacroSubNs, ResolvePathResultPrefixInfo},
     path::{ModPath, Path, PathKind},
@@ -107,7 +107,7 @@ pub enum TypeNs {
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum ResolveValueResult {
-    ValueNs(ValueNs, Option<ImportId>),
+    ValueNs(ValueNs, Option<ImportOrGlob>),
     Partial(TypeNs, usize, Option<ImportOrExternCrate>),
 }
 
@@ -485,7 +485,7 @@ impl Resolver {
         db: &dyn DefDatabase,
         path: &ModPath,
         expected_macro_kind: Option<MacroSubNs>,
-    ) -> Option<(MacroId, Option<ImportId>)> {
+    ) -> Option<(MacroId, Option<ImportOrGlob>)> {
         let (item_map, module) = self.item_scope();
         item_map
             .resolve_path(db, module, path, BuiltinShadowMode::Other, expected_macro_kind)
@@ -1014,7 +1014,7 @@ impl ModuleItemMap {
     }
 }
 
-fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportId>)> {
+fn to_value_ns(per_ns: PerNs) -> Option<(ValueNs, Option<ImportOrGlob>)> {
     let (def, import) = per_ns.take_values_import()?;
     let res = match def {
         ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
index 89eae862bd9..f0cf7ebf479 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs
@@ -23,15 +23,6 @@ pub struct ModPath {
     segments: SmallVec<[Name; 1]>,
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct UnescapedModPath<'a>(&'a ModPath);
-
-impl<'a> UnescapedModPath<'a> {
-    pub fn display(&'a self, db: &'a dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
-        UnescapedDisplay { db, path: self }
-    }
-}
-
 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum PathKind {
     Plain,
@@ -135,9 +126,11 @@ impl ModPath {
             _ => None,
         }
     }
-
-    pub fn unescaped(&self) -> UnescapedModPath<'_> {
-        UnescapedModPath(self)
+    pub fn display_verbatim<'a>(
+        &'a self,
+        db: &'a dyn crate::db::ExpandDatabase,
+    ) -> impl fmt::Display + 'a {
+        Display { db, path: self, edition: None }
     }
 
     pub fn display<'a>(
@@ -145,7 +138,7 @@ impl ModPath {
         db: &'a dyn crate::db::ExpandDatabase,
         edition: Edition,
     ) -> impl fmt::Display + 'a {
-        Display { db, path: self, edition }
+        Display { db, path: self, edition: Some(edition) }
     }
 }
 
@@ -158,23 +151,12 @@ impl Extend<Name> for ModPath {
 struct Display<'a> {
     db: &'a dyn ExpandDatabase,
     path: &'a ModPath,
-    edition: Edition,
+    edition: Option<Edition>,
 }
 
 impl fmt::Display for Display<'_> {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path, f, Escape::IfNeeded(self.edition))
-    }
-}
-
-struct UnescapedDisplay<'a> {
-    db: &'a dyn ExpandDatabase,
-    path: &'a UnescapedModPath<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        display_fmt_path(self.db, self.path.0, f, Escape::No)
+        display_fmt_path(self.db, self.path, f, self.edition)
     }
 }
 
@@ -184,16 +166,11 @@ impl From<Name> for ModPath {
     }
 }
 
-enum Escape {
-    No,
-    IfNeeded(Edition),
-}
-
 fn display_fmt_path(
     db: &dyn ExpandDatabase,
     path: &ModPath,
     f: &mut fmt::Formatter<'_>,
-    escaped: Escape,
+    edition: Option<Edition>,
 ) -> fmt::Result {
     let mut first_segment = true;
     let mut add_segment = |s| -> fmt::Result {
@@ -221,10 +198,10 @@ fn display_fmt_path(
             f.write_str("::")?;
         }
         first_segment = false;
-        match escaped {
-            Escape::IfNeeded(edition) => segment.display(db, edition).fmt(f)?,
-            Escape::No => segment.unescaped().display(db).fmt(f)?,
-        }
+        match edition {
+            Some(edition) => segment.display(db, edition).fmt(f)?,
+            None => fmt::Display::fmt(segment.as_str(), f)?,
+        };
     }
     Ok(())
 }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index cc53d2e34aa..848870c3a38 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -4,8 +4,8 @@ use std::fmt;
 
 use intern::{sym, Symbol};
 use span::{Edition, SyntaxContextId};
-use syntax::ast;
 use syntax::utils::is_raw_identifier;
+use syntax::{ast, format_smolstr};
 
 /// `Name` is a wrapper around string, which is used in hir for both references
 /// and declarations. In theory, names should also carry hygiene info, but we are
@@ -51,33 +51,26 @@ impl PartialEq<Symbol> for Name {
     }
 }
 
+impl PartialEq<&Symbol> for Name {
+    fn eq(&self, &sym: &&Symbol) -> bool {
+        self.symbol == *sym
+    }
+}
+
 impl PartialEq<Name> for Symbol {
     fn eq(&self, name: &Name) -> bool {
         *self == name.symbol
     }
 }
 
-/// Wrapper of `Name` to print the name without "r#" even when it is a raw identifier.
-#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct UnescapedName<'a>(&'a Name);
-
-impl<'a> UnescapedName<'a> {
-    pub fn display(self, db: &dyn crate::db::ExpandDatabase) -> impl fmt::Display + 'a {
-        _ = db;
-        UnescapedDisplay { name: self }
-    }
-    #[doc(hidden)]
-    pub fn display_no_db(self) -> impl fmt::Display + 'a {
-        UnescapedDisplay { name: self }
+impl PartialEq<Name> for &Symbol {
+    fn eq(&self, name: &Name) -> bool {
+        **self == name.symbol
     }
 }
 
 impl Name {
-    /// Note: this is private to make creating name from random string hard.
-    /// Hopefully, this should allow us to integrate hygiene cleaner in the
-    /// future, and to switch to interned representation of names.
     fn new_text(text: &str) -> Name {
-        debug_assert!(!text.starts_with("r#"));
         Name { symbol: Symbol::intern(text), ctx: () }
     }
 
@@ -87,12 +80,15 @@ impl Name {
         // Can't do that for all `SyntaxContextId`s because it breaks Salsa.
         ctx.remove_root_edition();
         _ = ctx;
-        Self::new_text(text)
+        match text.strip_prefix("r#") {
+            Some(text) => Self::new_text(text),
+            None => Self::new_text(text),
+        }
     }
 
     pub fn new_root(text: &str) -> Name {
         // The edition doesn't matter for hygiene.
-        Self::new(text.trim_start_matches("r#"), SyntaxContextId::root(Edition::Edition2015))
+        Self::new(text, SyntaxContextId::root(Edition::Edition2015))
     }
 
     pub fn new_tuple_field(idx: usize) -> Name {
@@ -119,12 +115,22 @@ impl Name {
     }
 
     pub fn new_lifetime(lt: &ast::Lifetime) -> Name {
-        Self::new_text(lt.text().as_str().trim_start_matches("r#"))
+        let text = lt.text();
+        match text.strip_prefix("'r#") {
+            Some(text) => Self::new_text(&format_smolstr!("'{text}")),
+            None => Self::new_text(text.as_str()),
+        }
+    }
+
+    pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
+        debug_assert!(!symbol.as_str().starts_with("r#"));
+        _ = ctx;
+        Self { symbol, ctx: () }
     }
 
-    /// Resolve a name from the text of token.
-    fn resolve(raw_text: &str) -> Name {
-        Name::new_text(raw_text.trim_start_matches("r#"))
+    // FIXME: This needs to go once we have hygiene
+    pub fn new_symbol_root(sym: Symbol) -> Self {
+        Self::new_symbol(sym, SyntaxContextId::root(Edition::Edition2015))
     }
 
     /// A fake name for things missing in the source code.
@@ -161,22 +167,19 @@ impl Name {
         self.symbol.as_str().parse().ok()
     }
 
+    /// Whether this name needs to be escaped in the given edition via `r#`.
+    pub fn needs_escape(&self, edition: Edition) -> bool {
+        is_raw_identifier(self.symbol.as_str(), edition)
+    }
+
     /// Returns the text this name represents if it isn't a tuple field.
     ///
     /// Do not use this for user-facing text, use `display` instead to handle editions properly.
+    // FIXME: This should take a database argument to hide the interning
     pub fn as_str(&self) -> &str {
         self.symbol.as_str()
     }
 
-    // FIXME: Remove this
-    pub fn unescaped(&self) -> UnescapedName<'_> {
-        UnescapedName(self)
-    }
-
-    pub fn needs_escape(&self, edition: Edition) -> bool {
-        is_raw_identifier(self.symbol.as_str(), edition)
-    }
-
     pub fn display<'a>(
         &'a self,
         db: &dyn crate::db::ExpandDatabase,
@@ -186,7 +189,7 @@ impl Name {
         self.display_no_db(edition)
     }
 
-    // FIXME: Remove this
+    // FIXME: Remove this in favor of `display`, see fixme on `as_str`
     #[doc(hidden)]
     pub fn display_no_db(&self, edition: Edition) -> impl fmt::Display + '_ {
         Display { name: self, needs_escaping: is_raw_identifier(self.symbol.as_str(), edition) }
@@ -195,24 +198,6 @@ impl Name {
     pub fn symbol(&self) -> &Symbol {
         &self.symbol
     }
-
-    pub fn new_symbol(symbol: Symbol, ctx: SyntaxContextId) -> Self {
-        debug_assert!(!symbol.as_str().starts_with("r#"));
-        _ = ctx;
-        Self { symbol, ctx: () }
-    }
-
-    // FIXME: This needs to go once we have hygiene
-    pub fn new_symbol_root(sym: Symbol) -> Self {
-        debug_assert!(!sym.as_str().starts_with("r#"));
-        Self { symbol: sym, ctx: () }
-    }
-
-    // FIXME: Remove this
-    #[inline]
-    pub fn eq_ident(&self, ident: &str) -> bool {
-        self.as_str() == ident.trim_start_matches("r#")
-    }
 }
 
 struct Display<'a> {
@@ -229,17 +214,6 @@ impl fmt::Display for Display<'_> {
     }
 }
 
-struct UnescapedDisplay<'a> {
-    name: UnescapedName<'a>,
-}
-
-impl fmt::Display for UnescapedDisplay<'_> {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        let symbol = self.name.0.symbol.as_str();
-        fmt::Display::fmt(symbol, f)
-    }
-}
-
 pub trait AsName {
     fn as_name(&self) -> Name;
 }
@@ -248,14 +222,14 @@ impl AsName for ast::NameRef {
     fn as_name(&self) -> Name {
         match self.as_tuple_field() {
             Some(idx) => Name::new_tuple_field(idx),
-            None => Name::resolve(&self.text()),
+            None => Name::new_root(&self.text()),
         }
     }
 }
 
 impl AsName for ast::Name {
     fn as_name(&self) -> Name {
-        Name::resolve(&self.text())
+        Name::new_root(&self.text())
     }
 }
 
@@ -270,7 +244,7 @@ impl AsName for ast::NameOrNameRef {
 
 impl<Span> AsName for tt::Ident<Span> {
     fn as_name(&self) -> Name {
-        Name::resolve(self.sym.as_str())
+        Name::new_root(self.sym.as_str())
     }
 }
 
@@ -288,6 +262,6 @@ impl AsName for ast::FieldKind {
 
 impl AsName for base_db::Dependency {
     fn as_name(&self) -> Name {
-        Name::new_text(&self.name)
+        Name::new_root(&self.name)
     }
 }
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 2b5342314a6..62feca5f8cb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -17,7 +17,7 @@ use crate::{
     TraitEnvironment, Ty, TyBuilder, TyKind,
 };
 
-static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(10);
+static AUTODEREF_RECURSION_LIMIT: Limit = Limit::new(20);
 
 #[derive(Debug)]
 pub(crate) enum AutoderefKind {
@@ -39,7 +39,7 @@ pub fn autoderef(
 ) -> impl Iterator<Item = Ty> {
     let mut table = InferenceTable::new(db, env);
     let ty = table.instantiate_canonical(ty);
-    let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false);
+    let mut autoderef = Autoderef::new_no_tracking(&mut table, ty, false, false);
     let mut v = Vec::new();
     while let Some((ty, _steps)) = autoderef.next() {
         // `ty` may contain unresolved inference variables. Since there's no chance they would be
@@ -49,7 +49,7 @@ pub fn autoderef(
         // If the deref chain contains a cycle (e.g. `A` derefs to `B` and `B` derefs to `A`), we
         // would revisit some already visited types. Stop here to avoid duplication.
         //
-        // XXX: The recursion limit for `Autoderef` is currently 10, so `Vec::contains()` shouldn't
+        // XXX: The recursion limit for `Autoderef` is currently 20, so `Vec::contains()` shouldn't
         // be too expensive. Replace this duplicate check with `FxHashSet` if it proves to be more
         // performant.
         if v.contains(&resolved) {
@@ -89,12 +89,18 @@ pub(crate) struct Autoderef<'table, 'db, T = Vec<(AutoderefKind, Ty)>> {
     at_start: bool,
     steps: T,
     explicit: bool,
+    use_receiver_trait: bool,
 }
 
 impl<'table, 'db> Autoderef<'table, 'db> {
-    pub(crate) fn new(table: &'table mut InferenceTable<'db>, ty: Ty, explicit: bool) -> Self {
+    pub(crate) fn new(
+        table: &'table mut InferenceTable<'db>,
+        ty: Ty,
+        explicit: bool,
+        use_receiver_trait: bool,
+    ) -> Self {
         let ty = table.resolve_ty_shallow(&ty);
-        Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit }
+        Autoderef { table, ty, at_start: true, steps: Vec::new(), explicit, use_receiver_trait }
     }
 
     pub(crate) fn steps(&self) -> &[(AutoderefKind, Ty)] {
@@ -107,9 +113,10 @@ impl<'table, 'db> Autoderef<'table, 'db, usize> {
         table: &'table mut InferenceTable<'db>,
         ty: Ty,
         explicit: bool,
+        use_receiver_trait: bool,
     ) -> Self {
         let ty = table.resolve_ty_shallow(&ty);
-        Autoderef { table, ty, at_start: true, steps: 0, explicit }
+        Autoderef { table, ty, at_start: true, steps: 0, explicit, use_receiver_trait }
     }
 }
 
@@ -137,7 +144,8 @@ impl<T: TrackAutoderefSteps> Iterator for Autoderef<'_, '_, T> {
             return None;
         }
 
-        let (kind, new_ty) = autoderef_step(self.table, self.ty.clone(), self.explicit)?;
+        let (kind, new_ty) =
+            autoderef_step(self.table, self.ty.clone(), self.explicit, self.use_receiver_trait)?;
 
         self.steps.push(kind, &self.ty);
         self.ty = new_ty;
@@ -150,11 +158,12 @@ pub(crate) fn autoderef_step(
     table: &mut InferenceTable<'_>,
     ty: Ty,
     explicit: bool,
+    use_receiver_trait: bool,
 ) -> Option<(AutoderefKind, Ty)> {
     if let Some(derefed) = builtin_deref(table.db, &ty, explicit) {
         Some((AutoderefKind::Builtin, table.resolve_ty_shallow(derefed)))
     } else {
-        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty)?))
+        Some((AutoderefKind::Overloaded, deref_by_trait(table, ty, use_receiver_trait)?))
     }
 }
 
@@ -176,6 +185,7 @@ pub(crate) fn builtin_deref<'ty>(
 pub(crate) fn deref_by_trait(
     table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>,
     ty: Ty,
+    use_receiver_trait: bool,
 ) -> Option<Ty> {
     let _p = tracing::info_span!("deref_by_trait").entered();
     if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() {
@@ -183,14 +193,25 @@ pub(crate) fn deref_by_trait(
         return None;
     }
 
-    let deref_trait =
-        db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())?;
+    let trait_id = || {
+        if use_receiver_trait {
+            if let Some(receiver) =
+                db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
+            {
+                return Some(receiver);
+            }
+        }
+        // Old rustc versions might not have `Receiver` trait.
+        // Fallback to `Deref` if they don't
+        db.lang_item(table.trait_env.krate, LangItem::Deref).and_then(|l| l.as_trait())
+    };
+    let trait_id = trait_id()?;
     let target = db
-        .trait_data(deref_trait)
+        .trait_data(trait_id)
         .associated_type_by_name(&Name::new_symbol_root(sym::Target.clone()))?;
 
     let projection = {
-        let b = TyBuilder::subst_for_def(db, deref_trait, None);
+        let b = TyBuilder::subst_for_def(db, trait_id, None);
         if b.remaining() != 1 {
             // the Target type + Deref trait should only have one generic parameter,
             // namely Deref's Self type
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 4991d173b9c..774991560e9 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
@@ -231,8 +231,7 @@ impl<'a> DeclValidator<'a> {
             .filter_map(|(pat_id, pat)| match pat {
                 Pat::Bind { id, .. } => {
                     let bind_name = &body.bindings[*id].name;
-                    let mut suggested_text =
-                        to_lower_snake_case(&bind_name.unescaped().display_no_db().to_smolstr())?;
+                    let mut suggested_text = to_lower_snake_case(bind_name.as_str())?;
                     if is_raw_identifier(&suggested_text, edition) {
                         suggested_text.insert_str(0, "r#");
                     }
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 3545bf76776..ae8fbe2ce6d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -34,6 +34,7 @@ use rustc_apfloat::{
     ieee::{Half as f16, Quad as f128},
     Float,
 };
+use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use span::Edition;
 use stdx::never;
@@ -87,6 +88,35 @@ pub struct HirFormatter<'a> {
     omit_verbose_types: bool,
     closure_style: ClosureStyle,
     display_target: DisplayTarget,
+    bounds_formatting_ctx: BoundsFormattingCtx,
+}
+
+#[derive(Default)]
+enum BoundsFormattingCtx {
+    Entered {
+        /// We can have recursive bounds like the following case:
+        /// ```rust
+        /// where
+        ///     T: Foo,
+        ///     T::FooAssoc: Baz<<T::FooAssoc as Bar>::BarAssoc> + Bar
+        /// ```
+        /// So, record the projection types met while formatting bounds and
+        //. prevent recursing into their bounds to avoid infinite loops.
+        projection_tys_met: FxHashSet<ProjectionTy>,
+    },
+    #[default]
+    Exited,
+}
+
+impl BoundsFormattingCtx {
+    fn contains(&mut self, proj: &ProjectionTy) -> bool {
+        match self {
+            BoundsFormattingCtx::Entered { projection_tys_met } => {
+                projection_tys_met.contains(proj)
+            }
+            BoundsFormattingCtx::Exited => false,
+        }
+    }
 }
 
 impl HirFormatter<'_> {
@@ -97,6 +127,30 @@ impl HirFormatter<'_> {
     fn end_location_link(&mut self) {
         self.fmt.end_location_link();
     }
+
+    fn format_bounds_with<T, F: FnOnce(&mut Self) -> T>(
+        &mut self,
+        target: ProjectionTy,
+        format_bounds: F,
+    ) -> T {
+        match self.bounds_formatting_ctx {
+            BoundsFormattingCtx::Entered { ref mut projection_tys_met } => {
+                projection_tys_met.insert(target);
+                format_bounds(self)
+            }
+            BoundsFormattingCtx::Exited => {
+                let mut projection_tys_met = FxHashSet::default();
+                projection_tys_met.insert(target);
+                self.bounds_formatting_ctx = BoundsFormattingCtx::Entered { projection_tys_met };
+                let res = format_bounds(self);
+                // Since we want to prevent only the infinite recursions in bounds formatting
+                // and do not want to skip formatting of other separate bounds, clear context
+                // when exiting the formatting of outermost bounds
+                self.bounds_formatting_ctx = BoundsFormattingCtx::Exited;
+                res
+            }
+        }
+    }
 }
 
 pub trait HirDisplay {
@@ -220,6 +274,7 @@ pub trait HirDisplay {
             closure_style: ClosureStyle::ImplFn,
             display_target: DisplayTarget::SourceCode { module_id, allow_opaque },
             show_container_bounds: false,
+            bounds_formatting_ctx: Default::default(),
         }) {
             Ok(()) => {}
             Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"),
@@ -427,6 +482,7 @@ impl<T: HirDisplay> HirDisplayWrapper<'_, T> {
             display_target: self.display_target,
             closure_style: self.closure_style,
             show_container_bounds: self.show_container_bounds,
+            bounds_formatting_ctx: Default::default(),
         })
     }
 
@@ -479,42 +535,46 @@ impl HirDisplay for ProjectionTy {
         // `<Param as Trait>::Assoc`
         if !f.display_target.is_source_code() {
             if let TyKind::Placeholder(idx) = self_ty.kind(Interner) {
-                let db = f.db;
-                let id = from_placeholder_idx(db, *idx);
-                let generics = generics(db.upcast(), id.parent);
-
-                let substs = generics.placeholder_subst(db);
-                let bounds = db
-                    .generic_predicates(id.parent)
-                    .iter()
-                    .map(|pred| pred.clone().substitute(Interner, &substs))
-                    .filter(|wc| match wc.skip_binders() {
-                        WhereClause::Implemented(tr) => {
-                            match tr.self_type_parameter(Interner).kind(Interner) {
-                                TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
-                                _ => false,
+                if !f.bounds_formatting_ctx.contains(self) {
+                    let db = f.db;
+                    let id = from_placeholder_idx(db, *idx);
+                    let generics = generics(db.upcast(), id.parent);
+
+                    let substs = generics.placeholder_subst(db);
+                    let bounds = db
+                        .generic_predicates(id.parent)
+                        .iter()
+                        .map(|pred| pred.clone().substitute(Interner, &substs))
+                        .filter(|wc| match wc.skip_binders() {
+                            WhereClause::Implemented(tr) => {
+                                matches!(
+                                    tr.self_type_parameter(Interner).kind(Interner),
+                                    TyKind::Alias(_)
+                                )
                             }
-                        }
-                        WhereClause::TypeOutlives(t) => match t.ty.kind(Interner) {
-                            TyKind::Alias(AliasTy::Projection(proj)) => proj == self,
-                            _ => false,
-                        },
-                        // We shouldn't be here if these exist
-                        WhereClause::AliasEq(_) => false,
-                        WhereClause::LifetimeOutlives(_) => false,
-                    })
-                    .collect::<Vec<_>>();
-                if !bounds.is_empty() {
-                    return write_bounds_like_dyn_trait_with_prefix(
-                        f,
-                        "impl",
-                        Either::Left(
-                            &TyKind::Alias(AliasTy::Projection(self.clone())).intern(Interner),
-                        ),
-                        &bounds,
-                        SizedByDefault::NotSized,
-                    );
-                };
+                            WhereClause::TypeOutlives(t) => {
+                                matches!(t.ty.kind(Interner), TyKind::Alias(_))
+                            }
+                            // We shouldn't be here if these exist
+                            WhereClause::AliasEq(_) => false,
+                            WhereClause::LifetimeOutlives(_) => false,
+                        })
+                        .collect::<Vec<_>>();
+                    if !bounds.is_empty() {
+                        return f.format_bounds_with(self.clone(), |f| {
+                            write_bounds_like_dyn_trait_with_prefix(
+                                f,
+                                "impl",
+                                Either::Left(
+                                    &TyKind::Alias(AliasTy::Projection(self.clone()))
+                                        .intern(Interner),
+                                ),
+                                &bounds,
+                                SizedByDefault::NotSized,
+                            )
+                        });
+                    }
+                }
             }
         }
 
@@ -1159,6 +1219,7 @@ impl HirDisplay for Ty {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             },
                         ) {
                             write!(f, "{}", path.display(f.db.upcast(), f.edition()))?;
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 2523aba5383..9283c46d0f6 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
@@ -277,7 +277,7 @@ impl CapturedItem {
     /// Converts the place to a name that can be inserted into source code.
     pub fn place_to_name(&self, owner: DefWithBodyId, db: &dyn HirDatabase) -> String {
         let body = db.body(owner);
-        let mut result = body[self.place.local].name.unescaped().display(db.upcast()).to_string();
+        let mut result = body[self.place.local].name.as_str().to_owned();
         for proj in &self.place.projections {
             match proj {
                 ProjectionElem::Deref => {}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
index 2fe90a8a924..d40816ba8ce 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs
@@ -420,7 +420,7 @@ impl InferenceTable<'_> {
 
         let snapshot = self.snapshot();
 
-        let mut autoderef = Autoderef::new(self, from_ty.clone(), false);
+        let mut autoderef = Autoderef::new(self, from_ty.clone(), false, false);
         let mut first_error = None;
         let mut found = None;
 
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 6b6c0348dcb..b951443897c 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
@@ -487,7 +487,7 @@ impl InferenceContext<'_> {
             }
             Expr::Call { callee, args, .. } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none(), ExprIsRead::Yes);
-                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false);
+                let mut derefs = Autoderef::new(&mut self.table, callee_ty.clone(), false, true);
                 let (res, derefed_callee) = loop {
                     let Some((callee_deref_ty, _)) = derefs.next() else {
                         break (None, callee_ty.clone());
@@ -854,7 +854,7 @@ impl InferenceContext<'_> {
                         if let Some(derefed) = builtin_deref(self.table.db, &inner_ty, true) {
                             self.resolve_ty_shallow(derefed)
                         } else {
-                            deref_by_trait(&mut self.table, inner_ty)
+                            deref_by_trait(&mut self.table, inner_ty, false)
                                 .unwrap_or_else(|| self.err_ty())
                         }
                     }
@@ -1718,7 +1718,7 @@ impl InferenceContext<'_> {
         receiver_ty: &Ty,
         name: &Name,
     ) -> Option<(Ty, Either<FieldId, TupleFieldId>, Vec<Adjustment>, bool)> {
-        let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false);
+        let mut autoderef = Autoderef::new(&mut self.table, receiver_ty.clone(), false, false);
         let mut private_field = None;
         let res = autoderef.by_ref().find_map(|(derefed_ty, _)| {
             let (field_id, parameters) = match derefed_ty.kind(Interner) {
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 182032f0481..1cea67ee964 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
@@ -528,7 +528,7 @@ impl ReceiverAdjustments {
         let mut ty = table.resolve_ty_shallow(&ty);
         let mut adjust = Vec::new();
         for _ in 0..self.autoderefs {
-            match autoderef::autoderef_step(table, ty.clone(), true) {
+            match autoderef::autoderef_step(table, ty.clone(), true, false) {
                 None => {
                     never!("autoderef not possible for {:?}", ty);
                     ty = TyKind::Error.intern(Interner);
@@ -1106,7 +1106,8 @@ fn iterate_method_candidates_by_receiver(
     // be found in any of the derefs of receiver_ty, so we have to go through
     // that, including raw derefs.
     table.run_in_snapshot(|table| {
-        let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+        let mut autoderef =
+            autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
         while let Some((self_ty, _)) = autoderef.next() {
             iterate_inherent_methods(
                 &self_ty,
@@ -1123,7 +1124,8 @@ fn iterate_method_candidates_by_receiver(
         ControlFlow::Continue(())
     })?;
     table.run_in_snapshot(|table| {
-        let mut autoderef = autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true);
+        let mut autoderef =
+            autoderef::Autoderef::new_no_tracking(table, receiver_ty.clone(), true, true);
         while let Some((self_ty, _)) = autoderef.next() {
             if matches!(self_ty.kind(Interner), TyKind::InferenceVar(_, TyVariableKind::General)) {
                 // don't try to resolve methods on unknown types
@@ -1709,7 +1711,7 @@ fn autoderef_method_receiver(
     ty: Ty,
 ) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
     let mut deref_chain: Vec<_> = Vec::new();
-    let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false);
+    let mut autoderef = autoderef::Autoderef::new_no_tracking(table, ty, false, true);
     while let Some((ty, derefs)) = autoderef.next() {
         deref_chain.push((
             autoderef.table.canonicalize(ty),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 74acf23b75a..8866de22dfb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -1343,7 +1343,7 @@ fn foo<T: Trait>(a: &T) {
 fn autoderef_visibility_field() {
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 mod a {
     pub struct Foo(pub char);
     pub struct Bar(i32);
@@ -1375,7 +1375,7 @@ fn autoderef_visibility_method() {
     cov_mark::check!(autoderef_candidate_not_visible);
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 mod a {
     pub struct Foo(pub char);
     impl Foo {
@@ -1741,7 +1741,7 @@ fn main() {
 fn deref_fun_1() {
     check_types(
         r#"
-//- minicore: deref
+//- minicore: receiver
 
 struct A<T, U>(T, U);
 struct B<T>(T);
@@ -1782,7 +1782,7 @@ fn test() {
 fn deref_fun_2() {
     check_types(
         r#"
-//- minicore: deref
+//- minicore: receiver
 
 struct A<T, U>(T, U);
 struct B<T>(T);
@@ -1903,7 +1903,7 @@ pub fn test(generic_args: impl Into<Foo>) {
 fn bad_inferred_reference_2() {
     check_no_mismatches(
         r#"
-//- minicore: deref
+//- minicore: receiver
 trait ExactSizeIterator {
     fn len(&self) -> usize;
 }
@@ -2054,7 +2054,7 @@ fn foo() {
 fn box_deref_is_builtin() {
     check(
         r#"
-//- minicore: deref
+//- minicore: receiver
 use core::ops::Deref;
 
 #[lang = "owned_box"]
@@ -2087,7 +2087,7 @@ fn test() {
 fn manually_drop_deref_is_not_builtin() {
     check(
         r#"
-//- minicore: manually_drop, deref
+//- minicore: manually_drop, receiver
 struct Foo;
 impl Foo {
     fn foo(&self) {}
@@ -2105,7 +2105,7 @@ fn test() {
 fn mismatched_args_due_to_supertraits_with_deref() {
     check_no_mismatches(
         r#"
-//- minicore: deref
+//- minicore: receiver
 use core::ops::Deref;
 
 trait Trait1 {
@@ -2139,3 +2139,34 @@ fn problem_method<T: Trait3>() {
 "#,
     );
 }
+
+#[test]
+fn receiver_without_deref_impl() {
+    check(
+        r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+    fn foo1(self: &Bar) -> i32 { 42 }
+    fn foo2(self: Bar) -> bool { true }
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+    type Target = Foo;
+}
+
+fn main() {
+    let bar = Bar;
+    let _v1 = bar.foo1();
+      //^^^ type: i32
+    let _v2 = bar.foo2();
+      //^^^ type: bool
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index db3121d3cd3..0cbc75726bf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -45,7 +45,7 @@ use hir_def::{
     body::BodyDiagnostic,
     data::{adt::VariantData, TraitFlags},
     generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
-    hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, Pat},
+    hir::{BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat},
     item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
     lang_item::LangItemTarget,
     layout::{self, ReprOptions, TargetDataLayout},
@@ -2470,20 +2470,31 @@ impl Param {
     }
 
     pub fn as_local(&self, db: &dyn HirDatabase) -> Option<Local> {
-        let parent = match self.func {
-            Callee::Def(CallableDefId::FunctionId(it)) => DefWithBodyId::FunctionId(it),
-            Callee::Closure(closure, _) => db.lookup_intern_closure(closure.into()).0,
-            _ => return None,
-        };
-        let body = db.body(parent);
-        if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
-            Some(Local { parent, binding_id: self_param })
-        } else if let Pat::Bind { id, .. } =
-            &body[body.params[self.idx - body.self_param.is_some() as usize]]
-        {
-            Some(Local { parent, binding_id: *id })
-        } else {
-            None
+        match self.func {
+            Callee::Def(CallableDefId::FunctionId(it)) => {
+                let parent = DefWithBodyId::FunctionId(it);
+                let body = db.body(parent);
+                if let Some(self_param) = body.self_param.filter(|_| self.idx == 0) {
+                    Some(Local { parent, binding_id: self_param })
+                } else if let Pat::Bind { id, .. } =
+                    &body[body.params[self.idx - body.self_param.is_some() as usize]]
+                {
+                    Some(Local { parent, binding_id: *id })
+                } else {
+                    None
+                }
+            }
+            Callee::Closure(closure, _) => {
+                let c = db.lookup_intern_closure(closure.into());
+                let body = db.body(c.0);
+                if let Expr::Closure { args, .. } = &body[c.1] {
+                    if let Pat::Bind { id, .. } = &body[args[self.idx]] {
+                        return Some(Local { parent: c.0, binding_id: *id });
+                    }
+                }
+                None
+            }
+            _ => None,
         }
     }
 
@@ -2756,6 +2767,15 @@ impl Trait {
         traits.iter().map(|tr| Trait::from(*tr)).collect()
     }
 
+    pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
+        db.trait_data(self.id).items.iter().find(|(n, _)| name == *n).and_then(
+            |&(_, it)| match it {
+                AssocItemId::FunctionId(id) => Some(Function { id }),
+                _ => None,
+            },
+        )
+    }
+
     pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
         db.trait_data(self.id).items.iter().map(|(_name, it)| (*it).into()).collect()
     }
@@ -4673,6 +4693,10 @@ impl Type {
         matches!(self.ty.kind(Interner), TyKind::Scalar(Scalar::Bool))
     }
 
+    pub fn is_str(&self) -> bool {
+        matches!(self.ty.kind(Interner), TyKind::Str)
+    }
+
     pub fn is_never(&self) -> bool {
         matches!(self.ty.kind(Interner), TyKind::Never)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 523bc6f10aa..09470bed9cf 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -1439,8 +1439,20 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(call.syntax())?.resolve_method_call_fallback(self.db, call)
     }
 
-    pub fn resolve_known_blanket_dual_impls(&self, call: &ast::MethodCallExpr) -> Option<Function> {
-        self.analyze(call.syntax())?.resolve_known_blanket_dual_impls(self.db, call)
+    /// Env is used to derive the trait environment
+    // FIXME: better api for the trait environment
+    pub fn resolve_trait_impl_method(
+        &self,
+        env: Type,
+        trait_: Trait,
+        func: Function,
+        subst: impl IntoIterator<Item = Type>,
+    ) -> Option<Function> {
+        let mut substs = hir_ty::TyBuilder::subst_for_def(self.db, TraitId::from(trait_), None);
+        for s in subst {
+            substs = substs.push(s.ty);
+        }
+        Some(self.db.lookup_impl_method(env.env, func.into(), substs.build()).0.into())
     }
 
     fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
@@ -1471,6 +1483,8 @@ impl<'db> SemanticsImpl<'db> {
         self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
     }
 
+    // This does not resolve the method call to the correct trait impl!
+    // We should probably fix that.
     pub fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
         self.analyze(call.syntax())?.resolve_method_call_as_callable(self.db, call)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index 6b78d7a3631..b699ccde412 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -322,68 +322,6 @@ impl SourceAnalyzer {
         }
     }
 
-    // If the method is into(), try_into(), parse(), resolve it to from, try_from, from_str.
-    pub(crate) fn resolve_known_blanket_dual_impls(
-        &self,
-        db: &dyn HirDatabase,
-        call: &ast::MethodCallExpr,
-    ) -> Option<Function> {
-        // e.g. if the method call is let b = a.into(),
-        // - receiver_type is A (type of a)
-        // - return_type is B (type of b)
-        // We will find the definition of B::from(a: A).
-        let callable = self.resolve_method_call_as_callable(db, call)?;
-        let (_, receiver_type) = callable.receiver_param(db)?;
-        let return_type = callable.return_type();
-        let (search_method, substs) = match call.name_ref()?.text().as_str() {
-            "into" => {
-                let trait_ =
-                    self.resolver.resolve_known_trait(db.upcast(), &path![core::convert::From])?;
-                (
-                    self.trait_fn(db, trait_, "from")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        .push(return_type.ty)
-                        .push(receiver_type.ty)
-                        .build(),
-                )
-            }
-            "try_into" => {
-                let trait_ = self
-                    .resolver
-                    .resolve_known_trait(db.upcast(), &path![core::convert::TryFrom])?;
-                (
-                    self.trait_fn(db, trait_, "try_from")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        // If the method is try_into() or parse(), return_type is Result<T, Error>.
-                        // Get T from type arguments of Result<T, Error>.
-                        .push(return_type.type_arguments().next()?.ty)
-                        .push(receiver_type.ty)
-                        .build(),
-                )
-            }
-            "parse" => {
-                let trait_ =
-                    self.resolver.resolve_known_trait(db.upcast(), &path![core::str::FromStr])?;
-                (
-                    self.trait_fn(db, trait_, "from_str")?,
-                    hir_ty::TyBuilder::subst_for_def(db, trait_, None)
-                        .push(return_type.type_arguments().next()?.ty)
-                        .build(),
-                )
-            }
-            _ => return None,
-        };
-
-        let found_method = self.resolve_impl_method_or_trait_def(db, search_method, substs);
-        // If found_method == search_method, the method in trait itself is resolved.
-        // It means the blanket dual impl is not found.
-        if found_method == search_method {
-            None
-        } else {
-            Some(found_method.into())
-        }
-    }
-
     pub(crate) fn resolve_expr_as_callable(
         &self,
         db: &dyn HirDatabase,
@@ -1309,18 +1247,6 @@ impl SourceAnalyzer {
         Some((trait_id, fn_id))
     }
 
-    fn trait_fn(
-        &self,
-        db: &dyn HirDatabase,
-        trait_id: TraitId,
-        method_name: &str,
-    ) -> Option<FunctionId> {
-        db.trait_data(trait_id).items.iter().find_map(|(item_name, item)| match item {
-            AssocItemId::FunctionId(t) if item_name.as_str() == method_name => Some(*t),
-            _ => None,
-        })
-    }
-
     fn ty_of_expr(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<&Ty> {
         self.infer.as_ref()?.type_of_expr_or_pat(self.expr_id(db, expr)?)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/symbols.rs b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
index a6b8ed70c36..2ebd88edae2 100644
--- a/src/tools/rust-analyzer/crates/hir/src/symbols.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/symbols.rs
@@ -3,7 +3,7 @@
 use either::Either;
 use hir_def::{
     db::DefDatabase,
-    item_scope::{ImportId, ImportOrExternCrate},
+    item_scope::{ImportId, ImportOrExternCrate, ImportOrGlob},
     per_ns::Item,
     src::{HasChildSource, HasSource},
     visibility::{Visibility, VisibilityExplicitness},
@@ -55,9 +55,10 @@ impl DeclarationLocation {
 }
 
 /// Represents an outstanding module that the symbol collector must collect symbols from.
+#[derive(Debug)]
 struct SymbolCollectorWork {
     module_id: ModuleId,
-    parent: Option<DefWithBodyId>,
+    parent: Option<Name>,
 }
 
 pub struct SymbolCollector<'a> {
@@ -81,7 +82,15 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
+    pub fn new_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
+        let mut symbol_collector = SymbolCollector::new(db);
+        symbol_collector.collect(module);
+        symbol_collector.finish()
+    }
+
     pub fn collect(&mut self, module: Module) {
+        let _p = tracing::info_span!("SymbolCollector::collect", ?module).entered();
+        tracing::info!(?module, "SymbolCollector::collect",);
         self.edition = module.krate().edition(self.db);
 
         // The initial work is the root module we're collecting, additional work will
@@ -97,16 +106,12 @@ impl<'a> SymbolCollector<'a> {
         self.symbols.into_iter().collect()
     }
 
-    pub fn collect_module(db: &dyn HirDatabase, module: Module) -> Box<[FileSymbol]> {
-        let mut symbol_collector = SymbolCollector::new(db);
-        symbol_collector.collect(module);
-        symbol_collector.finish()
-    }
-
     fn do_work(&mut self, work: SymbolCollectorWork) {
+        let _p = tracing::info_span!("SymbolCollector::do_work", ?work).entered();
+        tracing::info!(?work, "SymbolCollector::do_work");
         self.db.unwind_if_cancelled();
 
-        let parent_name = work.parent.and_then(|id| self.def_with_body_id_name(id));
+        let parent_name = work.parent.map(|name| name.as_str().to_smolstr());
         self.with_container_name(parent_name, |s| s.collect_from_module(work.module_id));
     }
 
@@ -116,18 +121,18 @@ impl<'a> SymbolCollector<'a> {
                 ModuleDefId::ModuleId(id) => this.push_module(id, name),
                 ModuleDefId::FunctionId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::AdtId(AdtId::StructId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::AdtId(AdtId::EnumId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::AdtId(AdtId::UnionId(id)) => this.push_decl(id, name, false),
                 ModuleDefId::ConstId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::StaticId(id) => {
                     this.push_decl(id, name, false);
-                    this.collect_from_body(id);
+                    this.collect_from_body(id, Some(name.clone()));
                 }
                 ModuleDefId::TraitId(id) => {
                     this.push_decl(id, name, false);
@@ -153,24 +158,32 @@ impl<'a> SymbolCollector<'a> {
         // Nested trees are very common, so a cache here will hit a lot.
         let import_child_source_cache = &mut FxHashMap::default();
 
-        let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId| {
+        let is_explicit_import = |vis| match vis {
+            Visibility::Public => true,
+            Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
+            Visibility::Module(_, VisibilityExplicitness::Implicit) => false,
+        };
+
+        let mut push_import = |this: &mut Self, i: ImportId, name: &Name, def: ModuleDefId, vis| {
             let source = import_child_source_cache
-                .entry(i.import)
-                .or_insert_with(|| i.import.child_source(this.db.upcast()));
+                .entry(i.use_)
+                .or_insert_with(|| i.use_.child_source(this.db.upcast()));
             let Some(use_tree_src) = source.value.get(i.idx) else { return };
-            let Some(name_ptr) = use_tree_src
-                .rename()
-                .and_then(|rename| rename.name())
-                .map(Either::Left)
-                .or_else(|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))
-                .map(|it| AstPtr::new(&it))
-            else {
+            let rename = use_tree_src.rename().and_then(|rename| rename.name());
+            let name_syntax = match rename {
+                Some(name) => Some(Either::Left(name)),
+                None if is_explicit_import(vis) => {
+                    (|| use_tree_src.path()?.segment()?.name_ref().map(Either::Right))()
+                }
+                None => None,
+            };
+            let Some(name_syntax) = name_syntax else {
                 return;
             };
             let dec_loc = DeclarationLocation {
                 hir_file_id: source.file_id,
                 ptr: SyntaxNodePtr::new(use_tree_src.syntax()),
-                name_ptr,
+                name_ptr: AstPtr::new(&name_syntax),
             };
             this.symbols.insert(FileSymbol {
                 name: name.symbol().clone(),
@@ -183,23 +196,23 @@ impl<'a> SymbolCollector<'a> {
         };
 
         let push_extern_crate =
-            |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId| {
+            |this: &mut Self, i: ExternCrateId, name: &Name, def: ModuleDefId, vis| {
                 let loc = i.lookup(this.db.upcast());
                 let source = loc.source(this.db.upcast());
-                let Some(name_ptr) = source
-                    .value
-                    .rename()
-                    .and_then(|rename| rename.name())
-                    .map(Either::Left)
-                    .or_else(|| source.value.name_ref().map(Either::Right))
-                    .map(|it| AstPtr::new(&it))
-                else {
+                let rename = source.value.rename().and_then(|rename| rename.name());
+
+                let name_syntax = match rename {
+                    Some(name) => Some(Either::Left(name)),
+                    None if is_explicit_import(vis) => None,
+                    None => source.value.name_ref().map(Either::Right),
+                };
+                let Some(name_syntax) = name_syntax else {
                     return;
                 };
                 let dec_loc = DeclarationLocation {
                     hir_file_id: source.file_id,
                     ptr: SyntaxNodePtr::new(source.value.syntax()),
-                    name_ptr,
+                    name_ptr: AstPtr::new(&name_syntax),
                 };
                 this.symbols.insert(FileSymbol {
                     name: name.symbol().clone(),
@@ -211,18 +224,6 @@ impl<'a> SymbolCollector<'a> {
                 });
             };
 
-        let is_explicit_import = |vis| {
-            match vis {
-                Visibility::Module(_, VisibilityExplicitness::Explicit) => true,
-                Visibility::Module(_, VisibilityExplicitness::Implicit) => {
-                    // consider imports in the crate root explicit, as these are visibly
-                    // crate-wide anyways
-                    module_id.is_crate_root()
-                }
-                Visibility::Public => true,
-            }
-        };
-
         let def_map = module_id.def_map(self.db.upcast());
         let scope = &def_map[module_id.local_id].scope;
 
@@ -232,14 +233,14 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.types() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    match i {
-                        ImportOrExternCrate::Import(i) => push_import(self, i, name, def),
-                        ImportOrExternCrate::ExternCrate(i) => {
-                            push_extern_crate(self, i, name, def)
-                        }
+                match i {
+                    ImportOrExternCrate::Import(i) => push_import(self, i, name, def, vis),
+                    ImportOrExternCrate::Glob(_) => (),
+                    ImportOrExternCrate::ExternCrate(i) => {
+                        push_extern_crate(self, i, name, def, vis)
                     }
                 }
+
                 continue;
             }
             // self is a declaration
@@ -248,8 +249,9 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.macros() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    push_import(self, i, name, def.into());
+                match i {
+                    ImportOrGlob::Import(i) => push_import(self, i, name, def.into(), vis),
+                    ImportOrGlob::Glob(_) => (),
                 }
                 continue;
             }
@@ -259,8 +261,9 @@ impl<'a> SymbolCollector<'a> {
 
         for (name, Item { def, vis, import }) in scope.values() {
             if let Some(i) = import {
-                if is_explicit_import(vis) {
-                    push_import(self, i, name, def);
+                match i {
+                    ImportOrGlob::Import(i) => push_import(self, i, name, def, vis),
+                    ImportOrGlob::Glob(_) => (),
                 }
                 continue;
             }
@@ -269,7 +272,7 @@ impl<'a> SymbolCollector<'a> {
         }
 
         for const_id in scope.unnamed_consts() {
-            self.collect_from_body(const_id);
+            self.collect_from_body(const_id, None);
         }
 
         for (name, id) in scope.legacy_macros() {
@@ -285,7 +288,7 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    fn collect_from_body(&mut self, body_id: impl Into<DefWithBodyId>) {
+    fn collect_from_body(&mut self, body_id: impl Into<DefWithBodyId>, name: Option<Name>) {
         let body_id = body_id.into();
         let body = self.db.body(body_id);
 
@@ -294,7 +297,7 @@ impl<'a> SymbolCollector<'a> {
             for (id, _) in def_map.modules() {
                 self.work.push(SymbolCollectorWork {
                     module_id: def_map.module_id(id),
-                    parent: Some(body_id),
+                    parent: name.clone(),
                 });
             }
         }
@@ -333,24 +336,6 @@ impl<'a> SymbolCollector<'a> {
         }
     }
 
-    fn def_with_body_id_name(&self, body_id: DefWithBodyId) -> Option<SmolStr> {
-        match body_id {
-            DefWithBodyId::FunctionId(id) => {
-                Some(self.db.function_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::StaticId(id) => {
-                Some(self.db.static_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::ConstId(id) => {
-                Some(self.db.const_data(id).name.as_ref()?.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::VariantId(id) => {
-                Some(self.db.enum_variant_data(id).name.display_no_db(self.edition).to_smolstr())
-            }
-            DefWithBodyId::InTypeConstId(_) => Some("in type const".into()),
-        }
-    }
-
     fn push_assoc_item(&mut self, assoc_item_id: AssocItemId, name: &Name) {
         match assoc_item_id {
             AssocItemId::FunctionId(id) => self.push_decl(id, name, true),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
index 82d8db42589..fb533077d96 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs
@@ -28,6 +28,7 @@ impl AssistConfig {
             prefer_no_std: self.prefer_no_std,
             prefer_prelude: self.prefer_prelude,
             prefer_absolute: self.prefer_absolute,
+            allow_unstable: true,
         }
     }
 }
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 a5c5b08d5b0..eb784cd1226 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
@@ -159,7 +159,7 @@ pub(crate) fn convert_bool_then_to_if(acc: &mut Assists, ctx: &AssistContext<'_>
     };
     // Verify this is `bool::then` that is being called.
     let func = ctx.sema.resolve_method_call(&mcall)?;
-    if !func.name(ctx.sema.db).eq_ident("then") {
+    if func.name(ctx.sema.db) != sym::then {
         return None;
     }
     let assoc = func.as_assoc_item(ctx.sema.db)?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
index bb04a43cf96..d34cf895cd9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_closure_to_fn.rs
@@ -343,11 +343,9 @@ fn compute_closure_type_params(
     let mut mentioned_names = mentioned_generic_params
         .iter()
         .filter_map(|param| match param {
-            hir::GenericParam::TypeParam(param) => {
-                Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
-            }
+            hir::GenericParam::TypeParam(param) => Some(param.name(ctx.db()).as_str().to_smolstr()),
             hir::GenericParam::ConstParam(param) => {
-                Some(param.name(ctx.db()).unescaped().display(ctx.db()).to_smolstr())
+                Some(param.name(ctx.db()).as_str().to_smolstr())
             }
             hir::GenericParam::LifetimeParam(_) => None,
         })
@@ -390,7 +388,7 @@ fn compute_closure_type_params(
             let has_name = syntax
                 .descendants()
                 .filter_map(ast::NameOrNameRef::cast)
-                .any(|name| mentioned_names.contains(&*name.text()));
+                .any(|name| mentioned_names.contains(name.text().trim_start_matches("r#")));
             let mut has_new_params = false;
             if has_name {
                 syntax
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index 615b5d3f98b..d4f2ea3bd94 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -170,7 +170,7 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
             ),
             _ => false,
         })
-        .any(|(name, _)| name.eq_ident(variant_name.text().as_str()))
+        .any(|(name, _)| name.as_str() == variant_name.text().trim_start_matches("r#"))
 }
 
 fn extract_generic_params(
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 97321f4ec1e..7b6f76d0045 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
@@ -1672,8 +1672,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    let $0vec = vec![];
-    let _ = vec;
+    let $0items = vec![];
+    let _ = items;
 }
 "#,
             "Extract into variable",
@@ -1696,8 +1696,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    const $0VEC: Vec = vec![];
-    let _ = VEC;
+    const $0ITEMS: Vec = vec![];
+    let _ = ITEMS;
 }
 "#,
             "Extract into constant",
@@ -1720,8 +1720,8 @@ macro_rules! vec {
     () => {Vec}
 }
 fn main() {
-    static $0VEC: Vec = vec![];
-    let _ = VEC;
+    static $0ITEMS: Vec = vec![];
+    let _ = ITEMS;
 }
 "#,
             "Extract into static",
@@ -2019,8 +2019,8 @@ impl<T> Vec<T> {
 }
 
 fn foo(s: &mut S) {
-    let $0vec = &mut s.vec;
-    vec.push(0);
+    let $0items = &mut s.vec;
+    items.push(0);
 }"#,
             "Extract into variable",
         );
@@ -2106,8 +2106,8 @@ impl<T> Vec<T> {
 }
 
 fn foo(f: &mut Y) {
-    let $0vec = &mut f.field.field.vec;
-    vec.push(0);
+    let $0items = &mut f.field.field.vec;
+    items.push(0);
 }"#,
             "Extract into variable",
         );
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
index 7a92d8911bf..47e4a68293f 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs
@@ -48,7 +48,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
     let (_, def) = module
         .scope(ctx.db(), None)
         .into_iter()
-        .find(|(name, _)| name.eq_ident(name_ref.text().as_str()))?;
+        .find(|(name, _)| name.as_str() == name_ref.text().trim_start_matches("r#"))?;
     let ScopeDef::ModuleDef(def) = def else {
         return None;
     };
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
index 8a7a06b380f..10915f8aafb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_from_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
     assists::{AssistId, AssistKind},
     base_db::AnchoredPathBuf,
 };
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_from_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.as_str().to_smolstr();
     let path = format!("../{module_name}.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
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 9692b705929..bbf18e21948 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
@@ -61,7 +61,7 @@ pub(crate) fn move_module_to_file(acc: &mut Assists, ctx: &AssistContext<'_>) ->
                                 .string_value_unescape()
                                 .is_none() =>
                     {
-                        format_to!(buf, "{}/", name.unescaped().display(db))
+                        format_to!(buf, "{}/", name.as_str())
                     }
                     _ => (),
                 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
index 2925e2334b4..7b38c795dc8 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_to_mod_rs.rs
@@ -2,7 +2,7 @@ use ide_db::{
     assists::{AssistId, AssistKind},
     base_db::AnchoredPathBuf,
 };
-use syntax::{ast, AstNode};
+use syntax::{ast, AstNode, ToSmolStr};
 
 use crate::{
     assist_context::{AssistContext, Assists},
@@ -39,7 +39,7 @@ pub(crate) fn move_to_mod_rs(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
     }
 
     let target = source_file.syntax().text_range();
-    let module_name = module.name(ctx.db())?.unescaped().display(ctx.db()).to_string();
+    let module_name = module.name(ctx.db())?.as_str().to_smolstr();
     let path = format!("./{module_name}/mod.rs");
     let dst = AnchoredPathBuf { anchor: ctx.file_id().into(), path };
     acc.add(
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 849b8a42c69..2a8465f634c 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
@@ -208,7 +208,7 @@ fn find_trait_method(
     if let Some(hir::AssocItem::Function(method)) =
         trait_.items(db).into_iter().find(|item: &hir::AssocItem| {
             item.name(db)
-                .map(|name| name.eq_ident(trait_method_name.text().as_str()))
+                .map(|name| name.as_str() == trait_method_name.text().trim_start_matches("r#"))
                 .unwrap_or(false)
         })
     {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
index 972303c2a04..a79a82be450 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_fields.rs
@@ -110,7 +110,7 @@ fn compute_fields_ranks(
         .fields(ctx.db())
         .into_iter()
         .enumerate()
-        .map(|(idx, field)| (field.name(ctx.db()).unescaped().display(ctx.db()).to_string(), idx))
+        .map(|(idx, field)| (field.name(ctx.db()).as_str().to_owned(), idx))
         .collect();
 
     Some(res)
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
index eb1d538f874..c3404173eaf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/reorder_impl_items.rs
@@ -122,7 +122,7 @@ fn compute_item_ranks(
             .iter()
             .flat_map(|i| i.name(ctx.db()))
             .enumerate()
-            .map(|(idx, name)| (name.unescaped().display(ctx.db()).to_string(), idx))
+            .map(|(idx, name)| (name.as_str().to_owned(), idx))
             .collect(),
     )
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
index 40669c65c57..a22e7b272ea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions.rs
@@ -188,9 +188,6 @@ impl Completions {
         resolution: hir::ScopeDef,
         doc_aliases: Vec<syntax::SmolStr>,
     ) {
-        if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
-            return;
-        }
         let is_private_editable = match ctx.def_is_visible(&resolution) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -216,9 +213,6 @@ impl Completions {
         local_name: hir::Name,
         resolution: hir::ScopeDef,
     ) {
-        if !ctx.check_stability(resolution.attrs(ctx.db).as_deref()) {
-            return;
-        }
         let is_private_editable = match ctx.def_is_visible(&resolution) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -241,7 +235,7 @@ impl Completions {
         path_ctx: &PathCompletionCtx,
         e: hir::Enum,
     ) {
-        if !ctx.check_stability(Some(&e.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(e) {
             return;
         }
         e.variants(ctx.db)
@@ -257,9 +251,6 @@ impl Completions {
         local_name: hir::Name,
         doc_aliases: Vec<syntax::SmolStr>,
     ) {
-        if !ctx.check_stability(Some(&module.attrs(ctx.db))) {
-            return;
-        }
         self.add_path_resolution(
             ctx,
             path_ctx,
@@ -276,9 +267,6 @@ impl Completions {
         mac: hir::Macro,
         local_name: hir::Name,
     ) {
-        if !ctx.check_stability(Some(&mac.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&mac) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -302,9 +290,6 @@ impl Completions {
         func: hir::Function,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -332,9 +317,6 @@ impl Completions {
         receiver: Option<SmolStr>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -362,9 +344,6 @@ impl Completions {
         func: hir::Function,
         import: LocatedImport,
     ) {
-        if !ctx.check_stability(Some(&func.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&func) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -387,9 +366,6 @@ impl Completions {
     }
 
     pub(crate) fn add_const(&mut self, ctx: &CompletionContext<'_>, konst: hir::Const) {
-        if !ctx.check_stability(Some(&konst.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&konst) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -406,9 +382,6 @@ impl Completions {
         ctx: &CompletionContext<'_>,
         type_alias: hir::TypeAlias,
     ) {
-        if !ctx.check_stability(Some(&type_alias.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&type_alias) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -438,7 +411,7 @@ impl Completions {
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         if let Some(builder) =
@@ -455,7 +428,7 @@ impl Completions {
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         if let PathCompletionCtx { kind: PathKind::Pat { pat_ctx }, .. } = path_ctx {
@@ -479,9 +452,6 @@ impl Completions {
         field: hir::Field,
         ty: &hir::Type,
     ) {
-        if !ctx.check_stability(Some(&field.attrs(ctx.db))) {
-            return;
-        }
         let is_private_editable = match ctx.is_visible(&field) {
             Visible::Yes => false,
             Visible::Editable => true,
@@ -506,12 +476,18 @@ impl Completions {
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
-            return;
-        }
-        if let Some(builder) =
-            render_struct_literal(RenderContext::new(ctx), path_ctx, strukt, path, local_name)
-        {
+        let is_private_editable = match ctx.is_visible(&strukt) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        if let Some(builder) = render_struct_literal(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            path_ctx,
+            strukt,
+            path,
+            local_name,
+        ) {
             self.add(builder.build(ctx.db));
         }
     }
@@ -523,10 +499,17 @@ impl Completions {
         path: Option<hir::ModPath>,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&un.attrs(ctx.db))) {
-            return;
-        }
-        let item = render_union_literal(RenderContext::new(ctx), un, path, local_name);
+        let is_private_editable = match ctx.is_visible(&un) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        let item = render_union_literal(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            un,
+            path,
+            local_name,
+        );
         self.add_opt(item);
     }
 
@@ -571,7 +554,7 @@ impl Completions {
         variant: hir::Variant,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         self.add_opt(render_variant_pat(
@@ -591,7 +574,7 @@ impl Completions {
         variant: hir::Variant,
         path: hir::ModPath,
     ) {
-        if !ctx.check_stability(Some(&variant.attrs(ctx.db))) {
+        if !ctx.check_stability_and_hidden(variant) {
             return;
         }
         let path = Some(&path);
@@ -612,10 +595,17 @@ impl Completions {
         strukt: hir::Struct,
         local_name: Option<hir::Name>,
     ) {
-        if !ctx.check_stability(Some(&strukt.attrs(ctx.db))) {
-            return;
-        }
-        self.add_opt(render_struct_pat(RenderContext::new(ctx), pattern_ctx, strukt, local_name));
+        let is_private_editable = match ctx.is_visible(&strukt) {
+            Visible::Yes => false,
+            Visible::Editable => true,
+            Visible::No => return,
+        };
+        self.add_opt(render_struct_pat(
+            RenderContext::new(ctx).private_editable(is_private_editable),
+            pattern_ctx,
+            strukt,
+            local_name,
+        ));
     }
 
     pub(crate) fn suggest_name(&mut self, ctx: &CompletionContext<'_>, name: &str) {
@@ -660,7 +650,7 @@ fn enum_variants_with_paths(
         if let Some(path) = ctx.module.find_path(
             ctx.db,
             hir::ModuleDef::from(variant),
-            ctx.config.import_path_config(),
+            ctx.config.import_path_config(ctx.is_nightly),
         ) {
             // Variants with trivial paths are already added by the existing completion logic,
             // so we should avoid adding these twice
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 7679d9076de..d12654665ce 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
@@ -42,31 +42,38 @@ pub(crate) fn complete_dot(
         item.detail("expr.await");
         item.add_to(acc, ctx.db);
 
-        // Completions that skip `.await`, e.g. `.await.foo()`.
-        let dot_access_kind = match &dot_access.kind {
-            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
-                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
-            }
-            it @ DotAccessKind::Method { .. } => *it,
-        };
-        let dot_access = DotAccess {
-            receiver: dot_access.receiver.clone(),
-            receiver_ty: Some(hir::TypeInfo { original: future_output.clone(), adjusted: None }),
-            kind: dot_access_kind,
-            ctx: dot_access.ctx,
-        };
-        complete_fields(
-            acc,
-            ctx,
-            &future_output,
-            |acc, field, ty| acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty),
-            |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
-            is_field_access,
-            is_method_access_with_parens,
-        );
-        complete_methods(ctx, &future_output, &traits_in_scope, |func| {
-            acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
-        });
+        if ctx.config.enable_auto_await {
+            // Completions that skip `.await`, e.g. `.await.foo()`.
+            let dot_access_kind = match &dot_access.kind {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                    DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+                }
+                it @ DotAccessKind::Method { .. } => *it,
+            };
+            let dot_access = DotAccess {
+                receiver: dot_access.receiver.clone(),
+                receiver_ty: Some(hir::TypeInfo {
+                    original: future_output.clone(),
+                    adjusted: None,
+                }),
+                kind: dot_access_kind,
+                ctx: dot_access.ctx,
+            };
+            complete_fields(
+                acc,
+                ctx,
+                &future_output,
+                |acc, field, ty| {
+                    acc.add_field(ctx, &dot_access, Some(await_str.clone()), field, &ty)
+                },
+                |acc, field, ty| acc.add_tuple_field(ctx, Some(await_str.clone()), field, &ty),
+                is_field_access,
+                is_method_access_with_parens,
+            );
+            complete_methods(ctx, &future_output, &traits_in_scope, |func| {
+                acc.add_method(ctx, &dot_access, func, Some(await_str.clone()), None)
+            });
+        }
     }
 
     complete_fields(
@@ -82,39 +89,41 @@ pub(crate) fn complete_dot(
         acc.add_method(ctx, dot_access, func, None, None)
     });
 
-    // FIXME:
-    // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
-    // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
-    // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
-    let iter = receiver_ty
-        .strip_references()
-        .add_reference(hir::Mutability::Shared)
-        .into_iterator_iter(ctx.db)
-        .map(|ty| (ty, SmolStr::new_static("iter()")));
-    // Does <receiver_ty as IntoIterator>::IntoIter` exist?
-    let into_iter = || {
-        receiver_ty
-            .clone()
+    if ctx.config.enable_auto_iter {
+        // FIXME:
+        // Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
+        // its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
+        // Does <&receiver_ty as IntoIterator>::IntoIter` exist? Assume `iter` is valid
+        let iter = receiver_ty
+            .strip_references()
+            .add_reference(hir::Mutability::Shared)
             .into_iterator_iter(ctx.db)
-            .map(|ty| (ty, SmolStr::new_static("into_iter()")))
-    };
-    if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
-        // Skip iterators, e.g. complete `.iter().filter_map()`.
-        let dot_access_kind = match &dot_access.kind {
-            DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
-                DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
-            }
-            it @ DotAccessKind::Method { .. } => *it,
+            .map(|ty| (ty, SmolStr::new_static("iter()")));
+        // Does <receiver_ty as IntoIterator>::IntoIter` exist?
+        let into_iter = || {
+            receiver_ty
+                .clone()
+                .into_iterator_iter(ctx.db)
+                .map(|ty| (ty, SmolStr::new_static("into_iter()")))
         };
-        let dot_access = DotAccess {
-            receiver: dot_access.receiver.clone(),
-            receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
-            kind: dot_access_kind,
-            ctx: dot_access.ctx,
-        };
-        complete_methods(ctx, &iter, &traits_in_scope, |func| {
-            acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
-        });
+        if let Some((iter, iter_sym)) = iter.or_else(into_iter) {
+            // Skip iterators, e.g. complete `.iter().filter_map()`.
+            let dot_access_kind = match &dot_access.kind {
+                DotAccessKind::Field { receiver_is_ambiguous_float_literal: _ } => {
+                    DotAccessKind::Field { receiver_is_ambiguous_float_literal: false }
+                }
+                it @ DotAccessKind::Method { .. } => *it,
+            };
+            let dot_access = DotAccess {
+                receiver: dot_access.receiver.clone(),
+                receiver_ty: Some(hir::TypeInfo { original: iter.clone(), adjusted: None }),
+                kind: dot_access_kind,
+                ctx: dot_access.ctx,
+            };
+            complete_methods(ctx, &iter, &traits_in_scope, |func| {
+                acc.add_method(ctx, &dot_access, func, Some(iter_sym.clone()), None)
+            });
+        }
     }
 }
 
@@ -1466,4 +1475,34 @@ async fn bar() {
 "#,
         );
     }
+
+    #[test]
+    fn receiver_without_deref_impl_completion() {
+        check_no_kw(
+            r#"
+//- minicore: receiver
+use core::ops::Receiver;
+
+struct Foo;
+
+impl Foo {
+    fn foo(self: Bar) {}
+}
+
+struct Bar;
+
+impl Receiver for Bar {
+    type Target = Foo;
+}
+
+fn main() {
+    let bar = Bar;
+    bar.$0
+}
+"#,
+            expect![[r#"
+    me foo() fn(self: Bar)
+"#]],
+        );
+    }
 }
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 db18b531d7c..e7101751701 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
@@ -247,7 +247,7 @@ pub(crate) fn complete_expr_path(
                             .find_path(
                                 ctx.db,
                                 hir::ModuleDef::from(strukt),
-                                ctx.config.import_path_config(),
+                                ctx.config.import_path_config(ctx.is_nightly),
                             )
                             .filter(|it| it.len() > 1);
 
@@ -269,7 +269,7 @@ pub(crate) fn complete_expr_path(
                             .find_path(
                                 ctx.db,
                                 hir::ModuleDef::from(un),
-                                ctx.config.import_path_config(),
+                                ctx.config.import_path_config(ctx.is_nightly),
                             )
                             .filter(|it| it.len() > 1);
 
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 73313eeaa6b..24243f57b46 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
@@ -5,7 +5,7 @@ use ide_db::imports::{
     insert_use::ImportScope,
 };
 use itertools::Itertools;
-use syntax::{ast, AstNode, SyntaxNode, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxNode};
 
 use crate::{
     config::AutoImportExclusionType,
@@ -257,7 +257,7 @@ fn import_on_the_fly(
     };
     let user_input_lowercased = potential_import_name.to_lowercase();
 
-    let import_cfg = ctx.config.import_path_config();
+    let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, import_cfg, ctx.config.insert_use.prefix_kind)
@@ -316,7 +316,7 @@ fn import_on_the_fly_pat_(
         ItemInNs::Values(def) => matches!(def, hir::ModuleDef::Const(_)),
     };
     let user_input_lowercased = potential_import_name.to_lowercase();
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -358,7 +358,7 @@ fn import_on_the_fly_method(
 
     let user_input_lowercased = potential_import_name.to_lowercase();
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     import_assets
         .search_for_imports(&ctx.sema, cfg, ctx.config.insert_use.prefix_kind)
@@ -444,7 +444,7 @@ fn compute_fuzzy_completion_order_key(
     cov_mark::hit!(certain_fuzzy_order_test);
     let import_name = match proposed_mod_path.segments().last() {
         // FIXME: nasty alloc, this is a hot path!
-        Some(name) => name.unescaped().display_no_db().to_smolstr().to_ascii_lowercase(),
+        Some(name) => name.as_str().to_ascii_lowercase(),
         None => return usize::MAX,
     };
     match import_name.match_indices(user_input_lowercased).next() {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
index 6d1945c4534..831f5665f4a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -31,7 +31,7 @@
 //! }
 //! ```
 
-use hir::{db::ExpandDatabase, HasAttrs, MacroFileId, Name};
+use hir::{db::ExpandDatabase, MacroFileId, Name};
 use ide_db::text_edit::TextEdit;
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
@@ -85,7 +85,7 @@ fn complete_trait_impl_name(
     name: &Option<ast::Name>,
     kind: ImplCompletionKind,
 ) -> Option<()> {
-    let item = match name {
+    let macro_file_item = match name {
         Some(name) => name.syntax().parent(),
         None => {
             let token = &ctx.token;
@@ -96,12 +96,12 @@ fn complete_trait_impl_name(
             .parent()
         }
     }?;
-    let item = ctx.sema.original_syntax_node_rooted(&item)?;
+    let real_file_item = ctx.sema.original_syntax_node_rooted(&macro_file_item)?;
     // item -> ASSOC_ITEM_LIST -> IMPL
-    let impl_def = ast::Impl::cast(item.parent()?.parent()?)?;
+    let impl_def = ast::Impl::cast(macro_file_item.parent()?.parent()?)?;
     let replacement_range = {
         // ctx.sema.original_ast_node(item)?;
-        let first_child = item
+        let first_child = real_file_item
             .children_with_tokens()
             .find(|child| {
                 !matches!(
@@ -109,7 +109,7 @@ fn complete_trait_impl_name(
                     SyntaxKind::COMMENT | SyntaxKind::WHITESPACE | SyntaxKind::ATTR
                 )
             })
-            .unwrap_or_else(|| SyntaxElement::Node(item.clone()));
+            .unwrap_or_else(|| SyntaxElement::Node(real_file_item.clone()));
 
         TextRange::new(first_child.text_range().start(), ctx.source_range().end())
     };
@@ -133,8 +133,11 @@ pub(crate) fn complete_trait_impl_item_by_name(
             acc,
             ctx,
             ImplCompletionKind::All,
-            match name_ref {
-                Some(name) => name.syntax().text_range(),
+            match name_ref
+                .as_ref()
+                .and_then(|name| ctx.sema.original_syntax_node_rooted(name.syntax()))
+            {
+                Some(name) => name.text_range(),
                 None => ctx.source_range(),
             },
             impl_,
@@ -152,7 +155,7 @@ fn complete_trait_impl(
     if let Some(hir_impl) = ctx.sema.to_def(impl_def) {
         get_missing_assoc_items(&ctx.sema, impl_def)
             .into_iter()
-            .filter(|item| ctx.check_stability(Some(&item.attrs(ctx.db))))
+            .filter(|item| ctx.check_stability_and_hidden(*item))
             .for_each(|item| {
                 use self::ImplCompletionKind::*;
                 match (item, kind) {
@@ -359,7 +362,7 @@ fn add_type_alias_impl(
     type_alias: hir::TypeAlias,
     impl_def: hir::Impl,
 ) {
-    let alias_name = type_alias.name(ctx.db).unescaped().display(ctx.db).to_smolstr();
+    let alias_name = type_alias.name(ctx.db).as_str().to_smolstr();
 
     let label = format_smolstr!("type {alias_name} =");
 
@@ -516,7 +519,7 @@ fn function_declaration(
 mod tests {
     use expect_test::expect;
 
-    use crate::tests::{check_edit, check_no_kw};
+    use crate::tests::{check, check_edit, check_no_kw};
 
     #[test]
     fn no_completion_inside_fn() {
@@ -1639,4 +1642,51 @@ impl DesugaredAsyncTrait for () {
 "#,
         );
     }
+
+    #[test]
+    fn within_attr_macro() {
+        check(
+            r#"
+//- proc_macros: identity
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+    fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+    f$0
+}
+                "#,
+            expect![[r#"
+                me fn bar(..)
+                me fn baz(..)
+                me fn foo(..)
+                md proc_macros
+                kw crate::
+                kw self::
+            "#]],
+        );
+        check(
+            r#"
+//- proc_macros: identity
+trait Trait {
+    fn foo(&self) {}
+    fn bar(&self) {}
+    fn baz(&self) {}
+}
+
+#[proc_macros::identity]
+impl Trait for () {
+    fn $0
+}
+        "#,
+            expect![[r#"
+                me fn bar(..)
+                me fn baz(..)
+                me fn foo(..)
+            "#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
index bafe3294209..cca6a22f290 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/mod_.rs
@@ -7,7 +7,7 @@ use ide_db::{
     base_db::{SourceRootDatabase, VfsPath},
     FxHashSet, RootDatabase, SymbolKind,
 };
-use syntax::{ast, AstNode, SyntaxKind, ToSmolStr};
+use syntax::{ast, AstNode, SyntaxKind};
 
 use crate::{context::CompletionContext, CompletionItem, Completions};
 
@@ -140,9 +140,7 @@ fn directory_to_look_for_submodules(
     module_chain_to_containing_module_file(module, db)
         .into_iter()
         .filter_map(|module| module.name(db))
-        .try_fold(base_directory, |path, name| {
-            path.join(&name.unescaped().display_no_db().to_smolstr())
-        })
+        .try_fold(base_directory, |path, name| path.join(name.as_str()))
 }
 
 fn module_chain_to_containing_module_file(
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 67ea05e002b..2c39a8fdfed 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
@@ -60,7 +60,7 @@ pub(crate) fn complete_postfix(
         None => return,
     };
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     if let Some(drop_trait) = ctx.famous_defs().core_ops_Drop() {
         if receiver_ty.impls_trait(ctx.db, drop_trait, &[]) {
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
index 9d62622add2..b384987c51c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/use_.rs
@@ -52,8 +52,14 @@ pub(crate) fn complete_use_path(
                         )
                     };
                     for (name, def) in module_scope {
-                        if !ctx.check_stability(def.attrs(ctx.db).as_deref()) {
-                            continue;
+                        if let (Some(attrs), Some(defining_crate)) =
+                            (def.attrs(ctx.db), def.krate(ctx.db))
+                        {
+                            if !ctx.check_stability(Some(&attrs))
+                                || ctx.is_doc_hidden(&attrs, defining_crate)
+                            {
+                                continue;
+                            }
                         }
                         let is_name_already_imported =
                             already_imported_names.contains(name.as_str());
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
index 8b1ce11e8a4..45aab38e8ea 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/config.rs
@@ -14,6 +14,8 @@ pub struct CompletionConfig<'a> {
     pub enable_postfix_completions: bool,
     pub enable_imports_on_the_fly: bool,
     pub enable_self_on_the_fly: bool,
+    pub enable_auto_iter: bool,
+    pub enable_auto_await: bool,
     pub enable_private_editable: bool,
     pub enable_term_search: bool,
     pub term_search_fuel: u64,
@@ -57,11 +59,12 @@ impl CompletionConfig<'_> {
             .flat_map(|snip| snip.prefix_triggers.iter().map(move |trigger| (&**trigger, snip)))
     }
 
-    pub fn import_path_config(&self) -> ImportPathConfig {
+    pub fn import_path_config(&self, allow_unstable: bool) -> ImportPathConfig {
         ImportPathConfig {
             prefer_no_std: self.prefer_no_std,
             prefer_prelude: self.prefer_prelude,
             prefer_absolute: self.prefer_absolute,
+            allow_unstable,
         }
     }
 }
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 3a2a4a23a19..2f1860cbb59 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -443,7 +443,9 @@ pub(crate) struct CompletionContext<'a> {
     /// The module of the `scope`.
     pub(crate) module: hir::Module,
     /// Whether nightly toolchain is used. Cached since this is looked up a lot.
-    is_nightly: bool,
+    pub(crate) is_nightly: bool,
+    /// The edition of the current crate
+    // FIXME: This should probably be the crate of the current token?
     pub(crate) edition: Edition,
 
     /// The expected name of what we are completing.
@@ -532,7 +534,7 @@ impl CompletionContext<'_> {
         }
     }
 
-    /// Checks if an item is visible and not `doc(hidden)` at the completion site.
+    /// Checks if an item is visible, not `doc(hidden)` and stable at the completion site.
     pub(crate) fn is_visible<I>(&self, item: &I) -> Visible
     where
         I: hir::HasVisibility + hir::HasAttrs + hir::HasCrate + Copy,
@@ -568,6 +570,15 @@ impl CompletionContext<'_> {
         !attrs.is_unstable() || self.is_nightly
     }
 
+    pub(crate) fn check_stability_and_hidden<I>(&self, item: I) -> bool
+    where
+        I: hir::HasAttrs + hir::HasCrate,
+    {
+        let defining_crate = item.krate(self.db);
+        let attrs = item.attrs(self.db);
+        self.check_stability(Some(&attrs)) && !self.is_doc_hidden(&attrs, defining_crate)
+    }
+
     /// Whether the given trait is an operator trait or not.
     pub(crate) fn is_ops_trait(&self, trait_: hir::Trait) -> bool {
         match trait_.attrs(self.db).lang() {
@@ -645,6 +656,10 @@ impl CompletionContext<'_> {
         attrs: &hir::Attrs,
         defining_crate: hir::Crate,
     ) -> Visible {
+        if !self.check_stability(Some(attrs)) {
+            return Visible::No;
+        }
+
         if !vis.is_visible_from(self.db, self.module.into()) {
             if !self.config.enable_private_editable {
                 return Visible::No;
@@ -664,7 +679,7 @@ impl CompletionContext<'_> {
         }
     }
 
-    fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
+    pub(crate) fn is_doc_hidden(&self, attrs: &hir::Attrs, defining_crate: hir::Crate) -> bool {
         // `doc(hidden)` items are only completed within the defining crate.
         self.krate != defining_crate && attrs.has_doc_hidden()
     }
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 3c4d489c0ff..f5a50ae8190 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
@@ -5,7 +5,7 @@ use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant};
 use ide_db::{active_parameter::ActiveParameter, RootDatabase};
 use itertools::Either;
 use syntax::{
-    algo::{ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
+    algo::{self, ancestors_at_offset, find_node_at_offset, non_trivia_sibling},
     ast::{
         self, AttrKind, HasArgList, HasGenericArgs, HasGenericParams, HasLoopBody, HasName,
         NameOrNameRef,
@@ -85,6 +85,11 @@ pub(super) fn expand_and_analyze(
     })
 }
 
+fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Option<SyntaxToken> {
+    let token = file.token_at_offset(offset).left_biased()?;
+    algo::skip_whitespace_token(token, Direction::Prev)
+}
+
 /// Expand attributes and macro calls at the current cursor position for both the original file
 /// and fake file repeatedly. As soon as one of the two expansions fail we stop so the original
 /// and speculative states stay in sync.
@@ -125,9 +130,7 @@ fn expand(
 
     // Left biased since there may already be an identifier token there, and we appended to it.
     if !sema.might_be_inside_macro_call(&fake_ident_token)
-        && original_file
-            .token_at_offset(original_offset + relative_offset)
-            .left_biased()
+        && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
             .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
     {
         // Recursion base case.
@@ -143,9 +146,11 @@ fn expand(
 
     let parent_item =
         |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
+    let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset)
+        .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
     let ancestor_items = iter::successors(
         Option::zip(
-            find_node_at_offset::<ast::Item>(&original_file, original_offset),
+            original_node,
             find_node_at_offset::<ast::Item>(
                 &speculative_file,
                 fake_ident_token.text_range().start(),
@@ -1590,11 +1595,11 @@ fn pattern_context_for(
                                         }).map(|enum_| enum_.variants(sema.db))
                                     })
                                 }).map(|variants| variants.iter().filter_map(|variant| {
-                                        let variant_name = variant.name(sema.db).unescaped().display(sema.db).to_string();
+                                        let variant_name = variant.name(sema.db);
 
                                         let variant_already_present = match_arm_list.arms().any(|arm| {
                                             arm.pat().and_then(|pat| {
-                                                let pat_already_present = pat.syntax().to_string().contains(&variant_name);
+                                                let pat_already_present = pat.syntax().to_string().contains(variant_name.as_str());
                                                 pat_already_present.then_some(pat_already_present)
                                             }).is_some()
                                         });
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 dc2f9a76802..41a82409597 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/item.rs
@@ -82,8 +82,7 @@ pub struct CompletionItem {
     pub ref_match: Option<(CompletionItemRefMode, TextSize)>,
 
     /// The import data to add to completion's edits.
-    /// (ImportPath, LastSegment)
-    pub import_to_add: SmallVec<[(String, String); 1]>,
+    pub import_to_add: SmallVec<[String; 1]>,
 }
 
 #[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
@@ -181,6 +180,8 @@ pub struct CompletionRelevance {
     pub postfix_match: Option<CompletionRelevancePostfixMatch>,
     /// This is set for items that are function (associated or method)
     pub function: Option<CompletionRelevanceFn>,
+    /// true when there is an `await.method()` or `iter().method()` completion.
+    pub is_skipping_completion: bool,
 }
 #[derive(Debug, Clone, Copy, Eq, PartialEq)]
 pub struct CompletionRelevanceTraitInfo {
@@ -269,6 +270,7 @@ impl CompletionRelevance {
             postfix_match,
             trait_,
             function,
+            is_skipping_completion,
         } = self;
 
         // only applicable for completions within use items
@@ -296,6 +298,12 @@ impl CompletionRelevance {
                 score -= 5;
             }
         }
+
+        // Lower rank for completions that skip `await` and `iter()`.
+        if is_skipping_completion {
+            score -= 7;
+        }
+
         // lower rank for items that need an import
         if requires_import {
             score -= 1;
@@ -561,12 +569,7 @@ impl Builder {
         let import_to_add = self
             .imports_to_add
             .into_iter()
-            .filter_map(|import| {
-                Some((
-                    import.import_path.display(db, self.edition).to_string(),
-                    import.import_path.segments().last()?.display(db, self.edition).to_string(),
-                ))
-            })
+            .map(|import| import.import_path.display(db, self.edition).to_string())
             .collect();
 
         CompletionItem {
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 56d7eeaf8ea..8051d48ca5f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -10,17 +10,13 @@ mod snippet;
 #[cfg(test)]
 mod tests;
 
-use ide_db::text_edit::TextEdit;
 use ide_db::{
-    helpers::mod_path_to_ast,
-    imports::{
-        import_assets::NameToImport,
-        insert_use::{self, ImportScope},
-    },
-    items_locator,
+    imports::insert_use::{self, ImportScope},
     syntax_helpers::tree_diff::diff,
+    text_edit::TextEdit,
     FilePosition, FxHashSet, RootDatabase,
 };
+use syntax::ast::make;
 
 use crate::{
     completions::Completions,
@@ -272,7 +268,7 @@ pub fn resolve_completion_edits(
     db: &RootDatabase,
     config: &CompletionConfig<'_>,
     FilePosition { file_id, offset }: FilePosition,
-    imports: impl IntoIterator<Item = (String, String)>,
+    imports: impl IntoIterator<Item = String>,
 ) -> Option<Vec<TextEdit>> {
     let _p = tracing::info_span!("resolve_completion_edits").entered();
     let sema = hir::Semantics::new(db);
@@ -289,27 +285,12 @@ pub fn resolve_completion_edits(
     let new_ast = scope.clone_for_update();
     let mut import_insert = TextEdit::builder();
 
-    let cfg = config.import_path_config();
-
-    imports.into_iter().for_each(|(full_import_path, imported_name)| {
-        let items_with_name = items_locator::items_with_name(
-            &sema,
-            current_crate,
-            NameToImport::exact_case_sensitive(imported_name),
-            items_locator::AssocSearchMode::Include,
+    imports.into_iter().for_each(|full_import_path| {
+        insert_use::insert_use(
+            &new_ast,
+            make::path_from_text_with_edition(&full_import_path, current_edition),
+            &config.insert_use,
         );
-        let import = items_with_name
-            .filter_map(|candidate| {
-                current_module.find_use_path(db, candidate, config.insert_use.prefix_kind, cfg)
-            })
-            .find(|mod_path| mod_path.display(db, current_edition).to_string() == full_import_path);
-        if let Some(import_path) = import {
-            insert_use::insert_use(
-                &new_ast,
-                mod_path_to_ast(&import_path, current_edition),
-                &config.insert_use,
-            );
-        }
     });
 
     diff(scope.as_syntax_node(), new_ast.as_syntax_node()).into_text_edit(&mut import_insert);
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 61e8114d381..dc7eacbfbaf 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render.rs
@@ -130,10 +130,8 @@ pub(crate) fn render_field(
     let db = ctx.db();
     let is_deprecated = ctx.is_deprecated(field);
     let name = field.name(db);
-    let (name, escaped_name) = (
-        name.unescaped().display(db).to_smolstr(),
-        name.display_no_db(ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr());
     let mut item = CompletionItem::new(
         SymbolKind::Field,
         ctx.source_range(),
@@ -142,7 +140,8 @@ pub(crate) fn render_field(
     );
     item.set_relevance(CompletionRelevance {
         type_match: compute_type_match(ctx.completion, ty),
-        exact_name_match: compute_exact_name_match(ctx.completion, name.as_str()),
+        exact_name_match: compute_exact_name_match(ctx.completion, &name),
+        is_skipping_completion: receiver.is_some(),
         ..CompletionRelevance::default()
     });
     item.detail(ty.display(db, ctx.completion.edition).to_string())
@@ -215,6 +214,10 @@ pub(crate) fn render_tuple_field(
     );
     item.detail(ty.display(ctx.db(), ctx.completion.edition).to_string())
         .lookup_by(field.to_string());
+    item.set_relevance(CompletionRelevance {
+        is_skipping_completion: receiver.is_some(),
+        ..ctx.completion_relevance()
+    });
     item.build(ctx.db())
 }
 
@@ -298,7 +301,7 @@ pub(crate) fn render_expr(
             .unwrap_or_else(|| String::from("..."))
     };
 
-    let cfg = ctx.config.import_path_config();
+    let cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     let label = expr.gen_source_code(&ctx.scope, &mut label_formatter, cfg, ctx.edition).ok()?;
 
@@ -512,7 +515,7 @@ fn render_resolution_simple_(
     let mut item = CompletionItem::new(
         kind,
         ctx.source_range(),
-        local_name.unescaped().display(db).to_smolstr(),
+        local_name.as_str().to_smolstr(),
         ctx.completion.edition,
     );
     item.set_relevance(ctx.completion_relevance())
@@ -1335,6 +1338,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                         trigger_call_info: true,
                     },
@@ -1364,6 +1368,7 @@ fn main() { let _: m::Spam = S$0 }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                         trigger_call_info: true,
                     },
@@ -1453,6 +1458,7 @@ fn foo() { A { the$0 } }
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -1511,6 +1517,7 @@ impl S {
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                     },
                     CompletionItem {
@@ -1653,6 +1660,7 @@ fn foo(s: S) { s.$0 }
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -1864,6 +1872,7 @@ fn f() -> i32 {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -2624,6 +2633,7 @@ fn foo(f: Foo) { let _: &u32 = f.b$0 }
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                         ref_match: "&@107",
                     },
@@ -2709,6 +2719,7 @@ fn foo() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
@@ -2766,6 +2777,7 @@ fn main() {
                                     return_type: Other,
                                 },
                             ),
+                            is_skipping_completion: false,
                         },
                         ref_match: "&@92",
                     },
@@ -3140,6 +3152,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                     CompletionItem {
@@ -3173,6 +3186,7 @@ fn main() {
                             is_private_editable: false,
                             postfix_match: None,
                             function: None,
+                            is_skipping_completion: false,
                         },
                     },
                 ]
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 415d87c6239..e357ab24d22 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
@@ -14,10 +14,8 @@ pub(crate) fn render_const(ctx: RenderContext<'_>, const_: hir::Const) -> Option
 fn render(ctx: RenderContext<'_>, const_: hir::Const) -> Option<CompletionItem> {
     let db = ctx.db();
     let name = const_.name(db)?;
-    let (name, escaped_name) = (
-        name.unescaped().display(db).to_smolstr(),
-        name.display(db, ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str().to_smolstr(), name.display(db, ctx.completion.edition).to_smolstr());
     let detail = const_.display(db, ctx.completion.edition).to_string();
 
     let mut item =
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 3b97d67169e..c3354902c3b 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
@@ -59,13 +59,10 @@ fn render(
 
     let (call, escaped_call) = match &func_kind {
         FuncKind::Method(_, Some(receiver)) => (
-            format_smolstr!("{}.{}", receiver, name.unescaped().display(ctx.db())),
+            format_smolstr!("{}.{}", receiver, name.as_str()),
             format_smolstr!("{}.{}", receiver, name.display(ctx.db(), completion.edition)),
         ),
-        _ => (
-            name.unescaped().display(db).to_smolstr(),
-            name.display(db, completion.edition).to_smolstr(),
-        ),
+        _ => (name.as_str().to_smolstr(), name.display(db, completion.edition).to_smolstr()),
     };
     let has_self_param = func.self_param(db).is_some();
     let mut item = CompletionItem::new(
@@ -126,6 +123,7 @@ fn render(
         exact_name_match: compute_exact_name_match(completion, &call),
         function,
         trait_: trait_info,
+        is_skipping_completion: matches!(func_kind, FuncKind::Method(_, Some(_))),
         ..ctx.completion_relevance()
     });
 
@@ -151,7 +149,7 @@ fn render(
     item.set_documentation(ctx.docs(func))
         .set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
         .detail(detail)
-        .lookup_by(name.unescaped().display(db).to_smolstr());
+        .lookup_by(name.as_str().to_smolstr());
 
     if let Some((cap, (self_param, params))) = complete_call_parens {
         add_call_parens(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
index c71356e5300..aab54ca5e01 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/literal.rs
@@ -75,7 +75,7 @@ fn render(
         None => (name.clone().into(), name.into(), false),
     };
     let (qualified_name, escaped_qualified_name) = (
-        qualified_name.unescaped().display(ctx.db()).to_string(),
+        qualified_name.display_verbatim(ctx.db()).to_string(),
         qualified_name.display(ctx.db(), completion.edition).to_string(),
     );
     let snippet_cap = ctx.snippet_cap();
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
index 6490171fbb4..e265e92f979 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs
@@ -46,21 +46,19 @@ fn render(
         ctx.source_range()
     };
 
-    let (name, escaped_name) = (
-        name.unescaped().display(ctx.db()).to_smolstr(),
-        name.display(ctx.db(), completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str(), name.display(ctx.db(), completion.edition).to_smolstr());
     let docs = ctx.docs(macro_);
     let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
     let is_fn_like = macro_.is_fn_like(completion.db);
-    let (bra, ket) = if is_fn_like { guess_macro_braces(&name, docs_str) } else { ("", "") };
+    let (bra, ket) = if is_fn_like { guess_macro_braces(name, docs_str) } else { ("", "") };
 
     let needs_bang = is_fn_like && !is_use_path && !has_macro_bang;
 
     let mut item = CompletionItem::new(
         SymbolKind::from(macro_.kind(completion.db)),
         source_range,
-        label(&ctx, needs_bang, bra, ket, &name),
+        label(&ctx, needs_bang, bra, ket, &name.to_smolstr()),
         completion.edition,
     );
     item.set_deprecated(ctx.is_deprecated(macro_))
@@ -71,11 +69,11 @@ fn render(
     match ctx.snippet_cap() {
         Some(cap) if needs_bang && !has_call_parens => {
             let snippet = format!("{escaped_name}!{bra}$0{ket}");
-            let lookup = banged_name(&name);
+            let lookup = banged_name(name);
             item.insert_snippet(cap, snippet).lookup_by(lookup);
         }
         _ if needs_bang => {
-            item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(&name));
+            item.insert_text(banged_name(&escaped_name)).lookup_by(banged_name(name));
         }
         _ => {
             cov_mark::hit!(dont_insert_macro_call_parens_unnecessary);
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 5675dfb5c6f..124abb17b6a 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
@@ -31,13 +31,11 @@ pub(crate) fn render_struct_pat(
     }
 
     let name = local_name.unwrap_or_else(|| strukt.name(ctx.db()));
-    let (name, escaped_name) = (
-        name.unescaped().display(ctx.db()).to_smolstr(),
-        name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
-    );
+    let (name, escaped_name) =
+        (name.as_str(), name.display(ctx.db(), ctx.completion.edition).to_smolstr());
     let kind = strukt.kind(ctx.db());
-    let label = format_literal_label(name.as_str(), kind, ctx.snippet_cap());
-    let lookup = format_literal_lookup(name.as_str(), kind);
+    let label = format_literal_label(name, kind, ctx.snippet_cap());
+    let lookup = format_literal_lookup(name, kind);
     let pat = render_pat(&ctx, pattern_ctx, &escaped_name, kind, &visible_fields, fields_omitted)?;
 
     let db = ctx.db();
@@ -61,13 +59,13 @@ pub(crate) fn render_variant_pat(
 
     let (name, escaped_name) = match path {
         Some(path) => (
-            path.unescaped().display(ctx.db()).to_string().into(),
-            path.display(ctx.db(), ctx.completion.edition).to_string().into(),
+            path.display_verbatim(ctx.db()).to_smolstr(),
+            path.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
         None => {
             let name = local_name.unwrap_or_else(|| variant.name(ctx.db()));
             let it = (
-                name.unescaped().display(ctx.db()).to_smolstr(),
+                name.as_str().to_smolstr(),
                 name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
             );
             it
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 09eb19201c5..1b952f31360 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
@@ -32,14 +32,11 @@ fn render(
     let name = type_alias.name(db);
     let (name, escaped_name) = if with_eq {
         (
-            SmolStr::from_iter([&name.unescaped().display(db).to_smolstr(), " = "]),
+            SmolStr::from_iter([&name.as_str().to_smolstr(), " = "]),
             SmolStr::from_iter([&name.display_no_db(ctx.completion.edition).to_smolstr(), " = "]),
         )
     } else {
-        (
-            name.unescaped().display(db).to_smolstr(),
-            name.display_no_db(ctx.completion.edition).to_smolstr(),
-        )
+        (name.as_str().to_smolstr(), name.display_no_db(ctx.completion.edition).to_smolstr())
     };
     let detail = type_alias.display(db, ctx.completion.edition).to_string();
 
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
index e053e299d90..74203626521 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/union_literal.rs
@@ -23,12 +23,12 @@ pub(crate) fn render_union_literal(
 
     let (qualified_name, escaped_qualified_name) = match path {
         Some(p) => (
-            p.unescaped().display(ctx.db()).to_string(),
-            p.display(ctx.db(), ctx.completion.edition).to_string(),
+            p.display_verbatim(ctx.db()).to_smolstr(),
+            p.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
         None => (
-            name.unescaped().display(ctx.db()).to_string(),
-            name.display(ctx.db(), ctx.completion.edition).to_string(),
+            name.as_str().to_smolstr(),
+            name.display(ctx.db(), ctx.completion.edition).to_smolstr(),
         ),
     };
     let label = format_literal_label(
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
index 04bb178c658..866b83a6146 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
@@ -164,7 +164,7 @@ impl Snippet {
 }
 
 fn import_edits(ctx: &CompletionContext<'_>, requires: &[ModPath]) -> Option<Vec<LocatedImport>> {
-    let import_cfg = ctx.config.import_path_config();
+    let import_cfg = ctx.config.import_path_config(ctx.is_nightly);
 
     let resolve = |import| {
         let item = ctx.scope.resolve_mod_path(import).next()?;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
index b7dbf0a6306..9d91f95eb65 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests.rs
@@ -87,6 +87,8 @@ pub(crate) const TEST_CONFIG: CompletionConfig<'_> = CompletionConfig {
     fields_to_resolve: CompletionFieldsToResolve::empty(),
     exclude_flyimport: vec![],
     exclude_traits: &[],
+    enable_auto_await: true,
+    enable_auto_iter: true,
 };
 
 pub(crate) fn completion_list(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
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 e117dbf4bdf..663a038580d 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
@@ -1965,3 +1965,24 @@ fn bar() {
         "#]],
     );
 }
+
+#[test]
+fn doc_hidden_enum_variant() {
+    check(
+        r#"
+//- /foo.rs crate:foo
+pub enum Enum {
+    #[doc(hidden)] Hidden,
+    Visible,
+}
+
+//- /lib.rs crate:lib deps:foo
+fn foo() {
+    let _ = foo::Enum::$0;
+}
+    "#,
+        expect![[r#"
+            ev Visible Visible
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
index d491e438fef..2e7c53def7f 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs
@@ -1391,6 +1391,41 @@ pub struct FooStruct {}
 }
 
 #[test]
+fn flyimport_pattern_unstable_path() {
+    check(
+        r#"
+//- /main.rs crate:main deps:std
+fn function() {
+    let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+    pub struct FooStruct {}
+}
+"#,
+        expect![""],
+    );
+    check(
+        r#"
+//- toolchain:nightly
+//- /main.rs crate:main deps:std
+fn function() {
+    let foo$0
+}
+//- /std.rs crate:std
+#[unstable]
+pub mod unstable {
+    pub struct FooStruct {}
+}
+"#,
+        expect![[r#"
+            st FooStruct (use std::unstable::FooStruct)
+        "#]],
+    );
+}
+
+#[test]
 fn flyimport_pattern_unstable_item_on_nightly() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
index 04b3a47a64d..593b1edde5c 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/use_tree.rs
@@ -451,3 +451,20 @@ marco_rules! m { () => {} }
         "#]],
     );
 }
+
+#[test]
+fn use_tree_doc_hidden() {
+    check(
+        r#"
+//- /foo.rs crate:foo
+#[doc(hidden)] pub struct Hidden;
+pub struct Visible;
+
+//- /lib.rs crate:lib deps:foo
+use foo::$0;
+    "#,
+        expect![[r#"
+            st Visible Visible
+        "#]],
+    );
+}
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 49d26dfe25c..d12bda0816f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -794,7 +794,7 @@ impl NameRefClass {
                                 hir::AssocItem::TypeAlias(it) => Some(it),
                                 _ => None,
                             })
-                            .find(|alias| alias.name(sema.db).eq_ident(name_ref.text().as_str()))
+                            .find(|alias| alias.name(sema.db).as_str() == name_ref.text().trim_start_matches("r#"))
                         {
                             // No substitution, this can only occur in type position.
                             return Some(NameRefClass::Definition(Definition::TypeAlias(ty), None));
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 9e3506d6f53..2f4d07446f2 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
@@ -46,6 +46,10 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:cmp:Ord")
     }
 
+    pub fn core_convert_FromStr(&self) -> Option<Trait> {
+        self.find_trait("core:str:FromStr")
+    }
+
     pub fn core_convert_From(&self) -> Option<Trait> {
         self.find_trait("core:convert:From")
     }
@@ -54,6 +58,14 @@ impl FamousDefs<'_, '_> {
         self.find_trait("core:convert:Into")
     }
 
+    pub fn core_convert_TryFrom(&self) -> Option<Trait> {
+        self.find_trait("core:convert:TryFrom")
+    }
+
+    pub fn core_convert_TryInto(&self) -> Option<Trait> {
+        self.find_trait("core:convert:TryInto")
+    }
+
     pub fn core_convert_Index(&self) -> Option<Trait> {
         self.find_trait("core:ops:Index")
     }
@@ -130,6 +142,13 @@ impl FamousDefs<'_, '_> {
         self.find_macro("core:unimplemented")
     }
 
+    pub fn core_fmt_Display(&self) -> Option<Trait> {
+        self.find_trait("core:fmt:Display")
+    }
+
+    pub fn alloc_string_ToString(&self) -> Option<Trait> {
+        self.find_trait("alloc:string:ToString")
+    }
     pub fn builtin_crates(&self) -> impl Iterator<Item = Crate> {
         IntoIterator::into_iter([
             self.std(),
@@ -202,14 +221,15 @@ impl FamousDefs<'_, '_> {
         for segment in path {
             module = module.children(db).find_map(|child| {
                 let name = child.name(db)?;
-                if name.eq_ident(segment) {
+                if name.as_str() == segment {
                     Some(child)
                 } else {
                     None
                 }
             })?;
         }
-        let def = module.scope(db, None).into_iter().find(|(name, _def)| name.eq_ident(trait_))?.1;
+        let def =
+            module.scope(db, None).into_iter().find(|(name, _def)| name.as_str() == trait_)?.1;
         Some(def)
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
index a045c22c2df..f045e44dd31 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/path_transform.rs
@@ -319,6 +319,7 @@ impl Ctx<'_> {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             };
                             let found_path = self.target_module.find_path(
                                 self.source_scope.db.upcast(),
@@ -378,6 +379,7 @@ impl Ctx<'_> {
                     prefer_no_std: false,
                     prefer_prelude: true,
                     prefer_absolute: false,
+                    allow_unstable: true,
                 };
                 let found_path =
                     self.target_module.find_path(self.source_scope.db.upcast(), def, cfg)?;
@@ -417,6 +419,7 @@ impl Ctx<'_> {
                             prefer_no_std: false,
                             prefer_prelude: true,
                             prefer_absolute: false,
+                            allow_unstable: true,
                         };
                         let found_path = self.target_module.find_path(
                             self.source_scope.db.upcast(),
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
index 42efbd68e33..59914bedde4 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/rename.rs
@@ -263,13 +263,12 @@ fn rename_mod(
         //  - Module has submodules defined in separate files
         let dir_paths = match (is_mod_rs, has_detached_child, module.name(sema.db)) {
             // Go up one level since the anchor is inside the dir we're trying to rename
-            (true, _, Some(mod_name)) => Some((
-                format!("../{}", mod_name.unescaped().display(sema.db)),
-                format!("../{new_name}"),
-            )),
+            (true, _, Some(mod_name)) => {
+                Some((format!("../{}", mod_name.as_str()), format!("../{new_name}")))
+            }
             // The anchor is on the same level as target dir
             (false, true, Some(mod_name)) => {
-                Some((mod_name.unescaped().display(sema.db).to_string(), new_name.to_owned()))
+                Some((mod_name.as_str().to_owned(), new_name.to_owned()))
             }
             _ => None,
         };
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index a75aba137be..7fc563a4241 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -625,7 +625,7 @@ impl<'a> FindUsages<'a> {
             let _p = tracing::info_span!("collect_possible_aliases").entered();
 
             let db = sema.db;
-            let container_name = container.name(db).unescaped().display(db).to_smolstr();
+            let container_name = container.name(db).as_str().to_smolstr();
             let search_scope = Definition::from(container).search_scope(db);
             let mut seen = FxHashSet::default();
             let mut completed = FxHashSet::default();
@@ -925,12 +925,8 @@ impl<'a> FindUsages<'a> {
                             .or_else(|| ty.as_builtin().map(|builtin| builtin.name()))
                     })
                 };
-                // We need to unescape the name in case it is written without "r#" in earlier
-                // editions of Rust where it isn't a keyword.
-                self.def
-                    .name(sema.db)
-                    .or_else(self_kw_refs)
-                    .map(|it| it.unescaped().display(sema.db).to_smolstr())
+                // We need to search without the `r#`, hence `as_str` access.
+                self.def.name(sema.db).or_else(self_kw_refs).map(|it| it.as_str().to_smolstr())
             }
         };
         let name = match &name {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index c94644eeb89..e5ce10a771e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -143,7 +143,7 @@ fn library_symbols(db: &dyn SymbolsDatabase, source_root_id: SourceRootId) -> Ar
 fn module_symbols(db: &dyn SymbolsDatabase, module: Module) -> Arc<SymbolIndex> {
     let _p = tracing::info_span!("module_symbols").entered();
 
-    Arc::new(SymbolIndex::new(SymbolCollector::collect_module(db.upcast(), module)))
+    Arc::new(SymbolIndex::new(SymbolCollector::new_module(db.upcast(), module)))
 }
 
 pub fn crate_symbols(db: &dyn SymbolsDatabase, krate: Crate) -> Box<[Arc<SymbolIndex>]> {
@@ -284,13 +284,15 @@ impl SymbolIndex {
             builder.insert(key, value).unwrap();
         }
 
-        // FIXME: fst::Map should ideally have a way to shrink the backing buffer without the unwrap dance
-        let map = fst::Map::new({
-            let mut buf = builder.into_inner().unwrap();
-            buf.shrink_to_fit();
-            buf
-        })
-        .unwrap();
+        let map = builder
+            .into_inner()
+            .and_then(|mut buf| {
+                fst::Map::new({
+                    buf.shrink_to_fit();
+                    buf
+                })
+            })
+            .unwrap();
         SymbolIndex { symbols, map }
     }
 
@@ -491,7 +493,7 @@ pub(self) use crate::Trait as IsThisJustATrait;
             .modules(&db)
             .into_iter()
             .map(|module_id| {
-                let mut symbols = SymbolCollector::collect_module(&db, module_id);
+                let mut symbols = SymbolCollector::new_module(&db, module_id);
                 symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
@@ -518,7 +520,7 @@ struct Duplicate;
             .modules(&db)
             .into_iter()
             .map(|module_id| {
-                let mut symbols = SymbolCollector::collect_module(&db, module_id);
+                let mut symbols = SymbolCollector::new_module(&db, module_id);
                 symbols.sort_by_key(|it| it.name.as_str().to_owned());
                 (module_id, symbols)
             })
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
index 557c95f704b..0a7141c19b6 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -31,6 +31,12 @@ const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
 /// `Result<User, Error>` -> `User`
 const WRAPPER_TYPES: &[&str] = &["Box", "Arc", "Rc", "Option", "Result"];
 
+/// Generic types replaced by a plural of their first argument.
+///
+/// # Examples
+/// `Vec<Name>` -> "names"
+const SEQUENCE_TYPES: &[&str] = &["Vec", "VecDeque", "LinkedList"];
+
 /// Prefixes to strip from methods names
 ///
 /// # Examples
@@ -378,6 +384,11 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
             return name_of_type(&inner_ty, db, edition);
         }
 
+        if SEQUENCE_TYPES.contains(&name.as_str()) {
+            let inner_ty = ty.type_arguments().next();
+            return Some(sequence_name(inner_ty.as_ref(), db, edition));
+        }
+
         name
     } else if let Some(trait_) = ty.as_dyn_trait() {
         trait_name(&trait_, db, edition)?
@@ -390,12 +401,32 @@ fn name_of_type(ty: &hir::Type, db: &RootDatabase, edition: Edition) -> Option<S
         name
     } else if let Some(inner_ty) = ty.remove_ref() {
         return name_of_type(&inner_ty, db, edition);
+    } else if let Some(inner_ty) = ty.as_slice() {
+        return Some(sequence_name(Some(&inner_ty), db, edition));
     } else {
         return None;
     };
     normalize(&name)
 }
 
+fn sequence_name(inner_ty: Option<&hir::Type>, db: &RootDatabase, edition: Edition) -> SmolStr {
+    let items_str = SmolStr::new_static("items");
+    let Some(inner_ty) = inner_ty else {
+        return items_str;
+    };
+    let Some(name) = name_of_type(inner_ty, db, edition) else {
+        return items_str;
+    };
+
+    if name.ends_with(['s', 'x', 'y']) {
+        // Given a type called e.g. "Boss", "Fox" or "Story", don't try to
+        // create a plural.
+        items_str
+    } else {
+        SmolStr::new(format!("{name}s"))
+    }
+}
+
 fn trait_name(trait_: &hir::Trait, db: &RootDatabase, edition: Edition) -> Option<String> {
     let name = trait_.name(db).display(db, edition).to_string();
     if USELESS_TRAITS.contains(&name.as_str()) {
@@ -898,6 +929,58 @@ fn foo() { $0(bar())$0; }
     }
 
     #[test]
+    fn vec_value() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Seed;
+fn bar() -> Vec<Seed> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
+    fn vec_value_ends_with_s() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Boss;
+fn bar() -> Vec<Boss> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "items",
+        );
+    }
+
+    #[test]
+    fn vecdeque_value() {
+        check(
+            r#"
+struct VecDeque<T> {};
+struct Seed;
+fn bar() -> VecDeque<Seed> {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
+    fn slice_value() {
+        check(
+            r#"
+struct Vec<T> {};
+struct Seed;
+fn bar() -> &[Seed] {}
+fn foo() { $0(bar())$0; }
+"#,
+            "seeds",
+        );
+    }
+
+    #[test]
     fn ref_call() {
         check(
             r#"
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
index 535777dfcbe..7dce95592b8 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
+++ b/src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt
@@ -1007,6 +1007,39 @@
                 is_alias: false,
                 is_assoc: false,
             },
+            FileSymbol {
+                name: "ThisStruct",
+                def: Adt(
+                    Struct(
+                        Struct {
+                            id: StructId(
+                                4,
+                            ),
+                        },
+                    ),
+                ),
+                loc: DeclarationLocation {
+                    hir_file_id: EditionedFileId(
+                        FileId(
+                            1,
+                        ),
+                        Edition2021,
+                    ),
+                    ptr: SyntaxNodePtr {
+                        kind: USE_TREE,
+                        range: 85..125,
+                    },
+                    name_ptr: AstPtr(
+                        SyntaxNodePtr {
+                            kind: NAME,
+                            range: 115..125,
+                        },
+                    ),
+                },
+                container_name: None,
+                is_alias: false,
+                is_assoc: false,
+            },
         ],
     ),
 ]
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
index 515bc418cb4..2fdd8358637 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/ty_filter.rs
@@ -26,7 +26,7 @@ impl TryEnum {
             _ => return None,
         };
         TryEnum::ALL.iter().find_map(|&var| {
-            if enum_.name(sema.db).eq_ident(var.type_name()) {
+            if enum_.name(sema.db).as_str() == var.type_name() {
                 return Some(var);
             }
             None
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 dca889d1a8e..f22041ebe23 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
@@ -147,6 +147,7 @@ pub(crate) fn json_in_items(
                             prefer_no_std: config.prefer_no_std,
                             prefer_prelude: config.prefer_prelude,
                             prefer_absolute: config.prefer_absolute,
+                            allow_unstable: true,
                         };
 
                         if !scope_has("Serialize") {
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 fd1044e51bc..938b7182bc9 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
@@ -128,6 +128,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                                 prefer_no_std: ctx.config.prefer_no_std,
                                 prefer_prelude: ctx.config.prefer_prelude,
                                 prefer_absolute: ctx.config.prefer_absolute,
+                                allow_unstable: ctx.is_nightly,
                             },
                         )?;
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
index 3ad84f7bda2..b023a95fb35 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/typed_hole.rs
@@ -70,6 +70,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::TypedHole) -> Option<Vec<Assist>
                     prefer_no_std: ctx.config.prefer_no_std,
                     prefer_prelude: ctx.config.prefer_prelude,
                     prefer_absolute: ctx.config.prefer_absolute,
+                    allow_unstable: ctx.is_nightly,
                 },
                 ctx.edition,
             )
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index 13591dfb2ee..f3109b9bb73 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -112,7 +112,7 @@ fn fixes(
                 // shouldn't occur
                 _ => continue 'crates,
             };
-            match current.children.iter().find(|(name, _)| name.eq_ident(seg)) {
+            match current.children.iter().find(|(name, _)| name.as_str() == seg) {
                 Some((_, &child)) => current = &crate_def_map[child],
                 None => continue 'crates,
             }
@@ -161,7 +161,7 @@ fn fixes(
             // try finding a parent that has an inline tree from here on
             let mut current = module;
             for s in stack.iter().rev() {
-                match module.children.iter().find(|(name, _)| name.eq_ident(s)) {
+                match module.children.iter().find(|(name, _)| name.as_str() == s) {
                     Some((_, child)) => {
                         current = &crate_def_map[*child];
                     }
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 1e99d7ad6e6..50c91a69602 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -83,7 +83,7 @@ use either::Either;
 use hir::{db::ExpandDatabase, diagnostics::AnyDiagnostic, Crate, HirFileId, InFile, Semantics};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
-    base_db::SourceDatabase,
+    base_db::{ReleaseChannel, SourceDatabase},
     generated::lints::{Lint, LintGroup, CLIPPY_LINT_GROUPS, DEFAULT_LINTS, DEFAULT_LINT_GROUPS},
     imports::insert_use::InsertUseConfig,
     label::Label,
@@ -276,6 +276,7 @@ struct DiagnosticsContext<'a> {
     sema: Semantics<'a, RootDatabase>,
     resolve: &'a AssistResolveStrategy,
     edition: Edition,
+    is_nightly: bool,
 }
 
 impl DiagnosticsContext<'_> {
@@ -368,7 +369,11 @@ pub fn semantic_diagnostics(
 
     let module = sema.file_to_module_def(file_id);
 
-    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition() };
+    let is_nightly = matches!(
+        module.and_then(|m| db.toolchain_channel(m.krate().into())),
+        Some(ReleaseChannel::Nightly) | None
+    );
+    let ctx = DiagnosticsContext { config, sema, resolve, edition: file_id.edition(), is_nightly };
 
     let mut diags = Vec::new();
     match module {
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 4edc3633fbe..4bead14e31d 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/matching.rs
@@ -673,6 +673,7 @@ impl Match {
                     prefer_no_std: false,
                     prefer_prelude: true,
                     prefer_absolute: false,
+                    allow_unstable: true,
                 };
                 let mod_path = module.find_path(sema.db, module_def, cfg).ok_or_else(|| {
                     match_error!("Failed to render template path `{}` at match location")
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 bc9843f3f35..cfd8919730a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -413,8 +413,7 @@ fn rewrite_url_link(db: &RootDatabase, def: Definition, target: &str) -> Option<
 fn mod_path_of_def(db: &RootDatabase, def: Definition) -> Option<String> {
     def.canonical_module_path(db).map(|it| {
         let mut path = String::new();
-        it.flat_map(|it| it.name(db))
-            .for_each(|name| format_to!(path, "{}/", name.unescaped().display(db)));
+        it.flat_map(|it| it.name(db)).for_each(|name| format_to!(path, "{}/", name.as_str()));
         path
     })
 }
@@ -590,10 +589,10 @@ fn filename_and_frag_for_def(
     let res = match def {
         Definition::Adt(adt) => match adt {
             Adt::Struct(s) => {
-                format!("struct.{}.html", s.name(db).unescaped().display(db.upcast()))
+                format!("struct.{}.html", s.name(db).as_str())
             }
-            Adt::Enum(e) => format!("enum.{}.html", e.name(db).unescaped().display(db.upcast())),
-            Adt::Union(u) => format!("union.{}.html", u.name(db).unescaped().display(db.upcast())),
+            Adt::Enum(e) => format!("enum.{}.html", e.name(db).as_str()),
+            Adt::Union(u) => format!("union.{}.html", u.name(db).as_str()),
         },
         Definition::Crate(_) => String::from("index.html"),
         Definition::Module(m) => match m.name(db) {
@@ -603,48 +602,48 @@ fn filename_and_frag_for_def(
                     Some(kw) => {
                         format!("keyword.{}.html", kw)
                     }
-                    None => format!("{}/index.html", name.unescaped().display(db.upcast())),
+                    None => format!("{}/index.html", name.as_str()),
                 }
             }
             None => String::from("index.html"),
         },
         Definition::Trait(t) => {
-            format!("trait.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("trait.{}.html", t.name(db).as_str())
         }
         Definition::TraitAlias(t) => {
-            format!("traitalias.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("traitalias.{}.html", t.name(db).as_str())
         }
         Definition::TypeAlias(t) => {
-            format!("type.{}.html", t.name(db).unescaped().display(db.upcast()))
+            format!("type.{}.html", t.name(db).as_str())
         }
         Definition::BuiltinType(t) => {
-            format!("primitive.{}.html", t.name().unescaped().display(db.upcast()))
+            format!("primitive.{}.html", t.name().as_str())
         }
         Definition::Function(f) => {
-            format!("fn.{}.html", f.name(db).unescaped().display(db.upcast()))
+            format!("fn.{}.html", f.name(db).as_str())
         }
         Definition::Variant(ev) => {
             format!(
                 "enum.{}.html#variant.{}",
-                ev.parent_enum(db).name(db).unescaped().display(db.upcast()),
-                ev.name(db).unescaped().display(db.upcast())
+                ev.parent_enum(db).name(db).as_str(),
+                ev.name(db).as_str()
             )
         }
         Definition::Const(c) => {
-            format!("const.{}.html", c.name(db)?.unescaped().display(db.upcast()))
+            format!("const.{}.html", c.name(db)?.as_str())
         }
         Definition::Static(s) => {
-            format!("static.{}.html", s.name(db).unescaped().display(db.upcast()))
+            format!("static.{}.html", s.name(db).as_str())
         }
         Definition::Macro(mac) => match mac.kind(db) {
             hir::MacroKind::Declarative
             | hir::MacroKind::BuiltIn
             | hir::MacroKind::Attr
             | hir::MacroKind::ProcMacro => {
-                format!("macro.{}.html", mac.name(db).unescaped().display(db.upcast()))
+                format!("macro.{}.html", mac.name(db).as_str())
             }
             hir::MacroKind::Derive => {
-                format!("derive.{}.html", mac.name(db).unescaped().display(db.upcast()))
+                format!("derive.{}.html", mac.name(db).as_str())
             }
         },
         Definition::Field(field) => {
@@ -654,11 +653,7 @@ fn filename_and_frag_for_def(
                 hir::VariantDef::Variant(it) => Definition::Variant(it),
             };
             let (_, file, _) = filename_and_frag_for_def(db, def)?;
-            return Some((
-                def,
-                file,
-                Some(format!("structfield.{}", field.name(db).unescaped().display(db.upcast()))),
-            ));
+            return Some((def, file, Some(format!("structfield.{}", field.name(db).as_str()))));
         }
         Definition::SelfType(impl_) => {
             let adt = impl_.self_ty(db).as_adt()?.into();
@@ -667,7 +662,7 @@ fn filename_and_frag_for_def(
             return Some((adt, file, Some(String::from("impl"))));
         }
         Definition::ExternCrateDecl(it) => {
-            format!("{}/index.html", it.name(db).unescaped().display(db.upcast()))
+            format!("{}/index.html", it.name(db).as_str())
         }
         Definition::Local(_)
         | Definition::GenericParam(_)
@@ -699,16 +694,16 @@ fn get_assoc_item_fragment(db: &dyn HirDatabase, assoc_item: hir::AssocItem) ->
             // Rustdoc makes this decision based on whether a method 'has defaultness'.
             // Currently this is only the case for provided trait methods.
             if is_trait_method && !function.has_body(db) {
-                format!("tymethod.{}", function.name(db).unescaped().display(db.upcast()))
+                format!("tymethod.{}", function.name(db).as_str())
             } else {
-                format!("method.{}", function.name(db).unescaped().display(db.upcast()))
+                format!("method.{}", function.name(db).as_str())
             }
         }
         AssocItem::Const(constant) => {
-            format!("associatedconstant.{}", constant.name(db)?.unescaped().display(db.upcast()))
+            format!("associatedconstant.{}", constant.name(db)?.as_str())
         }
         AssocItem::TypeAlias(ty) => {
-            format!("associatedtype.{}", ty.name(db).unescaped().display(db.upcast()))
+            format!("associatedtype.{}", ty.name(db).as_str())
         }
     })
 }
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 f804cc36772..d18732a6b84 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -5,10 +5,14 @@ use crate::{
     navigation_target::{self, ToNav},
     FilePosition, NavigationTarget, RangeInfo, TryToNav, UpmappingResult,
 };
-use hir::{AsAssocItem, AssocItem, FileRange, InFile, MacroFileIdExt, ModuleDef, Semantics};
+use hir::{
+    sym, AsAssocItem, AssocItem, CallableKind, FileRange, HasCrate, InFile, MacroFileIdExt,
+    ModuleDef, Semantics,
+};
 use ide_db::{
     base_db::{AnchoredPath, FileLoader, SourceDatabase},
     defs::{Definition, IdentClass},
+    famous_defs::FamousDefs,
     helpers::pick_best_token,
     RootDatabase, SymbolKind,
 };
@@ -129,15 +133,74 @@ pub(crate) fn goto_definition(
     Some(RangeInfo::new(original_token.text_range(), navs))
 }
 
-// If the token is into(), try_into(), parse(), search the definition of From, TryFrom, FromStr.
+// If the token is into(), try_into(), search the definition of From, TryFrom.
 fn find_definition_for_known_blanket_dual_impls(
     sema: &Semantics<'_, RootDatabase>,
     original_token: &SyntaxToken,
 ) -> Option<Vec<NavigationTarget>> {
     let method_call = ast::MethodCallExpr::cast(original_token.parent()?.parent()?)?;
-    let target_method = sema.resolve_known_blanket_dual_impls(&method_call)?;
+    let callable = sema.resolve_method_call_as_callable(&method_call)?;
+    let CallableKind::Function(f) = callable.kind() else { return None };
+    let assoc = f.as_assoc_item(sema.db)?;
+
+    let return_type = callable.return_type();
+    let fd = FamousDefs(sema, return_type.krate(sema.db));
+
+    let t = match assoc.container(sema.db) {
+        hir::AssocItemContainer::Trait(t) => t,
+        hir::AssocItemContainer::Impl(impl_)
+            if impl_.self_ty(sema.db).is_str() && f.name(sema.db) == sym::parse =>
+        {
+            let t = fd.core_convert_FromStr()?;
+            let t_f = t.function(sema.db, &sym::from_str)?;
+            return sema
+                .resolve_trait_impl_method(
+                    return_type.clone(),
+                    t,
+                    t_f,
+                    [return_type.type_arguments().next()?],
+                )
+                .map(|f| def_to_nav(sema.db, f.into()));
+        }
+        hir::AssocItemContainer::Impl(_) => return None,
+    };
 
-    let def = Definition::from(target_method);
+    let fn_name = f.name(sema.db);
+    let f = if fn_name == sym::into && fd.core_convert_Into() == Some(t) {
+        let dual = fd.core_convert_From()?;
+        let dual_f = dual.function(sema.db, &sym::from)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            [return_type, callable.receiver_param(sema.db)?.1],
+        )?
+    } else if fn_name == sym::try_into && fd.core_convert_TryInto() == Some(t) {
+        let dual = fd.core_convert_TryFrom()?;
+        let dual_f = dual.function(sema.db, &sym::try_from)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            // Extract the `T` from `Result<T, ..>`
+            [return_type.type_arguments().next()?, callable.receiver_param(sema.db)?.1],
+        )?
+    } else if fn_name == sym::to_string && fd.alloc_string_ToString() == Some(t) {
+        let dual = fd.core_fmt_Display()?;
+        let dual_f = dual.function(sema.db, &sym::fmt)?;
+        sema.resolve_trait_impl_method(
+            return_type.clone(),
+            dual,
+            dual_f,
+            [callable.receiver_param(sema.db)?.1.strip_reference()],
+        )?
+    } else {
+        return None;
+    };
+    // Assert that we got a trait impl function, if we are back in a trait definition we didn't
+    // succeed
+    let _t = f.as_assoc_item(sema.db)?.implemented_trait(sema.db)?;
+    let def = Definition::from(f);
     Some(def_to_nav(sema.db, def))
 }
 
@@ -3168,20 +3231,47 @@ fn f() {
             r#"
 //- minicore: from, str
 struct A;
-
 impl FromStr for A {
     type Error = String;
-
     fn from_str(value: &str) -> Result<Self, Self::Error> {
      //^^^^^^^^
         Ok(A)
     }
 }
-
 fn f() {
     let a: Result<A, _> = "aaaaaa".parse$0();
 }
         "#,
         );
     }
+
+    #[test]
+    fn to_string_call_to_display_definition() {
+        check(
+            r#"
+//- minicore:fmt
+//- /alloc.rs crate:alloc
+pub mod string {
+    pub struct String;
+    pub trait ToString {
+        fn to_string(&self) -> String;
+    }
+
+    impl<T: core::fmt::Display> ToString for T {
+        fn to_string(&self) -> String { String }
+    }
+}
+//- /lib.rs crate:lib deps:alloc
+use alloc::string::ToString;
+struct A;
+impl core::fmt::Display for A {
+    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {}
+    // ^^^
+}
+fn f() {
+    A.to_string$0();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 18a3fed07ec..9d4c103fc2e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -346,7 +346,7 @@ fn hover_offset(
         .unique()
         .reduce(|mut acc: HoverResult, HoverResult { markup, actions }| {
             acc.actions.extend(actions);
-            acc.markup = Markup::from(format!("{}\n---\n{markup}", acc.markup));
+            acc.markup = Markup::from(format!("{}\n\n---\n{markup}", acc.markup));
             acc
         })
         .map(|mut res: HoverResult| {
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 46242b75dd0..40f3406b72d 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -1082,7 +1082,19 @@ fn render_memory_layout(
 
     if config.niches {
         if let Some(niches) = layout.niches() {
-            format_to!(label, "niches = {niches}, ");
+            if niches > 1024 {
+                if niches.is_power_of_two() {
+                    format_to!(label, "niches = 2{}, ", pwr2_to_exponent(niches));
+                } else if is_pwr2plus1(niches) {
+                    format_to!(label, "niches = 2{} + 1, ", pwr2_to_exponent(niches - 1));
+                } else if is_pwr2minus1(niches) {
+                    format_to!(label, "niches = 2{} - 1, ", pwr2_to_exponent(niches + 1));
+                } else {
+                    format_to!(label, "niches = a lot, ");
+                }
+            } else {
+                format_to!(label, "niches = {niches}, ");
+            }
         }
     }
     label.pop(); // ' '
@@ -1210,3 +1222,74 @@ fn render_dyn_compatibility(
         }
     }
 }
+
+fn is_pwr2minus1(val: u128) -> bool {
+    val == u128::MAX || (val + 1).is_power_of_two()
+}
+
+fn is_pwr2plus1(val: u128) -> bool {
+    val != 0 && (val - 1).is_power_of_two()
+}
+
+/// Formats a power of two as an exponent of two, i.e. 16 => ⁴. Note that `num` MUST be a power
+/// of 2, or this function will panic.
+fn pwr2_to_exponent(num: u128) -> String {
+    const DIGITS: [char; 10] = ['⁰', '¹', '²', '³', '⁴', '⁵', '⁶', '⁷', '⁸', '⁹'];
+    assert_eq!(num.count_ones(), 1);
+    num.trailing_zeros()
+        .to_string()
+        .chars()
+        .map(|c| c.to_digit(10).unwrap() as usize)
+        .map(|idx| DIGITS[idx])
+        .collect::<String>()
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    const TESTERS: [u128; 10] = [0, 1, 2, 3, 4, 255, 256, 257, u128::MAX - 1, u128::MAX];
+
+    #[test]
+    fn test_is_pwr2minus1() {
+        const OUTCOMES: [bool; 10] =
+            [true, true, false, true, false, true, false, false, false, true];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = is_pwr2minus1(*test);
+            assert_eq!(actual, expected, "is_pwr2minu1({test}) gave {actual}, expected {expected}");
+        }
+    }
+
+    #[test]
+    fn test_is_pwr2plus1() {
+        const OUTCOMES: [bool; 10] =
+            [false, false, true, true, false, false, false, true, false, false];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = is_pwr2plus1(*test);
+            assert_eq!(actual, expected, "is_pwr2plus1({test}) gave {actual}, expected {expected}");
+        }
+    }
+
+    #[test]
+    fn test_pwr2_to_exponent() {
+        const TESTERS: [u128; 9] = [
+            1,
+            2,
+            4,
+            8,
+            16,
+            9223372036854775808,
+            18446744073709551616,
+            36893488147419103232,
+            170141183460469231731687303715884105728,
+        ];
+        const OUTCOMES: [&str; 9] = ["⁰", "¹", "²", "³", "⁴", "⁶³", "⁶⁴", "⁶⁵", "¹²⁷"];
+        for (test, expected) in TESTERS.iter().zip(OUTCOMES) {
+            let actual = pwr2_to_exponent(*test);
+            assert_eq!(
+                actual, expected,
+                "pwr2_to_exponent({test}) returned {actual}, expected {expected}",
+            );
+        }
+    }
+}
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 014b751f95b..8c32cc9720a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -303,6 +303,7 @@ m!(ab$0c);
             ---
 
             Outer
+
             ---
 
             ```rust
@@ -1357,7 +1358,7 @@ fn hover_enum_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, niches = 4294967288
+            size = 12 (0xC), align = 4, niches = a lot
         "#]],
     );
 }
@@ -4401,6 +4402,7 @@ fn main() {
             ---
 
             size = 8, align = 8, niches = 1
+
             ---
 
             ```rust
@@ -10094,6 +10096,7 @@ fn bar() {
             ```rust
             let field: i32
             ```
+
             ---
 
             ```rust
@@ -10128,6 +10131,7 @@ fn bar() {
             ---
 
             size = 4, align = 4
+
             ---
 
             ```rust
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 6d83a747d76..1f723c85df7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -209,7 +209,7 @@ fn hints(
 ) {
     closing_brace::hints(hints, sema, config, file_id, node.clone());
     if let Some(any_has_generic_args) = ast::AnyHasGenericArgs::cast(node.clone()) {
-        generic_param::hints(hints, sema, config, any_has_generic_args);
+        generic_param::hints(hints, famous_defs, config, any_has_generic_args);
     }
 
     match_ast! {
@@ -300,22 +300,23 @@ pub struct InlayHintsConfig {
     pub closing_brace_hints_min_lines: Option<usize>,
     pub fields_to_resolve: InlayFieldsToResolve,
 }
+
 impl InlayHintsConfig {
-    fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> Lazy<TextEdit> {
+    fn lazy_text_edit(&self, finish: impl FnOnce() -> TextEdit) -> LazyProperty<TextEdit> {
         if self.fields_to_resolve.resolve_text_edits {
-            Lazy::Lazy
+            LazyProperty::Lazy
         } else {
             let edit = finish();
             never!(edit.is_empty(), "inlay hint produced an empty text edit");
-            Lazy::Computed(edit)
+            LazyProperty::Computed(edit)
         }
     }
 
-    fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> Lazy<InlayTooltip> {
+    fn lazy_tooltip(&self, finish: impl FnOnce() -> InlayTooltip) -> LazyProperty<InlayTooltip> {
         if self.fields_to_resolve.resolve_hint_tooltip
             && self.fields_to_resolve.resolve_label_tooltip
         {
-            Lazy::Lazy
+            LazyProperty::Lazy
         } else {
             let tooltip = finish();
             never!(
@@ -326,7 +327,20 @@ impl InlayHintsConfig {
                 .is_empty(),
                 "inlay hint produced an empty tooltip"
             );
-            Lazy::Computed(tooltip)
+            LazyProperty::Computed(tooltip)
+        }
+    }
+
+    /// This always reports a resolvable location, so only use this when it is very likely for a
+    /// location link to actually resolve but where computing `finish` would be costly.
+    fn lazy_location_opt(
+        &self,
+        finish: impl FnOnce() -> Option<FileRange>,
+    ) -> Option<LazyProperty<FileRange>> {
+        if self.fields_to_resolve.resolve_label_location {
+            Some(LazyProperty::Lazy)
+        } else {
+            finish().map(LazyProperty::Computed)
         }
     }
 }
@@ -441,7 +455,7 @@ pub struct InlayHint {
     /// The actual label to show in the inlay hint.
     pub label: InlayHintLabel,
     /// Text edit to apply when "accepting" this inlay hint.
-    pub text_edit: Option<Lazy<TextEdit>>,
+    pub text_edit: Option<LazyProperty<TextEdit>>,
     /// Range to recompute inlay hints when trying to resolve for this hint. If this is none, the
     /// hint does not support resolving.
     pub resolve_parent: Option<TextRange>,
@@ -449,15 +463,15 @@ pub struct InlayHint {
 
 /// A type signaling that a value is either computed, or is available for computation.
 #[derive(Clone, Debug)]
-pub enum Lazy<T> {
+pub enum LazyProperty<T> {
     Computed(T),
     Lazy,
 }
 
-impl<T> Lazy<T> {
+impl<T> LazyProperty<T> {
     pub fn computed(self) -> Option<T> {
         match self {
-            Lazy::Computed(it) => Some(it),
+            LazyProperty::Computed(it) => Some(it),
             _ => None,
         }
     }
@@ -508,8 +522,8 @@ pub struct InlayHintLabel {
 impl InlayHintLabel {
     pub fn simple(
         s: impl Into<String>,
-        tooltip: Option<Lazy<InlayTooltip>>,
-        linked_location: Option<FileRange>,
+        tooltip: Option<LazyProperty<InlayTooltip>>,
+        linked_location: Option<LazyProperty<FileRange>>,
     ) -> InlayHintLabel {
         InlayHintLabel {
             parts: smallvec![InlayHintLabelPart { text: s.into(), linked_location, tooltip }],
@@ -593,16 +607,16 @@ pub struct InlayHintLabelPart {
     /// refers to (not necessarily the location itself).
     /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
     /// them both.
-    pub linked_location: Option<FileRange>,
+    pub linked_location: Option<LazyProperty<FileRange>>,
     /// The tooltip to show when hovering over the inlay hint, this may invoke other actions like
     /// hover requests to show.
-    pub tooltip: Option<Lazy<InlayTooltip>>,
+    pub tooltip: Option<LazyProperty<InlayTooltip>>,
 }
 
 impl std::hash::Hash for InlayHintLabelPart {
     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
         self.text.hash(state);
-        self.linked_location.hash(state);
+        self.linked_location.is_some().hash(state);
         self.tooltip.is_some().hash(state);
     }
 }
@@ -610,7 +624,9 @@ impl std::hash::Hash for InlayHintLabelPart {
 impl fmt::Debug for InlayHintLabelPart {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
-            Self { text, linked_location: None, tooltip: None | Some(Lazy::Lazy) } => text.fmt(f),
+            Self { text, linked_location: None, tooltip: None | Some(LazyProperty::Lazy) } => {
+                text.fmt(f)
+            }
             Self { text, linked_location, tooltip } => f
                 .debug_struct("InlayHintLabelPart")
                 .field("text", text)
@@ -618,8 +634,10 @@ impl fmt::Debug for InlayHintLabelPart {
                 .field(
                     "tooltip",
                     &tooltip.as_ref().map_or("", |it| match it {
-                        Lazy::Computed(InlayTooltip::String(it) | InlayTooltip::Markdown(it)) => it,
-                        Lazy::Lazy => "",
+                        LazyProperty::Computed(
+                            InlayTooltip::String(it) | InlayTooltip::Markdown(it),
+                        ) => it,
+                        LazyProperty::Lazy => "",
                     }),
                 )
                 .finish(),
@@ -632,7 +650,8 @@ struct InlayHintLabelBuilder<'a> {
     db: &'a RootDatabase,
     result: InlayHintLabel,
     last_part: String,
-    location: Option<FileRange>,
+    resolve: bool,
+    location: Option<LazyProperty<FileRange>>,
 }
 
 impl fmt::Write for InlayHintLabelBuilder<'_> {
@@ -645,11 +664,16 @@ impl HirWrite for InlayHintLabelBuilder<'_> {
     fn start_location_link(&mut self, def: ModuleDefId) {
         never!(self.location.is_some(), "location link is already started");
         self.make_new_part();
-        let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
-        let location = location.call_site();
-        let location =
-            FileRange { file_id: location.file_id, range: location.focus_or_full_range() };
-        self.location = Some(location);
+
+        self.location = Some(if self.resolve {
+            LazyProperty::Lazy
+        } else {
+            LazyProperty::Computed({
+                let Some(location) = ModuleDef::from(def).try_to_nav(self.db) else { return };
+                let location = location.call_site();
+                FileRange { file_id: location.file_id, range: location.focus_or_full_range() }
+            })
+        });
     }
 
     fn end_location_link(&mut self) {
@@ -735,6 +759,7 @@ fn label_of_ty(
         last_part: String::new(),
         location: None,
         result: InlayHintLabel::default(),
+        resolve: config.fields_to_resolve.resolve_label_location,
     };
     let _ = rec(sema, famous_defs, config.max_length, ty, &mut label_builder, config, edition);
     let r = label_builder.finish();
@@ -783,7 +808,7 @@ fn ty_to_text_edit(
     ty: &hir::Type,
     offset_to_insert: TextSize,
     prefix: impl Into<String>,
-) -> Option<Lazy<TextEdit>> {
+) -> Option<LazyProperty<TextEdit>> {
     // FIXME: Limit the length and bail out on excess somehow?
     let rendered = sema
         .scope(node_for_hint)
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index ab5464156f0..01a1a4545c4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -1206,4 +1206,38 @@ fn f5<G: T<Assoc = ()>>(it: G) {
 "#,
         );
     }
+
+    #[test]
+    fn regression_19007() {
+        check_types(
+            r#"
+trait Foo {
+    type Assoc;
+
+    fn foo(&self) -> Self::Assoc;
+}
+
+trait Bar {
+    type Target;
+}
+
+trait Baz<T> {}
+
+struct Struct<T: Foo> {
+    field: T,
+}
+
+impl<T> Struct<T>
+where
+    T: Foo,
+    T::Assoc: Baz<<T::Assoc as Bar>::Target> + Bar,
+{
+    fn f(&self) {
+        let x = self.field.foo();
+          //^ impl Baz<<<T as Foo>::Assoc as Bar>::Target> + Bar
+    }
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
index 429ddd31cbd..e9b728bcaa7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bounds.rs
@@ -22,11 +22,7 @@ pub(super) fn hints(
         return None;
     }
 
-    let linked_location =
-        famous_defs.core_marker_Sized().and_then(|it| it.try_to_nav(sema.db)).map(|it| {
-            let n = it.call_site();
-            FileRange { file_id: n.file_id, range: n.focus_or_full_range() }
-        });
+    let sized_trait = famous_defs.core_marker_Sized();
 
     for param in params.type_or_const_params() {
         match param {
@@ -48,7 +44,17 @@ pub(super) fn hints(
                         }
                         hint.parts.push(InlayHintLabelPart {
                             text: "Sized".to_owned(),
-                            linked_location,
+                            linked_location: sized_trait.and_then(|it| {
+                                config.lazy_location_opt(|| {
+                                    it.try_to_nav(sema.db).map(|it| {
+                                        let n = it.call_site();
+                                        FileRange {
+                                            file_id: n.file_id,
+                                            range: n.focus_or_full_range(),
+                                        }
+                                    })
+                                })
+                            }),
                             tooltip: None,
                         });
                         if has_bounds {
@@ -134,12 +140,14 @@ fn foo<T>() {}
                             InlayHintLabelPart {
                                 text: "Sized",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 135..140,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 135..140,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
index 7fa7ab1a94d..8471547727f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/chaining.rs
@@ -81,7 +81,10 @@ mod tests {
 
     use crate::{
         fixture,
-        inlay_hints::tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+        inlay_hints::{
+            tests::{check_expect, check_with_config, DISABLED_CONFIG, TEST_CONFIG},
+            LazyProperty,
+        },
         InlayHintsConfig,
     };
 
@@ -99,7 +102,7 @@ mod tests {
         let (analysis, file_id) = fixture::file(ra_fixture);
         let mut inlay_hints = analysis.inlay_hints(&config, file_id, None).unwrap();
         inlay_hints.iter_mut().flat_map(|hint| &mut hint.label.parts).for_each(|hint| {
-            if let Some(loc) = &mut hint.linked_location {
+            if let Some(LazyProperty::Computed(loc)) = &mut hint.linked_location {
                 loc.range = TextRange::empty(TextSize::from(0));
             }
         });
@@ -134,12 +137,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 63..64,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 63..64,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -151,12 +156,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "A",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..8,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..8,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -213,12 +220,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "C",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 51..52,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 51..52,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -230,12 +239,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 29..30,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 29..30,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -276,12 +287,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "C",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 51..52,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 51..52,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -293,12 +306,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 29..30,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 29..30,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -340,12 +355,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "B",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 23..24,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 23..24,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -353,12 +370,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "X",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 55..56,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 55..56,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -371,12 +390,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "A",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..8,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..8,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -384,12 +405,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "X",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 55..56,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 55..56,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -435,12 +458,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -448,12 +473,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -467,12 +494,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -480,12 +509,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -499,12 +530,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Iterator",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -512,12 +545,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Item",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            1,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                1,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -531,12 +566,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "MyIter",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 0..0,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 0..0,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -577,12 +614,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -594,12 +633,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -611,12 +652,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "Struct",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 7..13,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 7..13,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
@@ -628,12 +671,14 @@ fn main() {
                             InlayHintLabelPart {
                                 text: "self",
                                 linked_location: Some(
-                                    FileRangeWrapper {
-                                        file_id: FileId(
-                                            0,
-                                        ),
-                                        range: 42..46,
-                                    },
+                                    Computed(
+                                        FileRangeWrapper {
+                                            file_id: FileId(
+                                                0,
+                                            ),
+                                            range: 42..46,
+                                        },
+                                    ),
                                 ),
                                 tooltip: "",
                             },
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
index 90b8be64a46..3767d34e2c7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closing_brace.rs
@@ -11,7 +11,10 @@ use syntax::{
     match_ast, SyntaxKind, SyntaxNode, T,
 };
 
-use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, InlayKind};
+use crate::{
+    inlay_hints::LazyProperty, InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig,
+    InlayKind,
+};
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
@@ -141,7 +144,7 @@ pub(super) fn hints(
     acc.push(InlayHint {
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBrace,
-        label: InlayHintLabel::simple(label, None, linked_location),
+        label: InlayHintLabel::simple(label, None, linked_location.map(LazyProperty::Computed)),
         text_edit: None,
         position: InlayHintPosition::After,
         pad_left: true,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 906f2acf0c4..3e91618d08e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -53,10 +53,6 @@ pub(super) fn hints(
     let last = captures.len() - 1;
     for (idx, capture) in captures.into_iter().enumerate() {
         let local = capture.local();
-        let source = local.primary_source(sema.db);
-
-        // force cache the source file, otherwise sema lookup will potentially panic
-        _ = sema.parse_or_expand(source.file());
 
         let label = format!(
             "{}{}",
@@ -73,8 +69,17 @@ pub(super) fn hints(
         }
         hint.label.append_part(InlayHintLabelPart {
             text: label,
-            linked_location: source.name().and_then(|name| {
-                name.syntax().original_file_range_opt(sema.db).map(TupleExt::head).map(Into::into)
+            linked_location: config.lazy_location_opt(|| {
+                let source = local.primary_source(sema.db);
+
+                // force cache the source file, otherwise sema lookup will potentially panic
+                _ = sema.parse_or_expand(source.file());
+                source.name().and_then(|name| {
+                    name.syntax()
+                        .original_file_range_opt(sema.db)
+                        .map(TupleExt::head)
+                        .map(Into::into)
+                })
             }),
             tooltip: None,
         });
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
index 037b328d971..762a4c26551 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/generic_param.rs
@@ -1,17 +1,19 @@
 //! Implementation of inlay hints for generic parameters.
-use ide_db::{active_parameter::generic_def_for_node, RootDatabase};
+use ide_db::{active_parameter::generic_def_for_node, famous_defs::FamousDefs};
 use syntax::{
     ast::{self, AnyHasGenericArgs, HasGenericArgs, HasName},
     AstNode,
 };
 
-use crate::{inlay_hints::GenericParameterHints, InlayHint, InlayHintsConfig, InlayKind};
+use crate::{
+    inlay_hints::GenericParameterHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
+};
 
-use super::param_name::{is_argument_similar_to_param_name, render_label};
+use super::param_name::is_argument_similar_to_param_name;
 
 pub(crate) fn hints(
     acc: &mut Vec<InlayHint>,
-    sema: &hir::Semantics<'_, RootDatabase>,
+    FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     node: AnyHasGenericArgs,
 ) -> Option<()> {
@@ -45,12 +47,23 @@ pub(crate) fn hints(
             return None;
         }
 
-        let name = param.name(sema.db);
-        let param_name = name.as_str();
+        let allowed = match (param, &arg) {
+            (hir::GenericParam::TypeParam(_), ast::GenericArg::TypeArg(_)) => type_hints,
+            (hir::GenericParam::ConstParam(_), ast::GenericArg::ConstArg(_)) => const_hints,
+            (hir::GenericParam::LifetimeParam(_), ast::GenericArg::LifetimeArg(_)) => {
+                lifetime_hints
+            }
+            _ => false,
+        };
+        if !allowed {
+            return None;
+        }
+
+        let param_name = param.name(sema.db);
 
         let should_hide = {
             let argument = get_string_representation(&arg)?;
-            is_argument_similar_to_param_name(&argument, param_name)
+            is_argument_similar_to_param_name(&argument, param_name.as_str())
         };
 
         if should_hide {
@@ -59,30 +72,28 @@ pub(crate) fn hints(
 
         let range = sema.original_range_opt(arg.syntax())?.range;
 
-        let source_syntax = match param {
-            hir::GenericParam::TypeParam(it) => {
-                if !type_hints || !matches!(arg, ast::GenericArg::TypeArg(_)) {
-                    return None;
-                }
-                sema.source(it.merge())?.value.syntax().clone()
-            }
-            hir::GenericParam::ConstParam(it) => {
-                if !const_hints || !matches!(arg, ast::GenericArg::ConstArg(_)) {
-                    return None;
-                }
-                let syntax = sema.source(it.merge())?.value.syntax().clone();
-                let const_param = ast::ConstParam::cast(syntax)?;
-                const_param.name()?.syntax().clone()
-            }
-            hir::GenericParam::LifetimeParam(it) => {
-                if !lifetime_hints || !matches!(arg, ast::GenericArg::LifetimeArg(_)) {
-                    return None;
-                }
-                sema.source(it)?.value.syntax().clone()
-            }
-        };
-        let linked_location = sema.original_range_opt(&source_syntax);
-        let label = render_label(param_name, config, linked_location);
+        let colon = if config.render_colons { ":" } else { "" };
+        let label = InlayHintLabel::simple(
+            format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+            None,
+            config.lazy_location_opt(|| {
+                let source_syntax = match param {
+                    hir::GenericParam::TypeParam(it) => {
+                        sema.source(it.merge()).map(|it| it.value.syntax().clone())
+                    }
+                    hir::GenericParam::ConstParam(it) => {
+                        let syntax = sema.source(it.merge())?.value.syntax().clone();
+                        let const_param = ast::ConstParam::cast(syntax)?;
+                        const_param.name().map(|it| it.syntax().clone())
+                    }
+                    hir::GenericParam::LifetimeParam(it) => {
+                        sema.source(it).map(|it| it.value.syntax().clone())
+                    }
+                };
+                let linked_location = source_syntax.and_then(|it| sema.original_range_opt(&it));
+                linked_location.map(Into::into)
+            }),
+        );
 
         Some(InlayHint {
             range,
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 1358d3722f8..27c7c3d4981 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
@@ -49,7 +49,7 @@ pub(super) fn hints(
             if mir.locals[place.local].ty.adt_id(ChalkTyInterner).is_none() {
                 continue; // Arguably only ADTs have significant drop impls
             }
-            let Some(binding) = local_to_binding.get(place.local) else {
+            let Some(&binding_idx) = local_to_binding.get(place.local) else {
                 continue; // Ignore temporary values
             };
             let range = match terminator.span {
@@ -91,25 +91,26 @@ pub(super) fn hints(
                 },
                 MirSpan::Unknown => continue,
             };
-            let binding_source = source_map
-                .patterns_for_binding(*binding)
-                .first()
-                .and_then(|d| source_map.pat_syntax(*d).ok())
-                .and_then(|d| {
-                    Some(FileRange {
-                        file_id: d.file_id.file_id()?.into(),
-                        range: d.value.text_range(),
-                    })
-                });
-            let binding = &hir.bindings[*binding];
+            let binding = &hir.bindings[binding_idx];
             let name = binding.name.display_no_db(file_id.edition()).to_smolstr();
             if name.starts_with("<ra@") {
                 continue; // Ignore desugared variables
             }
             let mut label = InlayHintLabel::simple(
                 name,
-                Some(config.lazy_tooltip(|| crate::InlayTooltip::String("moz".into()))),
-                binding_source,
+                None,
+                config.lazy_location_opt(|| {
+                    source_map
+                        .patterns_for_binding(binding_idx)
+                        .first()
+                        .and_then(|d| source_map.pat_syntax(*d).ok())
+                        .and_then(|d| {
+                            Some(FileRange {
+                                file_id: d.file_id.file_id()?.into(),
+                                range: d.value.text_range(),
+                            })
+                        })
+                }),
             );
             label.prepend_str("drop(");
             label.append_str(")");
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
index a7b066700c5..8f01b1bd38b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/param_name.rs
@@ -3,7 +3,6 @@
 //! fn max(x: i32, y: i32) -> i32 { x + y }
 //! _ = max(/*x*/4, /*y*/4);
 //! ```
-use std::fmt::Display;
 
 use either::Either;
 use hir::{Callable, Semantics};
@@ -20,7 +19,7 @@ use crate::{InlayHint, InlayHintLabel, InlayHintPosition, InlayHintsConfig, Inla
 
 pub(super) fn hints(
     acc: &mut Vec<InlayHint>,
-    FamousDefs(sema, _): &FamousDefs<'_, '_>,
+    FamousDefs(sema, krate): &FamousDefs<'_, '_>,
     config: &InlayHintsConfig,
     _file_id: EditionedFileId,
     expr: ast::Expr,
@@ -37,23 +36,29 @@ pub(super) fn hints(
         .filter_map(|(p, arg)| {
             // Only annotate hints for expressions that exist in the original file
             let range = sema.original_range_opt(arg.syntax())?;
-            let source = sema.source(p)?;
-            let (param_name, name_syntax) = match source.value.as_ref() {
-                Either::Left(pat) => (pat.name()?, pat.name()),
-                Either::Right(param) => match param.pat()? {
-                    ast::Pat::IdentPat(it) => (it.name()?, it.name()),
-                    _ => return None,
-                },
-            };
-            Some((name_syntax, param_name, arg, range))
+            let param_name = p.name(sema.db)?;
+            Some((p, param_name, arg, range))
         })
         .filter(|(_, param_name, arg, _)| {
-            !should_hide_param_name_hint(sema, &callable, &param_name.text(), arg)
+            !should_hide_param_name_hint(sema, &callable, param_name.as_str(), arg)
         })
         .map(|(param, param_name, _, hir::FileRange { range, .. })| {
-            let linked_location = param.and_then(|name| sema.original_range_opt(name.syntax()));
-
-            let label = render_label(&param_name, config, linked_location);
+            let colon = if config.render_colons { ":" } else { "" };
+            let label = InlayHintLabel::simple(
+                format!("{}{colon}", param_name.display(sema.db, krate.edition(sema.db))),
+                None,
+                config.lazy_location_opt(|| {
+                    let source = sema.source(param)?;
+                    let name_syntax = match source.value.as_ref() {
+                        Either::Left(pat) => pat.name(),
+                        Either::Right(param) => match param.pat()? {
+                            ast::Pat::IdentPat(it) => it.name(),
+                            _ => None,
+                        },
+                    }?;
+                    sema.original_range_opt(name_syntax.syntax()).map(Into::into)
+                }),
+            );
             InlayHint {
                 range,
                 kind: InlayKind::Parameter,
@@ -70,16 +75,6 @@ pub(super) fn hints(
     Some(())
 }
 
-pub(super) fn render_label(
-    param_name: impl Display,
-    config: &InlayHintsConfig,
-    linked_location: Option<hir::FileRange>,
-) -> InlayHintLabel {
-    let colon = if config.render_colons { ":" } else { "" };
-
-    InlayHintLabel::simple(format!("{param_name}{colon}"), None, linked_location.map(Into::into))
-}
-
 fn get_callable(
     sema: &Semantics<'_, RootDatabase>,
     expr: &ast::Expr,
@@ -124,9 +119,7 @@ fn should_hide_param_name_hint(
     }
 
     let fn_name = match callable.kind() {
-        hir::CallableKind::Function(it) => {
-            Some(it.name(sema.db).unescaped().display_no_db().to_smolstr())
-        }
+        hir::CallableKind::Function(it) => Some(it.name(sema.db).as_str().to_smolstr()),
         _ => None,
     };
     let fn_name = fn_name.as_deref();
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 346e2862b0f..e942f5a6aac 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -91,7 +91,8 @@ pub use crate::{
     inlay_hints::{
         AdjustmentHints, AdjustmentHintsMode, ClosureReturnTypeHints, DiscriminantHints,
         GenericParameterHints, InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart,
-        InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LifetimeElisionHints,
+        InlayHintPosition, InlayHintsConfig, InlayKind, InlayTooltip, LazyProperty,
+        LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -671,7 +672,7 @@ impl Analysis {
         &self,
         config: &CompletionConfig<'_>,
         position: FilePosition,
-        imports: impl IntoIterator<Item = (String, String)> + std::panic::UnwindSafe,
+        imports: impl IntoIterator<Item = String> + std::panic::UnwindSafe,
     ) -> Cancellable<Vec<TextEdit>> {
         Ok(self
             .with_db(|db| ide_completion::resolve_completion_edits(db, config, position, imports))?
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index ba739df3092..07dfd83c4eb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -263,7 +263,7 @@ fn find_definitions(
                         .and_then(|def| {
                             // if the name differs from the definitions name it has to be an alias
                             if def
-                                .name(sema.db).is_some_and(|it| !it.eq_ident(name_ref.text().as_str()))
+                                .name(sema.db).is_some_and(|it| it.as_str() != name_ref.text().trim_start_matches("r#"))
                             {
                                 Err(format_err!("Renaming aliases is currently unsupported"))
                             } else {
diff --git a/src/tools/rust-analyzer/crates/intern/Cargo.toml b/src/tools/rust-analyzer/crates/intern/Cargo.toml
index 5e7ee54c6af..c0358ef929b 100644
--- a/src/tools/rust-analyzer/crates/intern/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/intern/Cargo.toml
@@ -19,7 +19,6 @@ dashmap.workspace = true
 hashbrown.workspace = true
 rustc-hash.workspace = true
 triomphe.workspace = true
-sptr = "0.3.2"
 
 [lints]
 workspace = true
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol.rs b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
index 200b14027f8..b3bf285edfb 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol.rs
@@ -13,7 +13,6 @@ use std::{
 use dashmap::{DashMap, SharedValue};
 use hashbrown::{hash_map::RawEntryMut, HashMap};
 use rustc_hash::FxHasher;
-use sptr::Strict;
 use triomphe::Arc;
 
 pub mod symbols;
@@ -84,7 +83,7 @@ impl TaggedArcPtr {
     #[inline]
     pub(crate) unsafe fn try_as_arc_owned(self) -> Option<ManuallyDrop<Arc<Box<str>>>> {
         // Unpack the tag from the alignment niche
-        let tag = Strict::addr(self.packed.as_ptr()) & Self::BOOL_BITS;
+        let tag = self.packed.as_ptr().addr() & Self::BOOL_BITS;
         if tag != 0 {
             // Safety: We checked that the tag is non-zero -> true, so we are pointing to the data offset of an `Arc`
             Some(ManuallyDrop::new(unsafe {
@@ -99,40 +98,18 @@ impl TaggedArcPtr {
     fn pack_arc(ptr: NonNull<*const str>) -> NonNull<*const str> {
         let packed_tag = true as usize;
 
-        // can't use this strict provenance stuff here due to trait methods not being const
-        // unsafe {
-        //     // Safety: The pointer is derived from a non-null
-        //     NonNull::new_unchecked(Strict::map_addr(ptr.as_ptr(), |addr| {
-        //         // Safety:
-        //         // - The pointer is `NonNull` => it's address is `NonZero<usize>`
-        //         // - `P::BITS` least significant bits are always zero (`Pointer` contract)
-        //         // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
-        //         //
-        //         // Thus `addr >> T::BITS` is guaranteed to be non-zero.
-        //         //
-        //         // `{non_zero} | packed_tag` can't make the value zero.
-
-        //         (addr >> Self::BOOL_BITS) | packed_tag
-        //     }))
-        // }
-        // so what follows is roughly what the above looks like but inlined
-
-        let self_addr = ptr.as_ptr() as *const *const str as usize;
-        let addr = self_addr | packed_tag;
-        let dest_addr = addr as isize;
-        let offset = dest_addr.wrapping_sub(self_addr as isize);
-
-        // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
-        unsafe { NonNull::new_unchecked(ptr.as_ptr().cast::<u8>().wrapping_offset(offset).cast()) }
+        unsafe {
+            // Safety: The pointer is derived from a non-null and bit-oring it with true (1) will
+            // not make it null.
+            NonNull::new_unchecked(ptr.as_ptr().map_addr(|addr| addr | packed_tag))
+        }
     }
 
     #[inline]
     pub(crate) fn pointer(self) -> NonNull<*const str> {
         // SAFETY: The resulting pointer is guaranteed to be NonNull as we only modify the niche bytes
         unsafe {
-            NonNull::new_unchecked(Strict::map_addr(self.packed.as_ptr(), |addr| {
-                addr & !Self::BOOL_BITS
-            }))
+            NonNull::new_unchecked(self.packed.as_ptr().map_addr(|addr| addr & !Self::BOOL_BITS))
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index b3b46421b50..9bc78ff87b8 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -240,8 +240,10 @@ define_symbols! {
     format_unsafe_arg,
     format,
     freeze,
+    from,
     From,
     FromStr,
+    from_str,
     from_output,
     from_residual,
     from_usize,
@@ -273,6 +275,8 @@ define_symbols! {
     index_mut,
     index,
     Index,
+    into,
+    Into,
     into_future,
     into_iter,
     IntoFuture,
@@ -361,6 +365,7 @@ define_symbols! {
     panic_nounwind,
     panic,
     Param,
+    parse,
     partial_ord,
     PartialEq,
     PartialOrd,
@@ -389,6 +394,7 @@ define_symbols! {
     RangeToInclusive,
     Ready,
     receiver,
+    receiver_target,
     recursion_limit,
     register_attr,
     register_tool,
@@ -454,13 +460,17 @@ define_symbols! {
     termination,
     test_case,
     test,
+    then,
     thiscall,
+    to_string,
     trace_macros,
     transmute_opts,
     transmute_trait,
     transparent,
+    try_into,
     Try,
     TryFrom,
+    try_from,
     tuple_trait,
     u128,
     u16,
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 00446b27cf2..5654c04a592 100644
--- a/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/load-cargo/src/lib.rs
@@ -256,6 +256,24 @@ impl ProjectFolders {
             fsc.add_file_set(file_set_roots)
         }
 
+        for ws in workspaces.iter() {
+            let mut file_set_roots: Vec<VfsPath> = vec![];
+            let mut entries = vec![];
+
+            for buildfile in ws.buildfiles() {
+                file_set_roots.push(VfsPath::from(buildfile.to_owned()));
+                entries.push(buildfile.to_owned());
+            }
+
+            if !file_set_roots.is_empty() {
+                let entry = vfs::loader::Entry::Files(entries);
+                res.watch.push(res.load.len());
+                res.load.push(entry);
+                local_filesets.push(fsc.len() as u64);
+                fsc.add_file_set(file_set_roots)
+            }
+        }
+
         if let Some(user_config_path) = user_config_dir_path {
             let ratoml_path = {
                 let mut p = user_config_path.to_path_buf();
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index c7614849e01..59293ee3f96 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -392,12 +392,12 @@ impl server::Span for RaSpanServer {
 
     fn line(&mut self, _span: Self::Span) -> usize {
         // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
-        0
+        1
     }
 
     fn column(&mut self, _span: Self::Span) -> usize {
         // FIXME requires db to resolve line index, THIS IS NOT INCREMENTAL
-        0
+        1
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index 466eb14b55e..409cf3cc781 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -291,11 +291,11 @@ impl server::Span for TokenIdServer {
     }
 
     fn line(&mut self, _span: Self::Span) -> usize {
-        0
+        1
     }
 
     fn column(&mut self, _span: Self::Span) -> usize {
-        0
+        1
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index 6a88cf022df..a3963967610 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -63,7 +63,7 @@ use crate::{ManifestPath, TargetKind};
 pub struct ProjectJson {
     /// e.g. `path/to/sysroot`
     pub(crate) sysroot: Option<AbsPathBuf>,
-    /// e.g. `path/to/sysroot/lib/rustlib/src/rust`
+    /// e.g. `path/to/sysroot/lib/rustlib/src/rust/library`
     pub(crate) sysroot_src: Option<AbsPathBuf>,
     project_root: AbsPathBuf,
     /// The path to the rust-project.json file. May be None if this
diff --git a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
index 4bf9b59e7d0..e472da0c89b 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/toolchain_info/rustc_cfg.rs
@@ -19,7 +19,7 @@ pub fn get(
     let rustc_cfgs = match rustc_cfgs {
         Ok(cfgs) => cfgs,
         Err(e) => {
-            tracing::error!(?e, "failed to get rustc cfgs");
+            tracing::warn!(?e, "failed to get rustc cfgs");
             return vec![];
         }
     };
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 f98d983ac06..dcd62753cb2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -524,6 +524,17 @@ impl ProjectWorkspace {
         }
     }
 
+    pub fn buildfiles(&self) -> Vec<AbsPathBuf> {
+        match &self.kind {
+            ProjectWorkspaceKind::Json(project) => project
+                .crates()
+                .filter_map(|(_, krate)| krate.build.as_ref().map(|build| build.build_file.clone()))
+                .map(|build_file| self.workspace_root().join(build_file))
+                .collect(),
+            _ => vec![],
+        }
+    }
+
     pub fn find_sysroot_proc_macro_srv(&self) -> anyhow::Result<AbsPathBuf> {
         self.sysroot.discover_proc_macro_srv()
     }
@@ -568,27 +579,15 @@ impl ProjectWorkspace {
         match &self.kind {
             ProjectWorkspaceKind::Json(project) => project
                 .crates()
-                .map(|(_, krate)| {
-                    // FIXME: PackageRoots dont allow specifying files, only directories
-                    let build_file = krate
-                        .build
-                        .as_ref()
-                        .map(|build| self.workspace_root().join(&build.build_file))
-                        .as_deref()
-                        .and_then(AbsPath::parent)
-                        .map(ToOwned::to_owned);
-
-                    PackageRoot {
-                        is_local: krate.is_workspace_member,
-                        include: krate
-                            .include
-                            .iter()
-                            .cloned()
-                            .chain(build_file)
-                            .chain(self.extra_includes.iter().cloned())
-                            .collect(),
-                        exclude: krate.exclude.clone(),
-                    }
+                .map(|(_, krate)| PackageRoot {
+                    is_local: krate.is_workspace_member,
+                    include: krate
+                        .include
+                        .iter()
+                        .cloned()
+                        .chain(self.extra_includes.iter().cloned())
+                        .collect(),
+                    exclude: krate.exclude.clone(),
                 })
                 .collect::<FxHashSet<_>>()
                 .into_iter()
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 bcaec520195..18c27c84496 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
@@ -465,6 +465,7 @@ impl flags::AnalysisStats {
                                 prefer_no_std: false,
                                 prefer_prelude: true,
                                 prefer_absolute: false,
+                                allow_unstable: true,
                             },
                             Edition::LATEST,
                         )
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 3dc4379258f..44325fa1a29 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -453,6 +453,10 @@ config_data! {
         ///
         /// In `match` arms it completes a comma instead.
         completion_addSemicolonToUnit: bool = true,
+        /// Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+        completion_autoAwait_enable: bool        = true,
+        /// Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+        completion_autoIter_enable: 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.
         completion_autoimport_enable: bool       = true,
@@ -1484,6 +1488,8 @@ impl Config {
             enable_imports_on_the_fly: self.completion_autoimport_enable(source_root).to_owned()
                 && self.caps.completion_item_edit_resolve(),
             enable_self_on_the_fly: self.completion_autoself_enable(source_root).to_owned(),
+            enable_auto_iter: *self.completion_autoIter_enable(source_root),
+            enable_auto_await: *self.completion_autoAwait_enable(source_root),
             enable_private_editable: self.completion_privateEditable_enable(source_root).to_owned(),
             full_function_signatures: self
                 .completion_fullFunctionSignatures_enable(source_root)
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
index 22f06d68d80..2309f94a742 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs
@@ -88,6 +88,17 @@ pub(crate) enum FlycheckConfig {
     },
 }
 
+impl FlycheckConfig {
+    pub(crate) fn invocation_strategy_once(&self) -> bool {
+        match self {
+            FlycheckConfig::CargoCommand { .. } => false,
+            FlycheckConfig::CustomCommand { invocation_strategy, .. } => {
+                *invocation_strategy == InvocationStrategy::Once
+            }
+        }
+    }
+}
+
 impl fmt::Display for FlycheckConfig {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
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 98efc637c2c..84ba89d9f31 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
@@ -291,9 +291,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
     let file_id = state.vfs.read().0.file_id(&vfs_path);
     if let Some(file_id) = file_id {
         let world = state.snapshot();
+        let invocation_strategy_once = state.config.flycheck(None).invocation_strategy_once();
         let may_flycheck_workspace = state.config.flycheck_workspace(None);
         let mut updated = false;
         let task = move || -> std::result::Result<(), ide::Cancelled> {
+            if invocation_strategy_once {
+                let saved_file = vfs_path.as_path().map(|p| p.to_owned());
+                world.flycheck[0].restart_workspace(saved_file.clone());
+            }
+
             let target = TargetSpec::for_file(&world, file_id)?.and_then(|it| {
                 let tgt_kind = it.target_kind();
                 let (tgt_name, root, package) = match it {
@@ -320,16 +326,15 @@ fn run_flycheck(state: &mut GlobalState, vfs_path: VfsPath) -> bool {
                 // the user opted into package checks then
                 let package_check_allowed = target.is_some() || !may_flycheck_workspace;
                 if package_check_allowed {
-                    let workspace =
-                        world.workspaces.iter().enumerate().find(|(_, ws)| match &ws.kind {
-                            project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
-                            | project_model::ProjectWorkspaceKind::DetachedFile {
-                                cargo: Some((cargo, _, _)),
-                                ..
-                            } => *cargo.workspace_root() == root,
-                            _ => false,
-                        });
-                    if let Some((idx, _)) = workspace {
+                    let workspace = world.workspaces.iter().position(|ws| match &ws.kind {
+                        project_model::ProjectWorkspaceKind::Cargo { cargo, .. }
+                        | project_model::ProjectWorkspaceKind::DetachedFile {
+                            cargo: Some((cargo, _, _)),
+                            ..
+                        } => *cargo.workspace_root() == root,
+                        _ => false,
+                    });
+                    if let Some(idx) = workspace {
                         world.flycheck[idx].restart_for_package(package, target);
                     }
                 }
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 190015d7faa..39cbf53eaa2 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
@@ -1154,10 +1154,7 @@ pub(crate) fn handle_completion_resolve(
             .resolve_completion_edits(
                 &forced_resolve_completions_config,
                 position,
-                resolve_data
-                    .imports
-                    .into_iter()
-                    .map(|import| (import.full_import_path, import.imported_name)),
+                resolve_data.imports.into_iter().map(|import| import.full_import_path),
             )?
             .into_iter()
             .flat_map(|edit| edit.into_iter().map(|indel| to_proto::text_edit(&line_index, indel)))
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index fcfd06679bf..5cdc51a1c19 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -176,6 +176,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -226,6 +228,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -274,6 +278,8 @@ fn integrated_completion_benchmark() {
             fields_to_resolve: CompletionFieldsToResolve::empty(),
             exclude_flyimport: vec![],
             exclude_traits: &[],
+            enable_auto_await: true,
+            enable_auto_iter: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index 61ec576dd4f..ccffa7a671e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -142,9 +142,8 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
         hasher.update(prefix);
         hasher.update(u32::from(*text_size).to_le_bytes());
     }
-    for (import_path, import_name) in &item.import_to_add {
+    for import_path in &item.import_to_add {
         hasher.update(import_path);
-        hasher.update(import_name);
     }
     hasher.finalize()
 }
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 134de92feab..ca4372aa83f 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
@@ -850,7 +850,6 @@ pub struct InlayHintResolveData {
 #[derive(Debug, Serialize, Deserialize)]
 pub struct CompletionImport {
     pub full_import_path: String,
-    pub imported_name: String,
 }
 
 #[derive(Debug, Deserialize, Default)]
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 a5516e7f9d4..bff53cf98b7 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
@@ -11,8 +11,8 @@ use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionFieldsToResolve,
     CompletionItem, CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange,
     FileSystemEdit, Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel,
-    InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, Markup,
-    NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
+    InlayFieldsToResolve, InlayHint, InlayHintLabel, InlayHintLabelPart, InlayKind, LazyProperty,
+    Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity, SignatureHelp,
     SnippetEdit, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
 use ide_db::{assists, rust_doc::format_docs, FxHasher};
@@ -394,10 +394,7 @@ fn completion_item(
             item.import_to_add
                 .clone()
                 .into_iter()
-                .map(|(import_path, import_name)| lsp_ext::CompletionImport {
-                    full_import_path: import_path,
-                    imported_name: import_name,
-                })
+                .map(|import_path| lsp_ext::CompletionImport { full_import_path: import_path })
                 .collect()
         } else {
             Vec::new()
@@ -549,12 +546,11 @@ pub(crate) fn inlay_hint(
 ) -> Cancellable<lsp_types::InlayHint> {
     let hint_needs_resolve = |hint: &InlayHint| -> Option<TextRange> {
         hint.resolve_parent.filter(|_| {
-            hint.text_edit.is_some()
-                || hint
-                    .label
-                    .parts
-                    .iter()
-                    .any(|part| part.linked_location.is_some() || part.tooltip.is_some())
+            hint.text_edit.as_ref().is_some_and(LazyProperty::is_lazy)
+                || hint.label.parts.iter().any(|part| {
+                    part.linked_location.as_ref().is_some_and(LazyProperty::is_lazy)
+                        || part.tooltip.as_ref().is_some_and(LazyProperty::is_lazy)
+                })
         })
     };
 
@@ -569,22 +565,21 @@ pub(crate) fn inlay_hint(
     });
 
     let mut something_to_resolve = false;
-    let text_edits = if snap
-        .config
-        .visual_studio_code_version()
-        .is_none_or(|version| VersionReq::parse(">=1.86.0").unwrap().matches(version))
-        && resolve_range_and_hash.is_some()
-        && fields_to_resolve.resolve_text_edits
-    {
-        something_to_resolve |= inlay_hint.text_edit.is_some();
-        None
-    } else {
-        inlay_hint
-            .text_edit
-            .take()
-            .and_then(|it| it.computed())
-            .map(|it| text_edit_vec(line_index, it))
-    };
+    let text_edits = inlay_hint
+        .text_edit
+        .take()
+        .and_then(|it| match it {
+            LazyProperty::Computed(it) => Some(it),
+            LazyProperty::Lazy => {
+                something_to_resolve |=
+                    snap.config.visual_studio_code_version().is_none_or(|version| {
+                        VersionReq::parse(">=1.86.0").unwrap().matches(version)
+                    }) && resolve_range_and_hash.is_some()
+                        && fields_to_resolve.resolve_text_edits;
+                None
+            }
+        })
+        .map(|it| text_edit_vec(line_index, it));
     let (label, tooltip) = inlay_hint_label(
         snap,
         fields_to_resolve,
@@ -637,22 +632,23 @@ fn inlay_hint_label(
     let (label, tooltip) = match &*label.parts {
         [InlayHintLabelPart { linked_location: None, .. }] => {
             let InlayHintLabelPart { text, tooltip, .. } = label.parts.pop().unwrap();
-            let hint_tooltip = if needs_resolve && fields_to_resolve.resolve_hint_tooltip {
-                *something_to_resolve |= tooltip.is_some();
-                None
-            } else {
-                match tooltip.and_then(|it| it.computed()) {
-                    Some(ide::InlayTooltip::String(s)) => {
-                        Some(lsp_types::InlayHintTooltip::String(s))
-                    }
-                    Some(ide::InlayTooltip::Markdown(s)) => {
-                        Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
-                            kind: lsp_types::MarkupKind::Markdown,
-                            value: s,
-                        }))
-                    }
-                    None => None,
+            let tooltip = tooltip.and_then(|it| match it {
+                LazyProperty::Computed(it) => Some(it),
+                LazyProperty::Lazy => {
+                    *something_to_resolve |=
+                        needs_resolve && fields_to_resolve.resolve_hint_tooltip;
+                    None
                 }
+            });
+            let hint_tooltip = match tooltip {
+                Some(ide::InlayTooltip::String(s)) => Some(lsp_types::InlayHintTooltip::String(s)),
+                Some(ide::InlayTooltip::Markdown(s)) => {
+                    Some(lsp_types::InlayHintTooltip::MarkupContent(lsp_types::MarkupContent {
+                        kind: lsp_types::MarkupKind::Markdown,
+                        value: s,
+                    }))
+                }
+                None => None,
             };
             (lsp_types::InlayHintLabel::String(text), hint_tooltip)
         }
@@ -661,31 +657,38 @@ fn inlay_hint_label(
                 .parts
                 .into_iter()
                 .map(|part| {
-                    let tooltip = if needs_resolve && fields_to_resolve.resolve_label_tooltip {
-                        *something_to_resolve |= part.tooltip.is_some();
-                        None
-                    } else {
-                        match part.tooltip.and_then(|it| it.computed()) {
-                            Some(ide::InlayTooltip::String(s)) => {
-                                Some(lsp_types::InlayHintLabelPartTooltip::String(s))
-                            }
-                            Some(ide::InlayTooltip::Markdown(s)) => {
-                                Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
-                                    lsp_types::MarkupContent {
-                                        kind: lsp_types::MarkupKind::Markdown,
-                                        value: s,
-                                    },
-                                ))
-                            }
-                            None => None,
+                    let tooltip = part.tooltip.and_then(|it| match it {
+                        LazyProperty::Computed(it) => Some(it),
+                        LazyProperty::Lazy => {
+                            *something_to_resolve |= fields_to_resolve.resolve_label_tooltip;
+                            None
                         }
+                    });
+                    let tooltip = match tooltip {
+                        Some(ide::InlayTooltip::String(s)) => {
+                            Some(lsp_types::InlayHintLabelPartTooltip::String(s))
+                        }
+                        Some(ide::InlayTooltip::Markdown(s)) => {
+                            Some(lsp_types::InlayHintLabelPartTooltip::MarkupContent(
+                                lsp_types::MarkupContent {
+                                    kind: lsp_types::MarkupKind::Markdown,
+                                    value: s,
+                                },
+                            ))
+                        }
+                        None => None,
                     };
-                    let location = if needs_resolve && fields_to_resolve.resolve_label_location {
-                        *something_to_resolve |= part.linked_location.is_some();
-                        None
-                    } else {
-                        part.linked_location.map(|range| location(snap, range)).transpose()?
-                    };
+                    let location = part
+                        .linked_location
+                        .and_then(|it| match it {
+                            LazyProperty::Computed(it) => Some(it),
+                            LazyProperty::Lazy => {
+                                *something_to_resolve |= fields_to_resolve.resolve_label_location;
+                                None
+                            }
+                        })
+                        .map(|range| location(snap, range))
+                        .transpose()?;
                     Ok(lsp_types::InlayHintLabelPart {
                         value: part.text,
                         tooltip,
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 dca231604fa..ff027ac5848 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/make.rs
@@ -411,6 +411,11 @@ pub fn path_from_text(text: &str) -> ast::Path {
     ast_from_text(&format!("fn main() {{ let test: {text}; }}"))
 }
 
+// FIXME: should not be pub
+pub fn path_from_text_with_edition(text: &str, edition: Edition) -> ast::Path {
+    ast_from_text_with_edition(&format!("fn main() {{ let test: {text}; }}"), edition)
+}
+
 pub fn use_tree_glob() -> ast::UseTree {
     ast_from_text("use *;")
 }
@@ -1230,7 +1235,12 @@ pub fn token_tree(
 
 #[track_caller]
 fn ast_from_text<N: AstNode>(text: &str) -> N {
-    let parse = SourceFile::parse(text, Edition::CURRENT);
+    ast_from_text_with_edition(text, Edition::CURRENT)
+}
+
+#[track_caller]
+fn ast_from_text_with_edition<N: AstNode>(text: &str, edition: Edition) -> N {
+    let parse = SourceFile::parse(text, edition);
     let node = match parse.tree().syntax().descendants().find_map(N::cast) {
         Some(it) => it,
         None => {
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 fd06736a252..4ed68d18e80 100644
--- a/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
+++ b/src/tools/rust-analyzer/crates/test-utils/src/minicore.rs
@@ -53,6 +53,7 @@
 //!     pin:
 //!     pointee: copy, send, sync, ord, hash, unpin
 //!     range:
+//!     receiver: deref
 //!     result:
 //!     send: sized
 //!     size_of: sized
@@ -513,10 +514,26 @@ pub mod ops {
             fn deref_mut(&mut self) -> &mut Self::Target;
         }
         // endregion:deref_mut
+
+        // region:receiver
+        #[lang = "receiver"]
+        pub trait Receiver {
+            #[lang = "receiver_target"]
+            type Target: ?Sized;
+        }
+
+        impl<P: ?Sized, T: ?Sized> Receiver for P
+        where
+            P: Deref<Target = T>,
+        {
+            type Target = T;
+        }
+        // endregion:receiver
     }
     pub use self::deref::{
         Deref,
         DerefMut, // :deref_mut
+        Receiver, // :receiver
     };
     // endregion:deref
 
diff --git a/src/tools/rust-analyzer/docs/dev/README.md b/src/tools/rust-analyzer/docs/dev/README.md
index 3ba492e0959..c990212d585 100644
--- a/src/tools/rust-analyzer/docs/dev/README.md
+++ b/src/tools/rust-analyzer/docs/dev/README.md
@@ -269,19 +269,13 @@ Note: we tag releases by dates, releasing a patch release on the same day should
 
 ## Permissions
 
-There are three sets of people with extra permissions:
+There are two sets of people with extra permissions:
 
-* rust-analyzer GitHub organization [**admins**](https://github.com/orgs/rust-analyzer/people?query=role:owner) (which include current t-compiler leads).
-  Admins have full access to the org.
-* [**review**](https://github.com/orgs/rust-analyzer/teams/review) team in the organization.
-  Reviewers have `r+` access to all of organization's repositories and publish rights on crates.io.
-  They also have direct commit access, but all changes should via bors queue.
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer.toml).
+  This team has write access to the repository and merge queue permissions (note the repo itself is managed by infra admins).
   It's ok to self-approve if you think you know what you are doing!
-  bors should automatically sync the permissions.
   Feel free to request a review or assign any PR to a reviewer with the relevant expertise to bring the work to their attention.
   Don't feel pressured to review assigned PRs though.
-  If you don't feel like reviewing for whatever reason, someone else will pick the review up!
-* [**triage**](https://github.com/orgs/rust-analyzer/teams/triage) team in the organization.
-  This team can label and close issues.
-
-Note that at the time being you need to be a member of the org yourself to view the links.
+  If you don't feel like reviewing for whatever reason, someone else will pick the review up (but please speak up if you don't feel like it)!
+* The [rust-lang](https://github.com/rust-lang) team [t-rust-analyzer-contributors]([https://github.com/orgs/rust-analyzer/teams/triage](https://github.com/rust-lang/team/blob/master/teams/rust-analyzer-contributors.toml)).
+  This team has general triaging permissions allowing to label, close and re-open issues.
diff --git a/src/tools/rust-analyzer/docs/dev/lsp-extensions.md b/src/tools/rust-analyzer/docs/dev/lsp-extensions.md
index a632fc6f5fb..c7ee4e40236 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: 2d8604825c458288
+lsp/ext.rs hash: af70cce5d6905e39
 
 If you need to change the above hash to make the test pass, please check if you
 need to adjust this doc as well and ping this issue:
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index bd091db58d3..b33de1956b8 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -274,6 +274,16 @@ Whether to automatically add a semicolon when completing unit-returning function
 
 In `match` arms it completes a comma instead.
 --
+[[rust-analyzer.completion.autoAwait.enable]]rust-analyzer.completion.autoAwait.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.
+--
+[[rust-analyzer.completion.autoIter.enable]]rust-analyzer.completion.autoIter.enable (default: `true`)::
++
+--
+Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.
+--
 [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 +
 --
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index ffc820e9b7f..4a2a6f2e368 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -716,6 +716,32 @@ interface JsonProject {
     /// dependencies as well as sysroot crate (libstd,
     /// libcore and such).
     crates: Crate[];
+    /// Configuration for CLI commands.
+    ///
+    /// These are used for running and debugging binaries
+    /// and tests without encoding build system-specific
+    /// knowledge into rust-analyzer.
+    ///
+    /// # Example
+    ///
+    /// Below is an example of a test runnable. `{label}` and `{test_id}`
+    /// are explained in `Runnable::args`'s documentation below.
+    ///
+    /// ```json
+    /// {
+    ///     "program": "buck",
+    ///     "args": [
+    ///         "test",
+    ///          "{label}",
+    ///          "--",
+    ///          "{test_id}",
+    ///          "--print-passing-details"
+    ///     ],
+    ///     "cwd": "/home/user/repo-root/",
+    ///     "kind": "testOne"
+    /// }
+    /// ```
+    runnables?: Runnable[];
 }
 
 interface Crate {
@@ -726,7 +752,10 @@ interface Crate {
     /// Path to the root module of the crate.
     root_module: string;
     /// Edition of the crate.
-    edition: "2015" | "2018" | "2021";
+    edition: '2015' | '2018' | '2021' | '2024';
+    /// The version of the crate. Used for calculating
+    /// the correct docs.rs URL.
+    version?: string;
     /// Dependencies
     deps: Dep[];
     /// Should this crate be treated as a member of
@@ -757,9 +786,9 @@ interface Crate {
     /// rust-analyzer assumes that files from one
     /// source can't refer to files in another source.
     source?: {
-        include_dirs: string[],
-        exclude_dirs: string[],
-    },
+        include_dirs: string[];
+        exclude_dirs: string[];
+    };
     /// List of cfg groups this crate inherits.
     ///
     /// All cfg in these groups will be concatenated to
@@ -776,21 +805,68 @@ interface Crate {
     target?: string;
     /// Environment variables, used for
     /// the `env!` macro
-    env: { [key: string]: string; },
+    env: { [key: string]: string; };
 
     /// Whether the crate is a proc-macro crate.
     is_proc_macro: boolean;
     /// For proc-macro crates, path to compiled
     /// proc-macro (.so file).
     proc_macro_dylib_path?: string;
+
+    /// Repository, matching the URL that would be used
+    /// in Cargo.toml.
+    repository?: string;
+
+    /// Build-specific data about this crate.
+    build?: BuildInfo;
 }
 
 interface Dep {
     /// Index of a crate in the `crates` array.
-    crate: number,
+    crate: number;
     /// Name as should appear in the (implicit)
     /// `extern crate name` declaration.
-    name: string,
+    name: string;
+}
+
+interface BuildInfo {
+    /// The name associated with this crate.
+    ///
+    /// This is determined by the build system that produced
+    /// the `rust-project.json` in question. For instance, if buck were used,
+    /// the label might be something like `//ide/rust/rust-analyzer:rust-analyzer`.
+    ///
+    /// Do not attempt to parse the contents of this string; it is a build system-specific
+    /// identifier similar to `Crate::display_name`.
+    label: string;
+    /// Path corresponding to the build system-specific file defining the crate.
+    build_file: string;
+    /// The kind of target.
+    ///
+    /// This information is used to determine what sort
+    /// of runnable codelens to provide, if any.
+    target_kind: 'bin' | 'lib' | 'test';
+}
+
+interface Runnable {
+    /// The program invoked by the runnable.
+    ///
+    /// For example, this might be `cargo`, `buck`, or `bazel`.
+    program: string;
+    /// The arguments passed to `program`.
+    args: string[];
+    /// The current working directory of the runnable.
+    cwd: string;
+    /// Used to decide what code lens to offer.
+    ///
+    /// `testOne`: This runnable will be used when the user clicks the 'Run Test'
+    /// CodeLens above a test.
+    ///
+    /// The args for testOne can contain two template strings:
+    /// `{label}` and `{test_id}`. `{label}` will be replaced
+    /// with the `Build::label` and `{test_id}` will be replaced
+    /// with the test name.
+    kind: 'testOne' | string;
 }
 ----
 
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 8b066377f2b..f148041ac3e 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1146,6 +1146,26 @@
             {
                 "title": "completion",
                 "properties": {
+                    "rust-analyzer.completion.autoAwait.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically show method calls and field accesses with `await` prefixed to them when completing on a future.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
+                    "rust-analyzer.completion.autoIter.enable": {
+                        "markdownDescription": "Toggles the additional completions that automatically show method calls with `iter()` or `into_iter()` prefixed to them when completing on a type that has them.",
+                        "default": true,
+                        "type": "boolean"
+                    }
+                }
+            },
+            {
+                "title": "completion",
+                "properties": {
                     "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,
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 5550bfa6558..96dc4f19b82 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -361,7 +361,14 @@ export class Ctx implements RustAnalyzerExtensionApi {
             }
         });
 
-        vscode.workspace.onDidChangeTextDocument(async () => {
+        vscode.workspace.onDidChangeTextDocument(async (e) => {
+            if (
+                vscode.window.activeTextEditor?.document !== e.document ||
+                e.contentChanges.length === 0
+            ) {
+                return;
+            }
+
             if (this.syntaxTreeView?.visible) {
                 await this.syntaxTreeProvider?.refresh();
             }
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 074bc43388a..2749557b91a 100644
--- a/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
+++ b/src/tools/rust-analyzer/lib/lsp-server/src/msg.rs
@@ -80,9 +80,9 @@ pub struct Request {
 
 #[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct Response {
-    // JSON RPC allows this to be null if it was impossible
-    // to decode the request's id. Ignore this special case
-    // and just die horribly.
+    // JSON-RPC allows this to be null if we can't find or parse the
+    // request id. We fail deserialization in that case, so we just
+    // make this field mandatory.
     pub id: RequestId,
     #[serde(skip_serializing_if = "Option::is_none")]
     pub result: Option<serde_json::Value>,
diff --git a/src/tools/rustbook/Cargo.lock b/src/tools/rustbook/Cargo.lock
index 86d2abcacb7..b31bf61a6fb 100644
--- a/src/tools/rustbook/Cargo.lock
+++ b/src/tools/rustbook/Cargo.lock
@@ -150,9 +150,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.16.0"
+version = "3.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf"
 
 [[package]]
 name = "byteorder"
@@ -191,9 +191,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.5.26"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783"
+checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -201,9 +201,9 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.5.26"
+version = "4.5.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121"
+checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7"
 dependencies = [
  "anstream",
  "anstyle",
@@ -214,9 +214,9 @@ dependencies = [
 
 [[package]]
 name = "clap_complete"
-version = "4.5.42"
+version = "4.5.43"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "33a7e468e750fa4b6be660e8b5651ad47372e8fb114030b594c2d75d48c5ffd0"
+checksum = "0952013545c9c6dca60f491602655b795c6c062ab180c9cb0bccb83135461861"
 dependencies = [
  "clap",
 ]
@@ -253,9 +253,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b"
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.16"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3"
+checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280"
 dependencies = [
  "libc",
 ]
@@ -750,9 +750,9 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.7.0"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f"
+checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652"
 dependencies = [
  "equivalent",
  "hashbrown",
@@ -867,9 +867,9 @@ dependencies = [
 
 [[package]]
 name = "mdbook"
-version = "0.4.43"
+version = "0.4.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fe1f98b8d66e537d2f0ba06e7dec4f44001deec539a2d18bfc102d6a86189148"
+checksum = "f9da1e54401fe5d45a664c57e112e70f18e8c5a73e268c179305b932ee864574"
 dependencies = [
  "ammonia",
  "anyhow",
@@ -1372,9 +1372,9 @@ dependencies = [
 
 [[package]]
 name = "rustix"
-version = "0.38.43"
+version = "0.38.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
+checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
 dependencies = [
  "bitflags 2.8.0",
  "errno",
@@ -1391,9 +1391,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4"
 
 [[package]]
 name = "ryu"
-version = "1.0.18"
+version = "1.0.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd"
 
 [[package]]
 name = "same-file"
@@ -1412,9 +1412,9 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "semver"
-version = "1.0.24"
+version = "1.0.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba"
+checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03"
 
 [[package]]
 name = "serde"
@@ -1438,9 +1438,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.135"
+version = "1.0.138"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9"
+checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949"
 dependencies = [
  "itoa",
  "memchr",
@@ -1732,9 +1732,9 @@ checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.14"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
+checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034"
 
 [[package]]
 name = "unicode-width"
@@ -1972,9 +1972,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
 
 [[package]]
 name = "winnow"
-version = "0.6.24"
+version = "0.6.25"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8d71a593cc5c42ad7876e2c1fda56f314f3754c084128833e64f1345ff8a03a"
+checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310"
 dependencies = [
  "memchr",
 ]
diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml
index c2ce8fef4d0..9f9846cdee0 100644
--- a/src/tools/rustbook/Cargo.toml
+++ b/src/tools/rustbook/Cargo.toml
@@ -14,6 +14,6 @@ mdbook-i18n-helpers = "0.3.3"
 mdbook-spec = { path = "../../doc/reference/mdbook-spec" }
 
 [dependencies.mdbook]
-version = "0.4.37"
+version = "0.4.44"
 default-features = false
 features = ["search"]
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index e7d0fba048b..457d0afe3b5 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -333,19 +333,19 @@ impl<'a> FnSig<'a> {
         defaultness: ast::Defaultness,
     ) -> FnSig<'a> {
         match *fn_kind {
-            visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _) => {
-                let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
+            visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, vis, ast::Fn { sig, generics, .. }) => {
+                let mut fn_sig = FnSig::from_method_sig(sig, generics, vis);
                 fn_sig.defaultness = defaultness;
                 fn_sig
             }
-            visit::FnKind::Fn(_, _, fn_sig, vis, generics, _) => FnSig {
+            visit::FnKind::Fn(_, _, vis, ast::Fn { sig, generics, .. }) => FnSig {
                 decl,
                 generics,
-                ext: fn_sig.header.ext,
-                constness: fn_sig.header.constness,
-                coroutine_kind: Cow::Borrowed(&fn_sig.header.coroutine_kind),
+                ext: sig.header.ext,
+                constness: sig.header.constness,
+                coroutine_kind: Cow::Borrowed(&sig.header.coroutine_kind),
                 defaultness,
-                safety: fn_sig.header.safety,
+                safety: sig.header.safety,
                 visibility: vis,
             },
             _ => unreachable!(),
@@ -3453,6 +3453,7 @@ impl Rewrite for ast::ForeignItem {
                     ref sig,
                     ref generics,
                     ref body,
+                    ..
                 } = **fn_kind;
                 if body.is_some() {
                     let mut visitor = FmtVisitor::from_context(context);
@@ -3461,7 +3462,7 @@ impl Rewrite for ast::ForeignItem {
                     let inner_attrs = inner_attributes(&self.attrs);
                     let fn_ctxt = visit::FnCtxt::Foreign;
                     visitor.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, &self.ident, sig, &self.vis, generics, body),
+                        visit::FnKind::Fn(fn_ctxt, &self.ident, &self.vis, fn_kind),
                         &sig.decl,
                         self.span,
                         defaultness,
diff --git a/src/tools/rustfmt/src/visitor.rs b/src/tools/rustfmt/src/visitor.rs
index 805e13b7803..bdcb619153d 100644
--- a/src/tools/rustfmt/src/visitor.rs
+++ b/src/tools/rustfmt/src/visitor.rs
@@ -386,7 +386,14 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
         let indent = self.block_indent;
         let block;
         let rewrite = match fk {
-            visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
+            visit::FnKind::Fn(
+                _,
+                ident,
+                _,
+                ast::Fn {
+                    body: Some(ref b), ..
+                },
+            ) => {
                 block = b;
                 self.rewrite_fn_before_block(
                     indent,
@@ -539,6 +546,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                         ref sig,
                         ref generics,
                         ref body,
+                        ..
                     } = **fn_kind;
                     if body.is_some() {
                         let inner_attrs = inner_attributes(&item.attrs);
@@ -547,7 +555,7 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                             _ => visit::FnCtxt::Foreign,
                         };
                         self.visit_fn(
-                            visit::FnKind::Fn(fn_ctxt, &item.ident, sig, &item.vis, generics, body),
+                            visit::FnKind::Fn(fn_ctxt, &item.ident, &item.vis, fn_kind),
                             &sig.decl,
                             item.span,
                             defaultness,
@@ -640,12 +648,13 @@ impl<'b, 'a: 'b> FmtVisitor<'a> {
                     ref sig,
                     ref generics,
                     ref body,
+                    ..
                 } = **fn_kind;
                 if body.is_some() {
                     let inner_attrs = inner_attributes(&ai.attrs);
                     let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
                     self.visit_fn(
-                        visit::FnKind::Fn(fn_ctxt, &ai.ident, sig, &ai.vis, generics, body),
+                        visit::FnKind::Fn(fn_ctxt, &ai.ident, &ai.vis, fn_kind),
                         &sig.decl,
                         ai.span,
                         defaultness,
diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt
index 6f0fd09b353..e75d3dc2147 100644
--- a/src/tools/tidy/src/allowed_run_make_makefiles.txt
+++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt
@@ -1,3 +1,2 @@
 run-make/split-debuginfo/Makefile
 run-make/symbol-mangling-hashed/Makefile
-run-make/translation/Makefile
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
index 605a0d520a7..7f99f695bf4 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-gather.rs
@@ -23,7 +23,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
                            values: Vec2<f32>) -> Vec2<f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x float> @llvm.masked.gather.v2f32.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x float> {{.*}})
     simd_gather(values, pointers, mask)
@@ -33,7 +33,7 @@ pub unsafe fn gather_f32x2(pointers: Vec2<*const f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn gather_pf32x2(pointers: Vec2<*const *const f32>, mask: Vec2<i32>,
                            values: Vec2<*const f32>) -> Vec2<*const f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x ptr> @llvm.masked.gather.v2p0.v2p0(<2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]], <2 x ptr> {{.*}})
     simd_gather(values, pointers, mask)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
index 015f6fd9cef..7f46630e920 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-load.rs
@@ -21,7 +21,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32,
                          values: Vec2<f32>) -> Vec2<f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call <2 x float> @llvm.masked.load.v2f32.p0(ptr {{.*}}, i32 4, <2 x i1> [[B]], <2 x float> {{.*}})
     simd_masked_load(mask, pointer, values)
@@ -31,7 +31,7 @@ pub unsafe fn load_f32x2(mask: Vec2<i32>, pointer: *const f32,
 #[no_mangle]
 pub unsafe fn load_pf32x4(mask: Vec4<i32>, pointer: *const *const f32,
                           values: Vec4<*const f32>) -> Vec4<*const f32> {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: call <4 x ptr> @llvm.masked.load.v4p0.p0(ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]], <4 x ptr> {{.*}})
     simd_masked_load(mask, pointer, values)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
index 471a4bea181..0d43234f1e2 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-masked-store.rs
@@ -20,7 +20,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @store_f32x2
 #[no_mangle]
 pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.store.v2f32.p0(<2 x float> {{.*}}, ptr {{.*}}, i32 4, <2 x i1> [[B]])
     simd_masked_store(mask, pointer, values)
@@ -29,7 +29,7 @@ pub unsafe fn store_f32x2(mask: Vec2<i32>, pointer: *mut f32, values: Vec2<f32>)
 // CHECK-LABEL: @store_pf32x4
 #[no_mangle]
 pub unsafe fn store_pf32x4(mask: Vec4<i32>, pointer: *mut *const f32, values: Vec4<*const f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> {{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: call void @llvm.masked.store.v4p0.p0(<4 x ptr> {{.*}}, ptr {{.*}}, i32 {{.*}}, <4 x i1> [[B]])
     simd_masked_store(mask, pointer, values)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
index 1c42b2534d8..ef7827bd96f 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-scatter.rs
@@ -23,7 +23,7 @@ extern "rust-intrinsic" {
 #[no_mangle]
 pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
                             values: Vec2<f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.scatter.v2f32.v2p0(<2 x float> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
     simd_scatter(values, pointers, mask)
@@ -34,7 +34,7 @@ pub unsafe fn scatter_f32x2(pointers: Vec2<*mut f32>, mask: Vec2<i32>,
 #[no_mangle]
 pub unsafe fn scatter_pf32x2(pointers: Vec2<*mut *const f32>, mask: Vec2<i32>,
                              values: Vec2<*const f32>) {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> {{.*}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: call void @llvm.masked.scatter.v2p0.v2p0(<2 x ptr> {{.*}}, <2 x ptr> {{.*}}, i32 {{.*}}, <2 x i1> [[B]]
     simd_scatter(values, pointers, mask)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
index a73593160f2..33ed2b437f9 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-generic-select.rs
@@ -29,7 +29,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @select_m8
 #[no_mangle]
 pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, <i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i8> %{{.*}}, {{<i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i8> [[A]] to <4 x i1>
     // CHECK: select <4 x i1> [[B]]
     simd_select(m, a, b)
@@ -38,7 +38,7 @@ pub unsafe fn select_m8(m: b8x4, a: f32x4, b: f32x4) -> f32x4 {
 // CHECK-LABEL: @select_m32
 #[no_mangle]
 pub unsafe fn select_m32(m: i32x4, a: f32x4, b: f32x4) -> f32x4 {
-    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, <i32 31, i32 31, i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <4 x i32> %{{.*}}, {{<i32 31, i32 31, i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <4 x i32> [[A]] to <4 x i1>
     // CHECK: select <4 x i1> [[B]]
     simd_select(m, a, b)
diff --git a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
index 4df246c2f5c..92067db9b15 100644
--- a/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
+++ b/tests/codegen/simd-intrinsic/simd-intrinsic-mask-reduce.rs
@@ -27,7 +27,7 @@ extern "rust-intrinsic" {
 // CHECK-LABEL: @reduce_any_32x2
 #[no_mangle]
 pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v2i1(<2 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -37,7 +37,7 @@ pub unsafe fn reduce_any_32x2(x: mask32x2) -> bool {
 // CHECK-LABEL: @reduce_all_32x2
 #[no_mangle]
 pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, <i32 31, i32 31>
+    // CHECK: [[A:%[0-9]+]] = lshr <2 x i32> %{{x|1}}, {{<i32 31, i32 31>|splat \(i32 31\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <2 x i32> [[A]] to <2 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v2i1(<2 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -47,7 +47,7 @@ pub unsafe fn reduce_all_32x2(x: mask32x2) -> bool {
 // CHECK-LABEL: @reduce_any_8x16
 #[no_mangle]
 pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.or.v16i1(<16 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
@@ -57,7 +57,7 @@ pub unsafe fn reduce_any_8x16(x: mask8x16) -> bool {
 // CHECK-LABEL: @reduce_all_8x16
 #[no_mangle]
 pub unsafe fn reduce_all_8x16(x: mask8x16) -> bool {
-    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>
+    // CHECK: [[A:%[0-9]+]] = lshr <16 x i8> %{{x|1}}, {{<i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>|splat \(i8 7\)}}
     // CHECK: [[B:%[0-9]+]] = trunc <16 x i8> [[A]] to <16 x i1>
     // CHECK: [[C:%[0-9]+]] = call i1 @llvm.vector.reduce.and.v16i1(<16 x i1> [[B]])
     // CHECK: %{{[0-9]+}} = zext i1 [[C]] to i8
diff --git a/tests/codegen/target-feature-overrides.rs b/tests/codegen/target-feature-overrides.rs
index e7f70a1e24a..f38a1ae72de 100644
--- a/tests/codegen/target-feature-overrides.rs
+++ b/tests/codegen/target-feature-overrides.rs
@@ -39,8 +39,8 @@ pub unsafe fn banana() -> u32 {
 }
 
 // CHECK: attributes [[APPLEATTRS]]
-// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx,+avx,{{.*}}"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx,+avx,{{.*}}"
 // CHECK: attributes [[BANANAATTRS]]
-// COMPAT-SAME: "target-features"="+x87,+sse2,+avx,+avx2,{{.*}}"
-// INCOMPAT-SAME: "target-features"="+x87,+sse2,-avx2,-avx"
+// COMPAT-SAME: "target-features"="+avx,+avx2,{{.*}}"
+// INCOMPAT-SAME: "target-features"="-avx2,-avx"
diff --git a/tests/codegen/tied-features-strength.rs b/tests/codegen/tied-features-strength.rs
index 6daa5cd7d5e..1b2b63c3d1a 100644
--- a/tests/codegen/tied-features-strength.rs
+++ b/tests/codegen/tied-features-strength.rs
@@ -11,11 +11,10 @@
 // ENABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
 
 //@ [DISABLE_SVE] compile-flags: -C target-feature=-sve -Copt-level=0
-// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?)|(\+fp-armv8,?))*}}" }
+// DISABLE_SVE: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-sve,?)|(\+neon,?))*}}" }
 
 //@ [DISABLE_NEON] compile-flags: -C target-feature=-neon -Copt-level=0
-// `neon` and `fp-armv8` get enabled as target base features, but then disabled again at the end of the list.
-// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fp-armv8,?)|(\+neon,?))*}},-neon,-fp-armv8{{(,\+fpmr)?}}" }
+// DISABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(-fp-armv8,?)|(-neon,?))*}}" }
 
 //@ [ENABLE_NEON] compile-flags: -C target-feature=+neon -Copt-level=0
 // ENABLE_NEON: attributes #0 = { {{.*}} "target-features"="{{((\+outline-atomics,?)|(\+v8a,?)|(\+fpmr,?)?|(\+fp-armv8,?)|(\+neon,?))*}}" }
diff --git a/tests/crashes/131103.rs b/tests/crashes/131103.rs
deleted file mode 100644
index 70193e8b3bd..00000000000
--- a/tests/crashes/131103.rs
+++ /dev/null
@@ -1,6 +0,0 @@
-//@ known-bug: #131103
-struct Struct<const N: i128>(pub [u8; N]);
-
-pub fn function(value: Struct<3>) -> u8 {
-    value.0[0]
-}
diff --git a/tests/mir-opt/pattern_types.main.PreCodegen.after.mir b/tests/mir-opt/pattern_types.main.PreCodegen.after.mir
new file mode 100644
index 00000000000..8c99902f9b8
--- /dev/null
+++ b/tests/mir-opt/pattern_types.main.PreCodegen.after.mir
@@ -0,0 +1,15 @@
+// MIR for `main` after PreCodegen
+
+fn main() -> () {
+    let mut _0: ();
+    scope 1 {
+        debug x => const 2_u32 is 1..=;
+        scope 2 {
+            debug y => const 0_u32 is 1..=;
+        }
+    }
+
+    bb0: {
+        return;
+    }
+}
diff --git a/tests/mir-opt/pattern_types.rs b/tests/mir-opt/pattern_types.rs
new file mode 100644
index 00000000000..217c64b90cb
--- /dev/null
+++ b/tests/mir-opt/pattern_types.rs
@@ -0,0 +1,12 @@
+#![feature(pattern_types)]
+#![feature(pattern_type_macro)]
+
+use std::pat::pattern_type;
+
+// EMIT_MIR pattern_types.main.PreCodegen.after.mir
+fn main() {
+    // CHECK: debug x => const 2_u32 is 1..=
+    let x: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(2) };
+    // CHECK: debug y => const 0_u32 is 1..=
+    let y: pattern_type!(u32 is 1..) = unsafe { std::mem::transmute(0) };
+}
diff --git a/tests/run-make/translation/Makefile b/tests/run-make/translation/Makefile
deleted file mode 100644
index 07e0547cfa0..00000000000
--- a/tests/run-make/translation/Makefile
+++ /dev/null
@@ -1,78 +0,0 @@
-include ../tools.mk
-
-# This test uses `ln -s` rather than copying to save testing time, but its
-# usage doesn't work on Windows.
-# ignore-windows
-
-SYSROOT:=$(shell $(RUSTC) --print sysroot)
-FAKEROOT=$(TMPDIR)/fakeroot
-RUSTC_LOG:=rustc_error_messages
-export RUSTC_TRANSLATION_NO_DEBUG_ASSERT:=1
-
-all: normal custom missing broken sysroot sysroot-invalid sysroot-missing
-
-# Check that the test works normally, using the built-in fallback bundle.
-normal: test.rs
-	$(RUSTC) $< 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a primary bundle can be loaded and will be preferentially used
-# where possible.
-custom: test.rs working.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/working.ftl 2>&1 | $(CGREP) "this is a test message"
-
-# Check that a primary bundle with a broken message (e.g. a interpolated
-# variable is missing) will use the fallback bundle.
-missing: test.rs missing.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/missing.ftl 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a primary bundle without the desired message will use the fallback
-# bundle.
-broken: test.rs broken.ftl
-	$(RUSTC) $< -Ztranslate-additional-ftl=$(CURDIR)/broken.ftl 2>&1 | $(CGREP) "struct literal body without path"
-
-# Check that a locale can be loaded from the sysroot given a language
-# identifier by making a local copy of the sysroot and adding the custom locale
-# to it.
-sysroot: test.rs working.ftl
-	rm -rf $(FAKEROOT)
-	mkdir $(FAKEROOT)
-	ln -s $(SYSROOT)/* $(FAKEROOT)
-	rm -f $(FAKEROOT)/lib
-	mkdir $(FAKEROOT)/lib
-	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
-	rm -f $(FAKEROOT)/lib/rustlib
-	mkdir $(FAKEROOT)/lib/rustlib
-	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
-	rm -f $(FAKEROOT)/lib/rustlib/src
-	mkdir $(FAKEROOT)/lib/rustlib/src
-	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
-	# When download-rustc is enabled, `$(SYSROOT)` will have a share directory. Delete the link to it.
-	rm -f $(FAKEROOT)/share
-	mkdir -p $(FAKEROOT)/share/locale/zh-CN/
-	ln -s $(CURDIR)/working.ftl $(FAKEROOT)/share/locale/zh-CN/basic-translation.ftl
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "this is a test message"
-
-# Check that the compiler errors out when the sysroot requested cannot be
-# found. This test might start failing if there actually exists a Klingon
-# translation of rustc's error messages.
-sysroot-missing:
-	$(RUSTC) $< -Ztranslate-lang=tlh 2>&1 | $(CGREP) "missing locale directory"
-
-# Check that the compiler errors out when the directory for the locale in the
-# sysroot is actually a file.
-sysroot-invalid: test.rs working.ftl
-	rm -rf $(FAKEROOT)
-	mkdir $(FAKEROOT)
-	ln -s $(SYSROOT)/* $(FAKEROOT)
-	rm -f $(FAKEROOT)/lib
-	mkdir $(FAKEROOT)/lib
-	ln -s $(SYSROOT)/lib/* $(FAKEROOT)/lib
-	rm -f $(FAKEROOT)/lib/rustlib
-	mkdir $(FAKEROOT)/lib/rustlib
-	ln -s $(SYSROOT)/lib/rustlib/* $(FAKEROOT)/lib/rustlib
-	rm -f $(FAKEROOT)/lib/rustlib/src
-	mkdir $(FAKEROOT)/lib/rustlib/src
-	ln -s $(SYSROOT)/lib/rustlib/src/* $(FAKEROOT)/lib/rustlib/src
-	mkdir -p $(FAKEROOT)/share/locale
-	touch $(FAKEROOT)/share/locale/zh-CN
-	$(RUSTC) $< --sysroot $(FAKEROOT) -Ztranslate-lang=zh-CN 2>&1 | $(CGREP) "`\$sysroot/share/locales/\$locale` is not a directory"
diff --git a/tests/run-make/translation/rmake.rs b/tests/run-make/translation/rmake.rs
new file mode 100644
index 00000000000..86078888c2e
--- /dev/null
+++ b/tests/run-make/translation/rmake.rs
@@ -0,0 +1,194 @@
+//! Smoke test for the rustc diagnostics translation infrastructure.
+//!
+//! # References
+//!
+//! - Current tracking issue: <https://github.com/rust-lang/rust/issues/132181>.
+//! - Old tracking issue: <https://github.com/rust-lang/rust/issues/100717>
+//! - Initial translation infra implementation: <https://github.com/rust-lang/rust/pull/95512>.
+
+// This test uses symbolic links to stub out a fake sysroot to save testing time.
+//@ needs-symlink
+//@ needs-subprocess
+
+#![deny(warnings)]
+
+use std::path::{Path, PathBuf};
+
+use run_make_support::rustc::sysroot;
+use run_make_support::{cwd, rfs, run_in_tmpdir, rustc};
+
+fn main() {
+    builtin_fallback_bundle();
+    additional_primary_bundle();
+    missing_slug_prefers_fallback_bundle();
+    broken_primary_bundle_prefers_fallback_bundle();
+    locale_sysroot();
+    missing_sysroot();
+    file_sysroot();
+}
+
+/// Check that the test works normally, using the built-in fallback bundle.
+fn builtin_fallback_bundle() {
+    rustc().input("test.rs").run_fail().assert_stderr_contains("struct literal body without path");
+}
+
+/// Check that a primary bundle can be loaded and will be preferentially used where possible.
+fn additional_primary_bundle() {
+    rustc()
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=working.ftl")
+        .run_fail()
+        .assert_stderr_contains("this is a test message");
+}
+
+/// Check that a primary bundle without the desired message will use the fallback bundle.
+fn missing_slug_prefers_fallback_bundle() {
+    rustc()
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=missing.ftl")
+        .run_fail()
+        .assert_stderr_contains("struct literal body without path");
+}
+
+/// Check that a primary bundle with a broken message (e.g. an interpolated variable is not
+/// provided) will use the fallback bundle.
+fn broken_primary_bundle_prefers_fallback_bundle() {
+    // FIXME(#135817): as of the rmake.rs port, the compiler actually ICEs on the additional
+    // `broken.ftl`, even though the original intention seems to be that it should gracefully
+    // failover to the fallback bundle. On `aarch64-apple-darwin`, somehow it *doesn't* ICE.
+
+    rustc()
+        .env("RUSTC_ICE", "0") // disable ICE dump file, not needed
+        .input("test.rs")
+        .arg("-Ztranslate-additional-ftl=broken.ftl")
+        .run_fail();
+}
+
+#[track_caller]
+fn shallow_symlink_dir_entries(src_dir: &Path, dst_dir: &Path) {
+    for entry in rfs::read_dir(src_dir) {
+        let entry = entry.unwrap();
+        let src_entry_path = entry.path();
+        let src_filename = src_entry_path.file_name().unwrap();
+        let meta = rfs::symlink_metadata(&src_entry_path);
+        if meta.is_symlink() || meta.is_file() {
+            rfs::symlink_file(&src_entry_path, dst_dir.join(src_filename));
+        } else if meta.is_dir() {
+            rfs::symlink_dir(&src_entry_path, dst_dir.join(src_filename));
+        } else {
+            unreachable!()
+        }
+    }
+}
+
+#[track_caller]
+fn shallow_symlink_dir_entries_materialize_single_dir(
+    src_dir: &Path,
+    dst_dir: &Path,
+    dir_filename: &str,
+) {
+    shallow_symlink_dir_entries(src_dir, dst_dir);
+
+    let dst_symlink_meta = rfs::symlink_metadata(dst_dir.join(dir_filename));
+
+    if dst_symlink_meta.is_file() || dst_symlink_meta.is_dir() {
+        unreachable!();
+    }
+
+    #[cfg(windows)]
+    {
+        use std::os::windows::fs::FileTypeExt as _;
+        if dst_symlink_meta.file_type().is_symlink_file() {
+            rfs::remove_file(dst_dir.join(dir_filename));
+        } else if dst_symlink_meta.file_type().is_symlink_dir() {
+            rfs::remove_dir(dst_dir.join(dir_filename));
+        } else {
+            unreachable!();
+        }
+    }
+    #[cfg(not(windows))]
+    {
+        rfs::remove_file(dst_dir.join(dir_filename));
+    }
+
+    rfs::create_dir_all(dst_dir.join(dir_filename));
+}
+
+#[track_caller]
+fn setup_fakeroot_parents() -> PathBuf {
+    let sysroot = sysroot();
+    let fakeroot = cwd().join("fakeroot");
+    rfs::create_dir_all(&fakeroot);
+    shallow_symlink_dir_entries_materialize_single_dir(&sysroot, &fakeroot, "lib");
+    shallow_symlink_dir_entries_materialize_single_dir(
+        &sysroot.join("lib"),
+        &fakeroot.join("lib"),
+        "rustlib",
+    );
+    shallow_symlink_dir_entries_materialize_single_dir(
+        &sysroot.join("lib").join("rustlib"),
+        &fakeroot.join("lib").join("rustlib"),
+        "src",
+    );
+    shallow_symlink_dir_entries(
+        &sysroot.join("lib").join("rustlib").join("src"),
+        &fakeroot.join("lib").join("rustlib").join("src"),
+    );
+    fakeroot
+}
+
+/// Check that a locale can be loaded from the sysroot given a language identifier by making a local
+/// copy of the sysroot and adding the custom locale to it.
+fn locale_sysroot() {
+    run_in_tmpdir(|| {
+        let fakeroot = setup_fakeroot_parents();
+
+        // When download-rustc is enabled, real sysroot will have a share directory. Delete the link
+        // to it.
+        let _ = std::fs::remove_file(fakeroot.join("share"));
+
+        let fake_locale_path = fakeroot.join("share").join("locale").join("zh-CN");
+        rfs::create_dir_all(&fake_locale_path);
+        rfs::symlink_file(
+            cwd().join("working.ftl"),
+            fake_locale_path.join("basic-translation.ftl"),
+        );
+
+        rustc()
+            .env("RUSTC_ICE", "0")
+            .input("test.rs")
+            .sysroot(&fakeroot)
+            .arg("-Ztranslate-lang=zh-CN")
+            .run_fail()
+            .assert_stderr_contains("this is a test message");
+    });
+}
+
+/// Check that the compiler errors out when the sysroot requested cannot be found. This test might
+/// start failing if there actually exists a Klingon translation of rustc's error messages.
+fn missing_sysroot() {
+    run_in_tmpdir(|| {
+        rustc()
+            .input("test.rs")
+            .arg("-Ztranslate-lang=tlh")
+            .run_fail()
+            .assert_stderr_contains("missing locale directory");
+    });
+}
+
+/// Check that the compiler errors out when the directory for the locale in the sysroot is actually
+/// a file.
+fn file_sysroot() {
+    run_in_tmpdir(|| {
+        let fakeroot = setup_fakeroot_parents();
+        rfs::create_dir_all(fakeroot.join("share").join("locale"));
+        rfs::write(fakeroot.join("share").join("locale").join("zh-CN"), b"not a dir");
+
+        rustc()
+            .input("test.rs")
+            .sysroot(&fakeroot)
+            .arg("-Ztranslate-lang=zh-CN")
+            .run_fail()
+            .assert_stderr_contains("is not a directory");
+    });
+}
diff --git a/tests/ui-fulldeps/codegen-backend/hotplug.rs b/tests/ui-fulldeps/codegen-backend/hotplug.rs
index 917b20fcdb5..ce310ba3e31 100644
--- a/tests/ui-fulldeps/codegen-backend/hotplug.rs
+++ b/tests/ui-fulldeps/codegen-backend/hotplug.rs
@@ -6,6 +6,10 @@
 //@ normalize-stdout: "libthe_backend.dylib" -> "libthe_backend.so"
 //@ normalize-stdout: "the_backend.dll" -> "libthe_backend.so"
 
+// Pick a target that requires no target features, so that no warning is shown
+// about missing target features.
+//@ compile-flags: --target arm-unknown-linux-gnueabi
+//@ needs-llvm-components: arm
 //@ revisions: normal dep bindep
 //@ compile-flags: --crate-type=lib
 //@ [normal] compile-flags: --emit=link=-
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
index 409178df9c5..27c8e958e53 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32e.stderr
@@ -22,170 +22,164 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: cannot use register `x16`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:48:18
+  --> $DIR/bad-reg.rs:46:18
    |
 LL |         asm!("", out("x16") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x17`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:50:18
+  --> $DIR/bad-reg.rs:48:18
    |
 LL |         asm!("", out("x17") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x18`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:52:18
+  --> $DIR/bad-reg.rs:50:18
    |
 LL |         asm!("", out("x18") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x19`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:54:18
+  --> $DIR/bad-reg.rs:52:18
    |
 LL |         asm!("", out("x19") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x20`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:56:18
+  --> $DIR/bad-reg.rs:54:18
    |
 LL |         asm!("", out("x20") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x21`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:58:18
+  --> $DIR/bad-reg.rs:56:18
    |
 LL |         asm!("", out("x21") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x22`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:60:18
+  --> $DIR/bad-reg.rs:58:18
    |
 LL |         asm!("", out("x22") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x23`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:62:18
+  --> $DIR/bad-reg.rs:60:18
    |
 LL |         asm!("", out("x23") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x24`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:64:18
+  --> $DIR/bad-reg.rs:62:18
    |
 LL |         asm!("", out("x24") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x25`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:66:18
+  --> $DIR/bad-reg.rs:64:18
    |
 LL |         asm!("", out("x25") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x26`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:68:18
+  --> $DIR/bad-reg.rs:66:18
    |
 LL |         asm!("", out("x26") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x27`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:70:18
+  --> $DIR/bad-reg.rs:68:18
    |
 LL |         asm!("", out("x27") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x28`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:72:18
+  --> $DIR/bad-reg.rs:70:18
    |
 LL |         asm!("", out("x28") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x29`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:74:18
+  --> $DIR/bad-reg.rs:72:18
    |
 LL |         asm!("", out("x29") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x30`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:76:18
+  --> $DIR/bad-reg.rs:74:18
    |
 LL |         asm!("", out("x30") _);
    |                  ^^^^^^^^^^^^
 
 error: cannot use register `x31`: register can't be used with the `e` target feature
-  --> $DIR/bad-reg.rs:78:18
+  --> $DIR/bad-reg.rs:76:18
    |
 LL |         asm!("", out("x31") _);
    |                  ^^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -193,7 +187,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -201,12 +195,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 34 previous errors
+error: aborting due to 33 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
index 4770e70cc2b..4ff03d819e6 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32gc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -73,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -81,12 +75,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
index ae7db1554b1..fbe63eb0563 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32i.stderr
@@ -22,74 +22,68 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -97,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -105,12 +99,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 18 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
index 8bc5c9a87fc..57664cfe893 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv32imafc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:86:35
+  --> $DIR/bad-reg.rs:84:35
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                                   ^
@@ -73,7 +67,7 @@ LL |         asm!("/* {} */", in(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: `d` target feature is not enabled
-  --> $DIR/bad-reg.rs:89:36
+  --> $DIR/bad-reg.rs:87:36
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                                    ^
@@ -81,7 +75,7 @@ LL |         asm!("/* {} */", out(freg) d);
    = note: this is required to use type `f64` with register class `freg`
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -89,7 +83,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -97,12 +91,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 16 previous errors
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
index 4770e70cc2b..4ff03d819e6 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64gc.stderr
@@ -22,50 +22,44 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -73,7 +67,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -81,12 +75,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 14 previous errors
+error: aborting due to 13 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
index ae7db1554b1..fbe63eb0563 100644
--- a/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
+++ b/tests/ui/asm/riscv/bad-reg.riscv64imac.stderr
@@ -22,74 +22,68 @@ error: invalid register `gp`: the global pointer cannot be used as an operand fo
 LL |         asm!("", out("gp") _);
    |                  ^^^^^^^^^^^
 
-error: invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:41:18
-   |
-LL |         asm!("", out("gp") _);
-   |                  ^^^^^^^^^^^
-
 error: invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:43:18
+  --> $DIR/bad-reg.rs:41:18
    |
 LL |         asm!("", out("tp") _);
    |                  ^^^^^^^^^^^
 
 error: invalid register `zero`: the zero register cannot be used as an operand for inline asm
-  --> $DIR/bad-reg.rs:45:18
+  --> $DIR/bad-reg.rs:43:18
    |
 LL |         asm!("", out("zero") _);
    |                  ^^^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:96:18
+  --> $DIR/bad-reg.rs:94:18
    |
 LL |         asm!("", in("v0") x);
    |                  ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:99:18
+  --> $DIR/bad-reg.rs:97:18
    |
 LL |         asm!("", out("v0") x);
    |                  ^^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:102:26
+  --> $DIR/bad-reg.rs:100:26
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                          ^^^^^^^^^^
 
 error: register class `vreg` can only be used as a clobber, not as an input or output
-  --> $DIR/bad-reg.rs:105:26
+  --> $DIR/bad-reg.rs:103:26
    |
 LL |         asm!("/* {} */", out(vreg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:82:26
+  --> $DIR/bad-reg.rs:80:26
    |
 LL |         asm!("/* {} */", in(freg) f);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:84:26
+  --> $DIR/bad-reg.rs:82:26
    |
 LL |         asm!("/* {} */", out(freg) _);
    |                          ^^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:86:26
+  --> $DIR/bad-reg.rs:84:26
    |
 LL |         asm!("/* {} */", in(freg) d);
    |                          ^^^^^^^^^^
 
 error: register class `freg` requires at least one of the following target features: d, f
-  --> $DIR/bad-reg.rs:89:26
+  --> $DIR/bad-reg.rs:87:26
    |
 LL |         asm!("/* {} */", out(freg) d);
    |                          ^^^^^^^^^^^
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:96:27
+  --> $DIR/bad-reg.rs:94:27
    |
 LL |         asm!("", in("v0") x);
    |                           ^
@@ -97,7 +91,7 @@ LL |         asm!("", in("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:99:28
+  --> $DIR/bad-reg.rs:97:28
    |
 LL |         asm!("", out("v0") x);
    |                            ^
@@ -105,12 +99,12 @@ LL |         asm!("", out("v0") x);
    = note: register class `vreg` supports these types: 
 
 error: type `i32` cannot be used with this register class
-  --> $DIR/bad-reg.rs:102:35
+  --> $DIR/bad-reg.rs:100:35
    |
 LL |         asm!("/* {} */", in(vreg) x);
    |                                   ^
    |
    = note: register class `vreg` supports these types: 
 
-error: aborting due to 18 previous errors
+error: aborting due to 17 previous errors
 
diff --git a/tests/ui/asm/riscv/bad-reg.rs b/tests/ui/asm/riscv/bad-reg.rs
index 7f0fc00d548..7d032d277aa 100644
--- a/tests/ui/asm/riscv/bad-reg.rs
+++ b/tests/ui/asm/riscv/bad-reg.rs
@@ -38,8 +38,6 @@ fn f() {
         //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm
         asm!("", out("gp") _);
         //~^ ERROR invalid register `gp`: the global pointer cannot be used as an operand for inline asm
-        asm!("", out("gp") _);
-        //~^ ERROR invalid register `gp`: the global pointer cannot be used as an operand for inline asm
         asm!("", out("tp") _);
         //~^ ERROR invalid register `tp`: the thread pointer cannot be used as an operand for inline asm
         asm!("", out("zero") _);
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.current.stderr
index 3ed73918de3..0d57d9d0142 100644
--- a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.stderr
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.current.stderr
@@ -1,5 +1,5 @@
 error[E0382]: use of moved value: `x`
-  --> $DIR/cant-see-copy-bound-from-child-rigid.rs:14:9
+  --> $DIR/cant-see-copy-bound-from-child-rigid.rs:18:9
    |
 LL | fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
    |                  - move occurs because `x` has type `<T as Trait>::Assoc`, which does not implement the `Copy` trait
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.next.stderr b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.next.stderr
new file mode 100644
index 00000000000..0d57d9d0142
--- /dev/null
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.next.stderr
@@ -0,0 +1,14 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/cant-see-copy-bound-from-child-rigid.rs:18:9
+   |
+LL | fn foo<T: Trait>(x: T::Assoc) -> (T::Assoc, T::Assoc)
+   |                  - move occurs because `x` has type `<T as Trait>::Assoc`, which does not implement the `Copy` trait
+...
+LL |     (x, x)
+   |      -  ^ value used here after move
+   |      |
+   |      value moved here
+
+error: aborting due to 1 previous error
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
index 6b3fd7e898d..fe135031b31 100644
--- a/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
+++ b/tests/ui/associated-type-bounds/cant-see-copy-bound-from-child-rigid.rs
@@ -1,3 +1,7 @@
+//@ revisions: current next
+//@ ignore-compare-mode-next-solver (explicit revisions)
+//@[next] compile-flags: -Znext-solver
+
 trait Id {
     type This: ?Sized;
 }
diff --git a/tests/ui/borrowck/issue-93093.rs b/tests/ui/borrowck/issue-93093.rs
index e85b296c983..1521b207238 100644
--- a/tests/ui/borrowck/issue-93093.rs
+++ b/tests/ui/borrowck/issue-93093.rs
@@ -4,7 +4,7 @@ struct S {
 }
 impl S {
     async fn bar(&self) { //~ HELP consider changing this to be a mutable reference
-        //~| SUGGESTION &mut self
+        //~| SUGGESTION mut
         self.foo += 1; //~ ERROR cannot assign to `self.foo`, which is behind a `&` reference [E0594]
     }
 }
diff --git a/tests/ui/borrowck/issue-93093.stderr b/tests/ui/borrowck/issue-93093.stderr
index b6a2768b61d..d788ce33197 100644
--- a/tests/ui/borrowck/issue-93093.stderr
+++ b/tests/ui/borrowck/issue-93093.stderr
@@ -7,7 +7,7 @@ LL |         self.foo += 1;
 help: consider changing this to be a mutable reference
    |
 LL |     async fn bar(&mut self) {
-   |                  ~~~~~~~~~
+   |                   +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
index 5c70eccfbd3..190ddeaa8f2 100644
--- a/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
+++ b/tests/ui/borrowck/trait-impl-argument-difference-ice.stderr
@@ -41,7 +41,7 @@ LL |         let a16 = self.read_word() as u16;
 help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
    |
 LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
-   |                              ~~~~~~~~~~~~
+   |                                  +++
 
 error[E0596]: cannot borrow `*self` as mutable, as it is behind a `&` reference
   --> $DIR/trait-impl-argument-difference-ice.rs:18:19
@@ -52,7 +52,7 @@ LL |         let b16 = self.read_word() as u16;
 help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
    |
 LL |     extern "C" fn read_dword(&'_ mut self) -> u16 {
-   |                              ~~~~~~~~~~~~
+   |                                  +++
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/tests/ui/const-generics/bad-subst-const-kind.stderr b/tests/ui/const-generics/bad-subst-const-kind.stderr
index 5c8d9c90363..b3605269642 100644
--- a/tests/ui/const-generics/bad-subst-const-kind.stderr
+++ b/tests/ui/const-generics/bad-subst-const-kind.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `13` is not of type `u64`
   --> $DIR/bad-subst-const-kind.rs:13:24
diff --git a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
index e03580ec007..7cb67252da5 100644
--- a/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
+++ b/tests/ui/const-generics/generic_const_exprs/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | impl<const N: u64> Q for [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u64`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error[E0046]: not all trait items implemented, missing: `ASSOC`
   --> $DIR/type_mismatch.rs:8:1
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.rs b/tests/ui/const-generics/issues/index_array_bad_type.rs
new file mode 100644
index 00000000000..91b89cd3fff
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.rs
@@ -0,0 +1,13 @@
+struct Struct<const N: i128>(pub [u8; N]);
+//~^ ERROR the constant `N` is not of type `usize`
+
+pub fn function(value: Struct<3>) -> u8 {
+    value.0[0]
+    //~^ ERROR the constant `3` is not of type `usize`
+
+    // FIXME(const_generics): Ideally we wouldn't report the above error
+    // b/c `Struct<_>` is never well formed, but I'd rather report too many
+    // errors rather than ICE the compiler.
+}
+
+fn main() {}
diff --git a/tests/ui/const-generics/issues/index_array_bad_type.stderr b/tests/ui/const-generics/issues/index_array_bad_type.stderr
new file mode 100644
index 00000000000..ceea0973377
--- /dev/null
+++ b/tests/ui/const-generics/issues/index_array_bad_type.stderr
@@ -0,0 +1,18 @@
+error: the constant `N` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:1:34
+   |
+LL | struct Struct<const N: i128>(pub [u8; N]);
+   |                                  ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
+
+error: the constant `3` is not of type `usize`
+  --> $DIR/index_array_bad_type.rs:5:5
+   |
+LL |     value.0[0]
+   |     ^^^^^^^ expected `usize`, found `i128`
+   |
+   = note: the length of array `[u8; 3]` must be type `usize`
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/const-generics/transmute-fail.stderr b/tests/ui/const-generics/transmute-fail.stderr
index 978a9744e88..0e26daa3a0f 100644
--- a/tests/ui/const-generics/transmute-fail.stderr
+++ b/tests/ui/const-generics/transmute-fail.stderr
@@ -3,6 +3,8 @@ error: the constant `W` is not of type `usize`
    |
 LL | fn bar<const W: bool, const H: usize>(v: [[u32; H]; W]) -> [[u32; W]; H] {
    |                                          ^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:11:9
@@ -18,6 +20,8 @@ error: the constant `W` is not of type `usize`
    |
 LL |         std::mem::transmute(v)
    |         ^^^^^^^^^^^^^^^^^^^ expected `usize`, found `bool`
+   |
+   = note: the length of array `[[u32; H]; W]` must be type `usize`
 
 error[E0512]: cannot transmute between types of different sizes, or dependently-sized types
   --> $DIR/transmute-fail.rs:26:9
diff --git a/tests/ui/const-generics/type_mismatch.stderr b/tests/ui/const-generics/type_mismatch.stderr
index d1bb5c1242f..bd169ed2ec8 100644
--- a/tests/ui/const-generics/type_mismatch.stderr
+++ b/tests/ui/const-generics/type_mismatch.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL | fn bar<const N: u8>() -> [u8; N] {}
    |                          ^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[u8; N]` must be type `usize`
 
 error: the constant `N` is not of type `u8`
   --> $DIR/type_mismatch.rs:2:11
diff --git a/tests/ui/consts/bad-array-size-in-type-err.stderr b/tests/ui/consts/bad-array-size-in-type-err.stderr
index 25d14d80c3e..c3ff216432e 100644
--- a/tests/ui/consts/bad-array-size-in-type-err.stderr
+++ b/tests/ui/consts/bad-array-size-in-type-err.stderr
@@ -3,6 +3,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     arr: [i32; N],
    |          ^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; N]` must be type `usize`
 
 error[E0308]: mismatched types
   --> $DIR/bad-array-size-in-type-err.rs:7:38
@@ -15,6 +17,8 @@ error: the constant `2` is not of type `usize`
    |
 LL |     let _ = BadArraySize::<2> { arr: [0, 0, 0] };
    |                                      ^^^^^^^^^ expected `usize`, found `u8`
+   |
+   = note: the length of array `[i32; 2]` must be type `usize`
 
 error: aborting due to 3 previous errors
 
diff --git a/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
new file mode 100644
index 00000000000..fa1663d49eb
--- /dev/null
+++ b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.rs
@@ -0,0 +1,9 @@
+//@ edition: 2021
+
+fn foo() {}
+
+fn main() {
+    let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect(); //~ ERROR
+    let _: Vec<fn()> = [foo].into_iter().collect(); //~ ERROR
+    let _: Vec<fn()> = Vec::from([foo]); //~ ERROR
+}
diff --git a/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
new file mode 100644
index 00000000000..d069d39514d
--- /dev/null
+++ b/tests/ui/did_you_mean/casting-fn-item-to-fn-pointer.stderr
@@ -0,0 +1,59 @@
+error[E0277]: a value of type `Vec<(&str, fn())>` cannot be built from an iterator over elements of type `(&str, fn() {foo})`
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:6:59
+   |
+LL |     let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
+   |                                                           ^^^^^^^ value of type `Vec<(&str, fn())>` cannot be built from `std::iter::Iterator<Item=(&str, fn() {foo})>`
+   |
+   = help: the trait `FromIterator<(&_, fn() {foo})>` is not implemented for `Vec<(&str, fn())>`
+           but trait `FromIterator<(&_, fn())>` is implemented for it
+   = help: for that trait implementation, expected `fn()`, found `fn() {foo}`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:6:47
+   |
+LL |     let _: Vec<(&str, fn())> = [("foo", foo)].into_iter().collect();
+   |                                -------------- ^^^^^^^^^^^ `Iterator::Item` is `(&str, fn() {foo})` here
+   |                                |
+   |                                this expression has type `[(&str, fn() {foo}); 1]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0277]: a value of type `Vec<fn()>` cannot be built from an iterator over elements of type `fn() {foo}`
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:7:42
+   |
+LL |     let _: Vec<fn()> = [foo].into_iter().collect();
+   |                                          ^^^^^^^ value of type `Vec<fn()>` cannot be built from `std::iter::Iterator<Item=fn() {foo}>`
+   |
+   = help: the trait `FromIterator<fn() {foo}>` is not implemented for `Vec<fn()>`
+           but trait `FromIterator<fn()>` is implemented for it
+   = help: for that trait implementation, expected `fn()`, found `fn() {foo}`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+note: the method call chain might not have had the expected associated types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:7:30
+   |
+LL |     let _: Vec<fn()> = [foo].into_iter().collect();
+   |                        ----- ^^^^^^^^^^^ `Iterator::Item` is `fn() {foo}` here
+   |                        |
+   |                        this expression has type `[fn() {foo}; 1]`
+note: required by a bound in `collect`
+  --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL
+
+error[E0308]: mismatched types
+  --> $DIR/casting-fn-item-to-fn-pointer.rs:8:24
+   |
+LL |     let _: Vec<fn()> = Vec::from([foo]);
+   |            ---------   ^^^^^^^^^^^^^^^^ expected `Vec<fn()>`, found `Vec<fn() {foo}>`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Vec<fn()>`
+              found struct `Vec<fn() {foo}>`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `foo as fn()`
+
+error: aborting due to 3 previous errors
+
+Some errors have detailed explanations: E0277, E0308.
+For more information about an error, try `rustc --explain E0277`.
diff --git a/tests/ui/did_you_mean/issue-38147-1.stderr b/tests/ui/did_you_mean/issue-38147-1.stderr
index a0392113ab1..6def86e4ba8 100644
--- a/tests/ui/did_you_mean/issue-38147-1.stderr
+++ b/tests/ui/did_you_mean/issue-38147-1.stderr
@@ -7,7 +7,7 @@ LL |         self.s.push('x');
 help: consider changing this to be a mutable reference
    |
 LL |     fn f(&mut self) {
-   |          ~~~~~~~~~
+   |           +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/did_you_mean/issue-39544.stderr b/tests/ui/did_you_mean/issue-39544.stderr
index 8ccb4cbb0c1..62dc027e31f 100644
--- a/tests/ui/did_you_mean/issue-39544.stderr
+++ b/tests/ui/did_you_mean/issue-39544.stderr
@@ -18,7 +18,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo<'z>(&'z mut self) {
-   |                ~~~~~~~~~~~~
+   |                    +++
 
 error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:20:17
@@ -29,7 +29,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo1(&mut self, other: &Z) {
-   |             ~~~~~~~~~
+   |              +++
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:21:17
@@ -51,7 +51,7 @@ LL |         let _ = &mut self.x;
 help: consider changing this to be a mutable reference
    |
 LL |     fn foo2<'a>(&'a mut self, other: &Z) {
-   |                 ~~~~~~~~~~~~
+   |                     +++
 
 error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference
   --> $DIR/issue-39544.rs:26:17
diff --git a/tests/ui/generic-const-items/def-site-eval.fail.stderr b/tests/ui/generic-const-items/def-site-eval.fail.stderr
new file mode 100644
index 00000000000..22a5f291697
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-eval.fail.stderr
@@ -0,0 +1,11 @@
+error[E0080]: evaluation of `_::<'_>` failed
+  --> $DIR/def-site-eval.rs:14:20
+   |
+LL | const _<'_a>: () = panic!();
+   |                    ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/def-site-eval.rs:14:20
+   |
+   = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (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 E0080`.
diff --git a/tests/ui/generic-const-items/def-site-eval.rs b/tests/ui/generic-const-items/def-site-eval.rs
new file mode 100644
index 00000000000..3ed7f96aed0
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-eval.rs
@@ -0,0 +1,16 @@
+//! Test that we only evaluate free const items (their def site to be clear)
+//! whose generics don't require monomorphization.
+#![feature(generic_const_items)]
+#![allow(incomplete_features)]
+
+//@ revisions: fail pass
+//@[fail] build-fail (we require monomorphization)
+//@[pass] build-pass (we require monomorphization)
+
+const _<_T>: () = panic!();
+const _<const _N: usize>: () = panic!();
+
+#[cfg(fail)]
+const _<'_a>: () = panic!(); //[fail]~ ERROR evaluation of `_::<'_>` failed
+
+fn main() {}
diff --git a/tests/ui/generic-const-items/def-site-mono.rs b/tests/ui/generic-const-items/def-site-mono.rs
new file mode 100644
index 00000000000..f10d450f6bd
--- /dev/null
+++ b/tests/ui/generic-const-items/def-site-mono.rs
@@ -0,0 +1,13 @@
+//! Ensure that we don't try to collect monomorphizeable items inside free const
+//! items (their def site to be clear) whose generics require monomorphization.
+//!
+//! Such items are to be collected at instantiation sites of free consts.
+
+#![feature(generic_const_items)]
+#![allow(incomplete_features)]
+
+//@ build-pass (we require monomorphization)
+
+const _IDENTITY<T>: fn(T) -> T = |x| x;
+
+fn main() {}
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.rs b/tests/ui/lint/dead-code/lint-dead-code-1.rs
index ddcafedf7bc..a7f654b5d8b 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.rs
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.rs
@@ -29,6 +29,7 @@ const used_const: isize = 0;
 pub const used_const2: isize = used_const;
 const USED_CONST: isize = 1;
 const CONST_USED_IN_ENUM_DISCRIMINANT: isize = 11;
+const CONST_USED_IN_RANGE_PATTERN: isize = 12;
 
 pub type typ = *const UsedStruct4;
 pub struct PubStruct;
@@ -81,6 +82,7 @@ pub fn pub_fn() {
     match i {
         USED_STATIC => (),
         USED_CONST => (),
+        CONST_USED_IN_RANGE_PATTERN..100 => {}
         _ => ()
     }
     f::<StructUsedInGeneric>();
diff --git a/tests/ui/lint/dead-code/lint-dead-code-1.stderr b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
index eb728b5b930..c4410114cea 100644
--- a/tests/ui/lint/dead-code/lint-dead-code-1.stderr
+++ b/tests/ui/lint/dead-code/lint-dead-code-1.stderr
@@ -17,19 +17,19 @@ LL | const priv_const: isize = 0;
    |       ^^^^^^^^^^
 
 error: struct `PrivStruct` is never constructed
-  --> $DIR/lint-dead-code-1.rs:35:8
+  --> $DIR/lint-dead-code-1.rs:36:8
    |
 LL | struct PrivStruct;
    |        ^^^^^^^^^^
 
 error: enum `priv_enum` is never used
-  --> $DIR/lint-dead-code-1.rs:64:6
+  --> $DIR/lint-dead-code-1.rs:65:6
    |
 LL | enum priv_enum { foo2, bar2 }
    |      ^^^^^^^^^
 
 error: variant `bar3` is never constructed
-  --> $DIR/lint-dead-code-1.rs:67:5
+  --> $DIR/lint-dead-code-1.rs:68:5
    |
 LL | enum used_enum {
    |      --------- variant in this enum
@@ -38,25 +38,25 @@ LL |     bar3
    |     ^^^^
 
 error: function `priv_fn` is never used
-  --> $DIR/lint-dead-code-1.rs:88:4
+  --> $DIR/lint-dead-code-1.rs:90:4
    |
 LL | fn priv_fn() {
    |    ^^^^^^^
 
 error: function `foo` is never used
-  --> $DIR/lint-dead-code-1.rs:93:4
+  --> $DIR/lint-dead-code-1.rs:95:4
    |
 LL | fn foo() {
    |    ^^^
 
 error: function `bar` is never used
-  --> $DIR/lint-dead-code-1.rs:98:4
+  --> $DIR/lint-dead-code-1.rs:100:4
    |
 LL | fn bar() {
    |    ^^^
 
 error: function `baz` is never used
-  --> $DIR/lint-dead-code-1.rs:102:4
+  --> $DIR/lint-dead-code-1.rs:104:4
    |
 LL | fn baz() -> impl Copy {
    |    ^^^
diff --git a/tests/ui/mut/mutable-class-fields-2.stderr b/tests/ui/mut/mutable-class-fields-2.stderr
index eb0c54f885b..7a6ff4da2bf 100644
--- a/tests/ui/mut/mutable-class-fields-2.stderr
+++ b/tests/ui/mut/mutable-class-fields-2.stderr
@@ -7,7 +7,7 @@ LL |     self.how_hungry -= 5;
 help: consider changing this to be a mutable reference
    |
 LL |   pub fn eat(&mut self) {
-   |              ~~~~~~~~~
+   |               +++
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/pattern/issue-110508.rs b/tests/ui/pattern/issue-110508.rs
index 6ed0476183e..74a8d673e83 100644
--- a/tests/ui/pattern/issue-110508.rs
+++ b/tests/ui/pattern/issue-110508.rs
@@ -1,5 +1,7 @@
 //@ run-pass
 
+#![deny(dead_code)]
+
 #[derive(PartialEq, Eq)]
 pub enum Foo {
     FooA(()),
@@ -11,6 +13,7 @@ impl Foo {
     const A2: Foo = Self::FooA(());
     const A3: Self = Foo::FooA(());
     const A4: Self = Self::FooA(());
+    const A5: u32 = 1;
 }
 
 fn main() {
@@ -35,4 +38,9 @@ fn main() {
         Foo::A4 => {},
         _ => {},
     }
+
+    match 3 {
+        Foo::A5..5 => {}
+        _ => {}
+    }
 }
diff --git a/tests/ui/asan-odr-win/asan_odr_windows.rs b/tests/ui/sanitizer/asan_odr_windows.rs
index c618ac02a66..c618ac02a66 100644
--- a/tests/ui/asan-odr-win/asan_odr_windows.rs
+++ b/tests/ui/sanitizer/asan_odr_windows.rs
diff --git a/tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs b/tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs
index 75488a29e5e..75488a29e5e 100644
--- a/tests/ui/asan-odr-win/auxiliary/asan_odr_win-2.rs
+++ b/tests/ui/sanitizer/auxiliary/asan_odr_win-2.rs
diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs
index b40439b8e37..9f5df9303c3 100644
--- a/tests/ui/suggestions/suggest-ref-mut.rs
+++ b/tests/ui/suggestions/suggest-ref-mut.rs
@@ -3,7 +3,7 @@ struct X(usize);
 impl X {
     fn zap(&self) {
         //~^ HELP
-        //~| SUGGESTION &mut self
+        //~| SUGGESTION mut
         self.0 = 32;
         //~^ ERROR
     }
diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr
index cc00022ab8e..935a04c052a 100644
--- a/tests/ui/suggestions/suggest-ref-mut.stderr
+++ b/tests/ui/suggestions/suggest-ref-mut.stderr
@@ -7,7 +7,7 @@ LL |         self.0 = 32;
 help: consider changing this to be a mutable reference
    |
 LL |     fn zap(&mut self) {
-   |            ~~~~~~~~~
+   |             +++
 
 error[E0594]: cannot assign to `*foo`, which is behind a `&` reference
   --> $DIR/suggest-ref-mut.rs:15:5
diff --git a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr b/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr
deleted file mode 100644
index b6c3ccdedfb..00000000000
--- a/tests/ui/target-feature/feature-hierarchy.aarch64-sve2.stderr
+++ /dev/null
@@ -1,7 +0,0 @@
-warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
-   |
-   = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
-   = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
-
-warning: 1 warning emitted
-
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr
index 72b2d03fe20..7ec8b04cfce 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-implied.stderr
@@ -1,4 +1,4 @@
-warning: target feature `sse` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
+warning: target feature `sse2` must be enabled to ensure that the ABI of the current target can be implemented correctly
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
index b6c3ccdedfb..b1186d5d5dc 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable-neon.stderr
@@ -1,4 +1,4 @@
-warning: target feature `neon` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
+warning: target feature `neon` must be enabled to ensure that the ABI of the current target can be implemented correctly
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
diff --git a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
index 6191681286a..02398d27501 100644
--- a/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
+++ b/tests/ui/target-feature/forbidden-hardfloat-target-feature-flag-disable.stderr
@@ -1,11 +1,11 @@
-warning: unstable feature specified for `-Ctarget-feature`: `x87`
-   |
-   = note: this feature is not stably supported; its behavior can change in the future
-
-warning: target feature `x87` cannot be disabled with `-Ctarget-feature`: this feature is required by the target ABI
+warning: target feature `x87` must be enabled to ensure that the ABI of the current target can be implemented correctly
    |
    = note: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
    = note: for more information, see issue #116344 <https://github.com/rust-lang/rust/issues/116344>
 
+warning: unstable feature specified for `-Ctarget-feature`: `x87`
+   |
+   = note: this feature is not stably supported; its behavior can change in the future
+
 warning: 2 warnings emitted
 
diff --git a/tests/ui/thir-print/thir-tree-match.stdout b/tests/ui/thir-print/thir-tree-match.stdout
index 916f296ccfc..910582ae4d9 100644
--- a/tests/ui/thir-print/thir-tree-match.stdout
+++ b/tests/ui/thir-print/thir-tree-match.stdout
@@ -26,16 +26,16 @@ params: [
 body:
     Expr {
         ty: bool
-        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
         kind: 
             Scope {
-                region_scope: Node(26)
-                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
+                region_scope: Node(28)
+                lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).28))
                 value:
                     Expr {
                         ty: bool
-                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                         span: $DIR/thir-tree-match.rs:15:32: 21:2 (#0)
                         kind: 
                             Block {
@@ -47,7 +47,7 @@ body:
                                 expr:
                                     Expr {
                                         ty: bool
-                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                         kind: 
                                             Scope {
@@ -56,14 +56,14 @@ body:
                                                 value:
                                                     Expr {
                                                         ty: bool
-                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                         span: $DIR/thir-tree-match.rs:16:5: 20:6 (#0)
                                                         kind: 
                                                             Match {
                                                                 scrutinee:
                                                                     Expr {
                                                                         ty: Foo
-                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                         kind: 
                                                                             Scope {
@@ -72,7 +72,7 @@ body:
                                                                                 value:
                                                                                     Expr {
                                                                                         ty: Foo
-                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
+                                                                                        temp_lifetime: TempLifetime { temp_lifetime: Some(Node(28)), backwards_incompatible: None }
                                                                                         span: $DIR/thir-tree-match.rs:16:11: 16:14 (#0)
                                                                                         kind: 
                                                                                             VarRef {
@@ -123,16 +123,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(14)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
+                                                                                        region_scope: Node(15)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).15))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(13)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(14)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:17:36: 17:40 (#0) }, neg: false)
@@ -140,8 +140,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).13))
-                                                                        scope: Node(13)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).14))
+                                                                        scope: Node(14)
                                                                         span: $DIR/thir-tree-match.rs:17:9: 17:40 (#0)
                                                                     }
                                                                     Arm {
@@ -175,16 +175,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(20)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
+                                                                                        region_scope: Node(21)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).21))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(19)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(20)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(false), span: $DIR/thir-tree-match.rs:18:27: 18:32 (#0) }, neg: false)
@@ -192,8 +192,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).19))
-                                                                        scope: Node(19)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).20))
+                                                                        scope: Node(20)
                                                                         span: $DIR/thir-tree-match.rs:18:9: 18:32 (#0)
                                                                     }
                                                                     Arm {
@@ -219,16 +219,16 @@ body:
                                                                         body: 
                                                                             Expr {
                                                                                 ty: bool
-                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                 kind: 
                                                                                     Scope {
-                                                                                        region_scope: Node(25)
-                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).25))
+                                                                                        region_scope: Node(27)
+                                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).27))
                                                                                         value:
                                                                                             Expr {
                                                                                                 ty: bool
-                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(24)), backwards_incompatible: None }
+                                                                                                temp_lifetime: TempLifetime { temp_lifetime: Some(Node(26)), backwards_incompatible: None }
                                                                                                 span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0)
                                                                                                 kind: 
                                                                                                     Literal( lit: Spanned { node: Bool(true), span: $DIR/thir-tree-match.rs:19:24: 19:28 (#0) }, neg: false)
@@ -236,8 +236,8 @@ body:
                                                                                             }
                                                                                     }
                                                                             }
-                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).24))
-                                                                        scope: Node(24)
+                                                                        lint_level: Explicit(HirId(DefId(0:16 ~ thir_tree_match[fcf8]::has_match).26))
+                                                                        scope: Node(26)
                                                                         span: $DIR/thir-tree-match.rs:19:9: 19:28 (#0)
                                                                     }
                                                                 ]
diff --git a/tests/ui/traits/const-traits/const-impl-trait.stderr b/tests/ui/traits/const-traits/const-impl-trait.stderr
index 4e320059448..27d7957c001 100644
--- a/tests/ui/traits/const-traits/const-impl-trait.stderr
+++ b/tests/ui/traits/const-traits/const-impl-trait.stderr
@@ -100,6 +100,16 @@ note: `PartialEq` can't be used with `~const` because it isn't annotated with `#
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
+  --> $DIR/const-impl-trait.rs:27:22
+   |
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+   |                      ^^^^^^ can't be applied to `PartialEq`
+   |
+note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
+  --> $SRC_DIR/core/src/cmp.rs:LL:COL
+   = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
+
+error: `~const` can only be applied to `#[const_trait]` traits
   --> $DIR/const-impl-trait.rs:23:22
    |
 LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
@@ -120,9 +130,9 @@ note: `PartialEq` can't be used with `~const` because it isn't annotated with `#
    = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`
 
 error: `~const` can only be applied to `#[const_trait]` traits
-  --> $DIR/const-impl-trait.rs:27:22
+  --> $DIR/const-impl-trait.rs:23:22
    |
-LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy {
+LL |     fn huh() -> impl ~const PartialEq + ~const Destruct + Copy;
    |                      ^^^^^^ can't be applied to `PartialEq`
    |
 note: `PartialEq` can't be used with `~const` because it isn't annotated with `#[const_trait]`
@@ -181,7 +191,7 @@ LL |     a == a
    |
    = note: calls in constant functions are limited to constant functions, tuple structs and tuple variants
 
-error: aborting due to 20 previous errors
+error: aborting due to 21 previous errors
 
 Some errors have detailed explanations: E0015, E0635.
 For more information about an error, try `rustc --explain E0015`.
diff --git a/tests/ui/typeck/issue-107775.stderr b/tests/ui/typeck/issue-107775.stderr
index 180b0183a3f..dad7e1581e7 100644
--- a/tests/ui/typeck/issue-107775.stderr
+++ b/tests/ui/typeck/issue-107775.stderr
@@ -10,6 +10,8 @@ LL |         Self { map }
    |
    = note: expected struct `HashMap<u16, fn(_) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>>`
               found struct `HashMap<{integer}, fn(_) -> Pin<Box<dyn Future<Output = ()> + Send>> {<Struct as Trait>::do_something::<'_>}>`
+   = note: fn items are distinct from fn pointers
+   = help: consider casting the fn item to a fn pointer: `<Struct as Trait>::do_something::<'_> as fn(u8) -> Pin<Box<(dyn Future<Output = ()> + Send + 'static)>>`
 
 error: aborting due to 1 previous error
 
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
index 1bcc0dbaf67..92ad83c3300 100644
--- a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.current.stderr
@@ -9,6 +9,8 @@ error: the constant `N` is not of type `usize`
    |
 LL |     fn func<const N: u32>() -> [(); N];
    |                                ^^^^^^^ expected `usize`, found `u32`
+   |
+   = note: the length of array `[(); N]` must be type `usize`
 
 error: aborting due to 2 previous errors