about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-11-24 09:44:46 +0000
committerbors <bors@rust-lang.org>2022-11-24 09:44:46 +0000
commit1dda298ad39a64e019a3511139c5b13ac0a18e54 (patch)
treeac1b48fa193d147d799dedabcddd525f5b0ec5ad /src
parent341d8b8a2c290b4535e965867e876b095461ff6e (diff)
parent1afbd6e0318600639433fc455b4ab641db51c2d0 (diff)
Auto merge of #104809 - matthiaskrgr:rollup-8abjdwh, r=matthiaskrgr
Rollup of 9 pull requests

Successful merges:

 - #103908 (Suggest `.clone()` or `ref binding` on E0382)
 - #104517 (Throw error on failure in loading llvm-plugin)
 - #104594 (Properly handle `Pin<&mut dyn* Trait>` receiver in codegen)
 - #104742 (Make `deref_into_dyn_supertrait` lint the impl and not the usage)
 - #104753 (Pass `InferCtxt` to `DropRangeVisitor` so we can resolve vars)
 - #104771 (Add regression test for issue #99938)
 - #104772 (Small accessibility improvements)
 - #104775 (Use ObligationCtxt::normalize)
 - #104778 (:arrow_up: rust-analyzer)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
Diffstat (limited to 'src')
-rw-r--r--src/librustdoc/html/render/mod.rs12
-rw-r--r--src/librustdoc/html/render/print_item.rs18
-rw-r--r--src/librustdoc/html/static/css/rustdoc.css3
-rw-r--r--src/librustdoc/html/templates/page.html1
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs106
-rw-r--r--src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr62
-rw-r--r--src/test/ui/binding/issue-53114-borrow-checks.stderr16
-rw-r--r--src/test/ui/binop/binop-move-semantics.stderr4
-rw-r--r--src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr25
-rw-r--r--src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr12
-rw-r--r--src/test/ui/borrowck/borrowck-consume-upcast-box.stderr8
-rw-r--r--src/test/ui/borrowck/borrowck-drop-from-guard.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr40
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr36
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr56
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr36
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr56
-rw-r--r--src/test/ui/borrowck/borrowck-move-out-from-array.stderr40
-rw-r--r--src/test/ui/borrowck/borrowck-multiple-captures.stderr15
-rw-r--r--src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr5
-rw-r--r--src/test/ui/borrowck/borrowck-reinit.stderr5
-rw-r--r--src/test/ui/borrowck/issue-31287-drop-in-guard.stderr5
-rw-r--r--src/test/ui/borrowck/issue-41962.stderr2
-rw-r--r--src/test/ui/borrowck/issue-83760.stderr4
-rw-r--r--src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr2
-rw-r--r--src/test/ui/borrowck/move-in-pattern-mut.stderr4
-rw-r--r--src/test/ui/borrowck/move-in-pattern.stderr4
-rw-r--r--src/test/ui/borrowck/mut-borrow-in-loop-2.stderr8
-rw-r--r--src/test/ui/borrowck/or-patterns.stderr16
-rw-r--r--src/test/ui/codemap_tests/tab_3.stderr4
-rw-r--r--src/test/ui/drop/repeat-drop-2.stderr5
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.rs52
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout1
-rw-r--r--src/test/ui/dyn-star/dispatch-on-pin-mut.stderr11
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs5
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout2
-rw-r--r--src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr11
-rw-r--r--src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs13
-rw-r--r--src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr23
-rw-r--r--src/test/ui/dyn-star/upcast.rs3
-rw-r--r--src/test/ui/dyn-star/upcast.stderr20
-rw-r--r--src/test/ui/issues/issue-29723.stderr5
-rw-r--r--src/test/ui/issues/issue-42796.stderr4
-rw-r--r--src/test/ui/liveness/liveness-move-call-arg.stderr16
-rw-r--r--src/test/ui/liveness/liveness-move-in-loop.stderr14
-rw-r--r--src/test/ui/liveness/liveness-move-in-while.stderr12
-rw-r--r--src/test/ui/liveness/liveness-use-after-move.stderr4
-rw-r--r--src/test/ui/liveness/liveness-use-after-send.stderr9
-rw-r--r--src/test/ui/moves/borrow-closures-instead-of-move.stderr15
-rw-r--r--src/test/ui/moves/issue-46099-move-in-macro.stderr5
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.rs6
-rw-r--r--src/test/ui/moves/issue-72649-uninit-in-loop.stderr10
-rw-r--r--src/test/ui/moves/move-fn-self-receiver.stderr10
-rw-r--r--src/test/ui/moves/move-guard-same-consts.stderr12
-rw-r--r--src/test/ui/moves/move-in-guard-1.stderr12
-rw-r--r--src/test/ui/moves/move-in-guard-2.stderr12
-rw-r--r--src/test/ui/moves/moves-based-on-type-access-to-field.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr2
-rw-r--r--src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr10
-rw-r--r--src/test/ui/moves/moves-based-on-type-exprs.stderr60
-rw-r--r--src/test/ui/moves/moves-based-on-type-match-bindings.stderr4
-rw-r--r--src/test/ui/moves/moves-based-on-type-tuple.stderr5
-rw-r--r--src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr5
-rw-r--r--src/test/ui/nll/closure-access-spans.stderr10
-rw-r--r--src/test/ui/nll/issue-21232-partial-init-and-use.stderr24
-rw-r--r--src/test/ui/nll/issue-51512.stderr5
-rw-r--r--src/test/ui/nll/issue-53807.stderr2
-rw-r--r--src/test/ui/nll/match-cfg-fake-edges.stderr5
-rw-r--r--src/test/ui/nll/ref-suggestion.stderr12
-rw-r--r--src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr14
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr31
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr4
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr5
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr148
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr25
-rw-r--r--src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr20
-rw-r--r--src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr4
-rw-r--r--src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr10
-rw-r--r--src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr4
-rw-r--r--src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr6
-rw-r--r--src/test/ui/rfc-2497-if-let-chains/issue-99938.rs31
-rw-r--r--src/test/ui/suggestions/borrow-for-loop-head.stderr1
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.fixed19
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.rs19
-rw-r--r--src/test/ui/suggestions/ref-pattern-binding.stderr107
-rw-r--r--src/test/ui/track-diagnostics/track2.stderr5
-rw-r--r--src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs6
-rw-r--r--src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr11
-rw-r--r--src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr4
-rw-r--r--src/test/ui/union/union-move.mirunsafeck.stderr16
-rw-r--r--src/test/ui/union/union-move.thirunsafeck.stderr16
-rw-r--r--src/test/ui/unop-move-semantics.stderr4
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.stderr13
-rw-r--r--src/test/ui/unsized-locals/double-move.stderr8
-rw-r--r--src/test/ui/use/use-after-move-based-on-type.stderr4
-rw-r--r--src/test/ui/use/use-after-move-implicity-coerced-object.stderr8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs19
-rw-r--r--src/tools/rust-analyzer/Cargo.lock116
-rw-r--r--src/tools/rust-analyzer/crates/base-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/cfg/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/Cargo.toml3
-rw-r--r--src/tools/rust-analyzer/crates/flycheck/src/lib.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/data.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs3
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs10
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs7
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests.rs6
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/globs.rs33
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs96
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/lib.rs50
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs40
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs16
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs36
-rw-r--r--src/tools/rust-analyzer/crates/hir/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs37
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs16
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs270
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/fix_visibility.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs63
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/utils.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/completions/item_list/trait_impl.rs159
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs8
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs32
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/line_index.rs7
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs60
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs5
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs22
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/goto_definition.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs9
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs243
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/lib.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/moniker.rs20
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/references.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/signature_help.rs31
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/static_index.rs7
-rw-r--r--src/tools/rust-analyzer/crates/limit/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs89
-rw-r--r--src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs93
-rw-r--r--src/tools/rust-analyzer/crates/parser/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/paths/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs6
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/profile/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs2
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs50
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/sysroot.rs27
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/tests.rs71
-rw-r--r--src/tools/rust-analyzer/crates/project-model/src/workspace.rs84
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs10
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs22
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs115
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs83
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs22
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs6
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs19
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs60
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs111
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs8
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs64
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs60
-rw-r--r--src/tools/rust-analyzer/crates/sourcegen/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/stdx/Cargo.toml4
-rw-r--r--src/tools/rust-analyzer/crates/syntax/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/rust.ungram7
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs2
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs46
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs2
-rw-r--r--src/tools/rust-analyzer/crates/test-utils/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/text-edit/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/toolchain/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/tt/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/crates/vfs/Cargo.toml2
-rw-r--r--src/tools/rust-analyzer/docs/dev/architecture.md6
-rw-r--r--src/tools/rust-analyzer/docs/user/generated_config.adoc20
-rw-r--r--src/tools/rust-analyzer/docs/user/manual.adoc2
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json46
-rw-r--r--src/tools/rust-analyzer/editors/code/src/client.ts42
-rw-r--r--src/tools/rust-analyzer/editors/code/src/config.ts3
-rw-r--r--src/tools/rust-analyzer/editors/code/src/ctx.ts3
-rw-r--r--src/tools/rust-analyzer/editors/code/src/main.ts24
-rw-r--r--src/tools/rust-analyzer/xtask/Cargo.toml2
-rw-r--r--src/tools/rustfmt/src/expr.rs2
230 files changed, 3657 insertions, 985 deletions
diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs
index d12874e1bfd..ef28e2a855a 100644
--- a/src/librustdoc/html/render/mod.rs
+++ b/src/librustdoc/html/render/mod.rs
@@ -1071,7 +1071,7 @@ fn write_impl_section_heading(w: &mut Buffer, title: &str, id: &str) {
         w,
         "<h2 id=\"{id}\" class=\"small-section-header\">\
             {title}\
-            <a href=\"#{id}\" class=\"anchor\"></a>\
+            <a href=\"#{id}\" class=\"anchor\">§</a>\
          </h2>"
     );
 }
@@ -1536,7 +1536,7 @@ fn render_impl(
                     render_rightside(w, cx, item, containing_item, render_mode);
                     if trait_.is_some() {
                         // Anchors are only used on trait impls.
-                        write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                        write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
                     }
                     w.write_str("<h4 class=\"code-header\">");
                     render_assoc_item(
@@ -1562,7 +1562,7 @@ fn render_impl(
                 render_rightside(w, cx, item, containing_item, render_mode);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_const(
@@ -1587,7 +1587,7 @@ fn render_impl(
                 write!(w, "<section id=\"{}\" class=\"{}{}\">", id, item_type, in_trait_class);
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1613,7 +1613,7 @@ fn render_impl(
                 );
                 if trait_.is_some() {
                     // Anchors are only used on trait impls.
-                    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+                    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
                 }
                 w.write_str("<h4 class=\"code-header\">");
                 assoc_type(
@@ -1846,7 +1846,7 @@ pub(crate) fn render_impl_summary(
     };
     write!(w, "<section id=\"{}\" class=\"impl has-srclink\"{}>", id, aliases);
     render_rightside(w, cx, &i.impl_item, containing_item, RenderMode::Normal);
-    write!(w, "<a href=\"#{}\" class=\"anchor\"></a>", id);
+    write!(w, "<a href=\"#{}\" class=\"anchor\">§</a>", id);
     write!(w, "<h3 class=\"code-header\">");
 
     if let Some(use_absolute) = use_absolute {
diff --git a/src/librustdoc/html/render/print_item.rs b/src/librustdoc/html/render/print_item.rs
index a0e5309a70c..0f9b3b15c77 100644
--- a/src/librustdoc/html/render/print_item.rs
+++ b/src/librustdoc/html/render/print_item.rs
@@ -717,7 +717,7 @@ fn item_trait(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, t: &clean:
         write!(
             w,
             "<h2 id=\"{0}\" class=\"small-section-header\">\
-                {1}<a href=\"#{0}\" class=\"anchor\"></a>\
+                {1}<a href=\"#{0}\" class=\"anchor\">§</a>\
              </h2>{2}",
             id, title, extra_content
         )
@@ -1147,7 +1147,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
         write!(
             w,
             "<h2 id=\"fields\" class=\"fields small-section-header\">\
-                Fields<a href=\"#fields\" class=\"anchor\"></a>\
+                Fields<a href=\"#fields\" class=\"anchor\">§</a>\
             </h2>"
         );
         for (field, ty) in fields {
@@ -1156,7 +1156,7 @@ fn item_union(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean:
             write!(
                 w,
                 "<span id=\"{id}\" class=\"{shortty} small-section-header\">\
-                     <a href=\"#{id}\" class=\"anchor field\"></a>\
+                     <a href=\"#{id}\" class=\"anchor field\">§</a>\
                      <code>{name}: {ty}</code>\
                  </span>",
                 id = id,
@@ -1262,7 +1262,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
         write!(
             w,
             "<h2 id=\"variants\" class=\"variants small-section-header\">\
-                Variants{}<a href=\"#variants\" class=\"anchor\"></a>\
+                Variants{}<a href=\"#variants\" class=\"anchor\">§</a>\
             </h2>",
             document_non_exhaustive_header(it)
         );
@@ -1273,7 +1273,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
             write!(
                 w,
                 "<section id=\"{id}\" class=\"variant\">\
-                    <a href=\"#{id}\" class=\"anchor\"></a>",
+                    <a href=\"#{id}\" class=\"anchor\">§</a>",
                 id = id,
             );
             render_stability_since_raw_with_extra(
@@ -1325,7 +1325,7 @@ fn item_enum(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, e: &clean::
                                 w,
                                 "<div class=\"sub-variant-field\">\
                                  <span id=\"{id}\" class=\"small-section-header\">\
-                                     <a href=\"#{id}\" class=\"anchor field\"></a>\
+                                     <a href=\"#{id}\" class=\"anchor field\">§</a>\
                                      <code>{f}:&nbsp;{t}</code>\
                                  </span>",
                                 id = id,
@@ -1477,7 +1477,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
             write!(
                 w,
                 "<h2 id=\"fields\" class=\"fields small-section-header\">\
-                     {}{}<a href=\"#fields\" class=\"anchor\"></a>\
+                     {}{}<a href=\"#fields\" class=\"anchor\">§</a>\
                  </h2>",
                 if s.ctor_kind.is_none() { "Fields" } else { "Tuple Fields" },
                 document_non_exhaustive_header(it)
@@ -1490,7 +1490,7 @@ fn item_struct(w: &mut Buffer, cx: &mut Context<'_>, it: &clean::Item, s: &clean
                 write!(
                     w,
                     "<span id=\"{id}\" class=\"{item_type} small-section-header\">\
-                         <a href=\"#{id}\" class=\"anchor field\"></a>\
+                         <a href=\"#{id}\" class=\"anchor field\">§</a>\
                          <code>{name}: {ty}</code>\
                      </span>",
                     item_type = ItemType::StructField,
@@ -1908,7 +1908,7 @@ fn document_type_layout(w: &mut Buffer, cx: &Context<'_>, ty_def_id: DefId) {
     writeln!(
         w,
         "<h2 id=\"layout\" class=\"small-section-header\"> \
-        Layout<a href=\"#layout\" class=\"anchor\"></a></h2>"
+        Layout<a href=\"#layout\" class=\"anchor\">§</a></h2>"
     );
     writeln!(w, "<div class=\"docblock\">");
 
diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css
index 63530b924c2..e0a4f2364b6 100644
--- a/src/librustdoc/html/static/css/rustdoc.css
+++ b/src/librustdoc/html/static/css/rustdoc.css
@@ -730,9 +730,6 @@ a {
 h2.small-section-header > .anchor {
 	padding-right: 6px;
 }
-.anchor::before {
-	content: '§';
-}
 
 .main-heading a:hover,
 .example-wrap > pre.rust a:hover,
diff --git a/src/librustdoc/html/templates/page.html b/src/librustdoc/html/templates/page.html
index df13e597f1f..aa3bf827db4 100644
--- a/src/librustdoc/html/templates/page.html
+++ b/src/librustdoc/html/templates/page.html
@@ -115,6 +115,7 @@
                     <input {# -#}
                         class="search-input" {# -#}
                         name="search" {# -#}
+                        aria-label="Run search in the documentation" {# -#}
                         autocomplete="off" {# -#}
                         spellcheck="false" {# -#}
                         placeholder="Click or press ‘S’ to search, ‘?’ for more options…" {# -#}
diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs
new file mode 100644
index 00000000000..7f729429581
--- /dev/null
+++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.rs
@@ -0,0 +1,106 @@
+// compile-flags: -Zdrop-tracking
+// incremental
+// edition: 2021
+
+use std::future::*;
+use std::marker::PhantomData;
+use std::pin::Pin;
+use std::task::*;
+
+fn send<T: Send>(_: T) {}
+
+pub trait Stream {
+    type Item;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>;
+}
+
+struct Empty<T>(PhantomData<fn() -> T>);
+
+impl<T> Stream for Empty<T> {
+    type Item = T;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+pub trait FnOnce1<A> {
+    type Output;
+    fn call_once(self, arg: A) -> Self::Output;
+}
+
+impl<T, A, R> FnOnce1<A> for T
+where
+    T: FnOnce(A) -> R,
+{
+    type Output = R;
+    fn call_once(self, arg: A) -> R {
+        self(arg)
+    }
+}
+
+pub trait FnMut1<A>: FnOnce1<A> {
+    fn call_mut(&mut self, arg: A) -> Self::Output;
+}
+
+impl<T, A, R> FnMut1<A> for T
+where
+    T: FnMut(A) -> R,
+{
+    fn call_mut(&mut self, arg: A) -> R {
+        self(arg)
+    }
+}
+
+struct Map<St, F>(St, F);
+
+impl<St, F> Stream for Map<St, F>
+where
+    St: Stream,
+    F: FnMut1<St::Item>,
+{
+    type Item = F::Output;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+struct FuturesOrdered<T: Future>(PhantomData<fn() -> T::Output>);
+
+pub struct Buffered<St: Stream>(St, FuturesOrdered<St::Item>, usize)
+where
+    St::Item: Future;
+
+impl<St> Stream for Buffered<St>
+where
+    St: Stream,
+    St::Item: Future,
+{
+    type Item = <St::Item as Future>::Output;
+
+    fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+        todo!()
+    }
+}
+
+struct Next<'a, T: ?Sized>(&'a T);
+
+impl<St: ?Sized + Stream + Unpin> Future for Next<'_, St> {
+    type Output = Option<St::Item>;
+
+    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
+        todo!()
+    }
+}
+
+fn main() {
+    send(async {
+        //~^ ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        //~| ERROR implementation of `FnOnce` is not general enough
+        Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+    });
+}
diff --git a/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
new file mode 100644
index 00000000000..aa9a22e9e72
--- /dev/null
+++ b/src/test/ui/async-await/drop-tracking-unresolved-typeck-results.stderr
@@ -0,0 +1,62 @@
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: implementation of `FnOnce` is not general enough
+  --> $DIR/drop-tracking-unresolved-typeck-results.rs:99:5
+   |
+LL | /     send(async {
+LL | |
+LL | |
+LL | |
+LL | |
+LL | |         Next(&Buffered(Map(Empty(PhantomData), ready::<&()>), FuturesOrdered(PhantomData), 0)).await
+LL | |     });
+   | |______^ implementation of `FnOnce` is not general enough
+   |
+   = note: `fn(&'0 ()) -> std::future::Ready<&'0 ()> {std::future::ready::<&'0 ()>}` must implement `FnOnce<(&'1 (),)>`, for any two lifetimes `'0` and `'1`...
+   = note: ...but it actually implements `FnOnce<(&(),)>`
+
+error: aborting due to 4 previous errors
+
diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr
index 489bf70d920..0ec2ae8839e 100644
--- a/src/test/ui/binding/issue-53114-borrow-checks.stderr
+++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr
@@ -17,6 +17,10 @@ LL |     match mm { (_, _y) => { } }
    |           ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     match mm { (ref _x, _) => { } }
+   |                 +++
 
 error[E0382]: use of partially moved value: `mm`
   --> $DIR/issue-53114-borrow-checks.rs:29:11
@@ -28,6 +32,10 @@ LL |     match mm { (_, _) => { } }
    |           ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     match mm { (_, ref _y) => { } }
+   |                    +++
 
 error[E0382]: use of moved value: `m`
   --> $DIR/issue-53114-borrow-checks.rs:36:16
@@ -48,6 +56,10 @@ LL |     if let (_, _y) = mm { }
    |                      ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let (ref _x, _) = mm { }
+   |             +++
 
 error[E0382]: use of partially moved value: `mm`
   --> $DIR/issue-53114-borrow-checks.rs:43:21
@@ -59,6 +71,10 @@ LL |     if let (_, _) = mm { }
    |                     ^^ value used here after partial move
    |
    = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     if let (_, ref _y) = mm { }
+   |                +++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/binop/binop-move-semantics.stderr b/src/test/ui/binop/binop-move-semantics.stderr
index 695b01d5ee3..994eaf9d8c7 100644
--- a/src/test/ui/binop/binop-move-semantics.stderr
+++ b/src/test/ui/binop/binop-move-semantics.stderr
@@ -32,6 +32,10 @@ LL |     +
 LL |     x.clone();
    |     ^^^^^^^^^ value borrowed here after move
    |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     x.clone()
+   |      ++++++++
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Add<Output=()> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
index 1fd1eb12851..50eee1049db 100644
--- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
+++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr
@@ -27,6 +27,11 @@ LL |         a @ [.., _] => (),
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., _] => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as immutable because it is also borrowed as mutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:28:5
@@ -71,13 +76,15 @@ LL | fn bindings_after_at_or_patterns_move(x: Option<Test>) {
    |                                       - move occurs because `x` has type `Option<Test>`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         foo @ Some(Test::Foo | Test::Bar) => (),
-   |         ---
-   |         |
-   |         value moved here
-   |         value moved here
+   |         --- value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref foo @ Some(Test::Foo | Test::Bar) => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:86:5
@@ -122,13 +129,15 @@ LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option<Test>; 4])
    |                                                       - move occurs because `x` has type `[Option<Test>; 4]`, which does not implement the `Copy` trait
 LL |     match x {
 LL |         a @ [.., Some(Test::Foo | Test::Bar)] => (),
-   |         -
-   |         |
-   |         value moved here
-   |         value moved here
+   |         - value moved here
 ...
 LL |     &x;
    |     ^^ value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ [.., Some(Test::Foo | Test::Bar)] => (),
+   |         +++
 
 error[E0502]: cannot borrow `x` as mutable because it is also borrowed as immutable
   --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:144:5
diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
index 17b93106615..d2e9497d079 100644
--- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
+++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr
@@ -7,6 +7,18 @@ LL |     consume(b);
    |             - value moved here
 LL |     consume(b);
    |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-unsize-vec.rs:3:15
+   |
+LL | fn consume(_: Box<[i32]>) {
+   |    -------    ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     consume(b.clone());
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
index 4e20bbf1757..ed7e883ca63 100644
--- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
+++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr
@@ -7,6 +7,14 @@ LL |     consume(b);
    |             - value moved here
 LL |     consume(b);
    |             ^ value used here after move
+   |
+note: consider changing this parameter type in function `consume` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrowck-consume-upcast-box.rs:5:15
+   |
+LL | fn consume(_: Box<dyn Foo>) {
+   |    -------    ^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
index cd0d2fee942..eaf4bb38bc5 100644
--- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
+++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr
@@ -9,6 +9,11 @@ LL |         Some(_) if { drop(my_str); false } => {}
 LL |         Some(_) => {}
 LL |         None => { foo(my_str); }
    |                       ^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(my_str.clone()); false } => {}
+   |                                 ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
index 0dd720ff6ce..e1b99162088 100644
--- a/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
+++ b/src/test/ui/borrowck/borrowck-loan-in-overloaded-op.stderr
@@ -7,6 +7,11 @@ LL |     let _y = {x} + x.clone(); // the `{x}` forces a move to occur
    |               -    ^^^^^^^^^ value borrowed here after move
    |               |
    |               value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = {x.clone()} + x.clone(); // the `{x}` forces a move to occur
+   |                ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
index 346b82a2666..67b00c1dd90 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr
@@ -8,6 +8,10 @@ LL |         [.., _y] => {}
    |              ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-match.rs:23:14
@@ -19,6 +23,10 @@ LL |         [.., _y] => {}
    |              ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:33:15
@@ -30,6 +38,10 @@ LL |         [.., (_y, _)] => {}
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:44:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:55:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:66:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:77:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:89:11
@@ -85,6 +113,10 @@ LL |         [(_x, _), _, _] => {}
    |           ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-match.rs:99:15
@@ -96,6 +128,10 @@ LL |         [.., (_x, _)] => {}
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-match.rs:110:11
@@ -107,6 +143,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
index 6c6a25c251e..47429ea3eeb 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr
@@ -8,6 +8,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11
@@ -19,6 +23,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11
@@ -30,6 +38,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11
@@ -85,6 +113,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11
@@ -96,6 +128,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
index 77702e145df..bfab13d42d2 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr
@@ -8,6 +8,10 @@ LL |         [.., ref _y] => {}
    |              ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14
@@ -19,6 +23,10 @@ LL |         [.., ref _y] => {}
    |              ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: borrow of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15
@@ -30,6 +38,10 @@ LL |         [.., (ref _y, _)] => {}
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11
@@ -85,6 +113,10 @@ LL |         [(ref _x, _), _, _] => {}
    |           ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _, _] => {}
+   |          +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15
@@ -96,6 +128,10 @@ LL |         [.., (ref _x, _)] => {}
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _y @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11
@@ -107,6 +143,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5
@@ -118,6 +158,10 @@ LL |     a[2] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5
@@ -129,6 +173,10 @@ LL |     a[2].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5
@@ -140,6 +188,10 @@ LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5
@@ -151,6 +203,10 @@ LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x @ ..] => {}
+   |                +++
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
index 6cc2c2f7a98..8412c24fe61 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr
@@ -8,6 +8,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, ref _x] => {}
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11
@@ -19,6 +23,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, _, (ref _x, _)] => {}
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11
@@ -30,6 +38,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _x, _, _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11
@@ -41,6 +53,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., ref _x] => {}
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11
@@ -52,6 +68,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [(ref _x, _), _, _] => {}
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11
@@ -63,6 +83,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [.., (ref _x, _)] => {}
+   |               +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11
@@ -74,6 +98,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [_, ref _y @ ..] => {}
+   |             +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11
@@ -85,6 +113,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref _y @ .., _] => {}
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11
@@ -96,6 +128,10 @@ LL |     match a {
    |           ^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         [ref x @ .., _, _] => {}
+   |          +++
 
 error: aborting due to 9 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
index 9add7553afa..e2aeaafc63c 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr
@@ -7,6 +7,10 @@ LL |     let [.., ref _y] = a;
    |              ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:16:14
@@ -17,6 +21,10 @@ LL |     let [.., ref _y] = a;
    |              ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: borrow of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array-use.rs:22:15
@@ -27,6 +35,10 @@ LL |     let [.., (ref _y, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:30:10
@@ -37,6 +49,10 @@ LL |     let [ref _y @ .., _, _] = a;
    |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:36:16
@@ -47,6 +63,10 @@ LL |     let [_, _, ref _y @ ..] = a;
    |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:42:10
@@ -57,6 +77,10 @@ LL |     let [ref _y @ .., _, _] = a;
    |          ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:48:16
@@ -67,6 +91,10 @@ LL |     let [_, _, ref _y @ ..] = a;
    |                ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:54:11
@@ -77,6 +105,10 @@ LL |     let [(ref _x, _), _, _] = a;
    |           ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
 
 error[E0382]: borrow of moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array-use.rs:60:15
@@ -87,6 +119,10 @@ LL |     let [.., (ref _x, _)] = a;
    |               ^^^^^^ value borrowed here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
 
 error[E0382]: borrow of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:68:13
@@ -97,6 +133,10 @@ LL |     let [_, ref _y @ ..] = a;
    |             ^^^^^^ value borrowed here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:76:5
@@ -107,6 +147,10 @@ LL |     a[2] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:82:5
@@ -117,6 +161,10 @@ LL |     a[2].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:88:5
@@ -127,6 +175,10 @@ LL |     a[0] = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array-use.rs:94:5
@@ -137,6 +189,10 @@ LL |     a[0].1 = Default::default();
    |     ^^^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x @ ..] = a;
+   |                +++
 
 error: aborting due to 14 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
index 363effcfe53..dd456681f57 100644
--- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
+++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr
@@ -7,6 +7,10 @@ LL |     let [.., _y] = a;
    |              ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _x] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a[..]`
   --> $DIR/borrowck-move-out-from-array.rs:16:14
@@ -17,6 +21,10 @@ LL |     let [.., _y] = a;
    |              ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:22:15
@@ -27,6 +35,10 @@ LL |     let [.., (_y, _)] = a;
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, (ref _x, _)] = a;
+   |                 +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:30:10
@@ -37,6 +49,10 @@ LL |     let [_y @ .., _, _] = a;
    |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _x, _, _] = a;
+   |          +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:36:16
@@ -47,6 +63,10 @@ LL |     let [_, _, _y @ ..] = a;
    |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., ref _x] = a;
+   |              +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:42:10
@@ -57,6 +77,10 @@ LL |     let [_y @ .., _, _] = a;
    |          ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [(ref _x, _), _, _] = a;
+   |           +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:48:16
@@ -67,6 +91,10 @@ LL |     let [_, _, _y @ ..] = a;
    |                ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [.., (ref _x, _)] = a;
+   |               +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:54:11
@@ -77,6 +105,10 @@ LL |     let [(_x, _), _, _] = a;
    |           ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref _y @ .., _, _] = a;
+   |          +++
 
 error[E0382]: use of moved value: `a[..].0`
   --> $DIR/borrowck-move-out-from-array.rs:60:15
@@ -87,6 +119,10 @@ LL |     let [.., (_x, _)] = a;
    |               ^^ value used here after move
    |
    = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [_, _, ref _y @ ..] = a;
+   |                +++
 
 error[E0382]: use of partially moved value: `a`
   --> $DIR/borrowck-move-out-from-array.rs:68:13
@@ -97,6 +133,10 @@ LL |     let [_, _y @ ..] = a;
    |             ^^ value used here after partial move
    |
    = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let [ref x @ .., _] = a;
+   |          +++
 
 error: aborting due to 10 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr
index 86d2955e236..f94cbc30db4 100644
--- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr
+++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr
@@ -40,6 +40,11 @@ LL |     thread::spawn(move|| {
 ...
 LL |         drop(x1);
    |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x1.clone());
+   |            ++++++++
 
 error[E0382]: use of moved value: `x2`
   --> $DIR/borrowck-multiple-captures.rs:27:19
@@ -53,6 +58,11 @@ LL |     thread::spawn(move|| {
 ...
 LL |         drop(x2);
    |              -- use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x2.clone());
+   |            ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/borrowck-multiple-captures.rs:41:14
@@ -100,6 +110,11 @@ LL |     thread::spawn(move|| {
 LL |
 LL |         drop(x);
    |              - use occurs due to use in closure
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
 
 error: aborting due to 8 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
index e01c26adcfc..fb0e274c291 100644
--- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
+++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr
@@ -33,6 +33,11 @@ LL |     println!("{}", f[s]);
 ...
 LL |     f[s] = 10;
    |       ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     println!("{}", f[s.clone()]);
+   |                       ++++++++
 
 error: aborting due to 3 previous errors
 
diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr
index 22253cd96f1..f785900d53f 100644
--- a/src/test/ui/borrowck/borrowck-reinit.stderr
+++ b/src/test/ui/borrowck/borrowck-reinit.stderr
@@ -8,6 +8,11 @@ LL |     drop(x);
    |          - value moved here
 LL |     let _ = (1,x);
    |                ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     drop(x.clone());
+   |           ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
index d33115988a9..ad898fcabd9 100644
--- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
+++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr
@@ -8,6 +8,11 @@ LL |         Some(_) if { drop(a); false } => None,
    |                           - value moved here
 LL |         x => x,
    |         ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         Some(_) if { drop(a.clone()); false } => None,
+   |                            ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr
index b20cc6d8cf5..716cc9d0c8b 100644
--- a/src/test/ui/borrowck/issue-41962.stderr
+++ b/src/test/ui/borrowck/issue-41962.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `maybe.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref thing) = maybe {
    |                     +++
diff --git a/src/test/ui/borrowck/issue-83760.stderr b/src/test/ui/borrowck/issue-83760.stderr
index beeda5685dc..2552fff860c 100644
--- a/src/test/ui/borrowck/issue-83760.stderr
+++ b/src/test/ui/borrowck/issue-83760.stderr
@@ -8,6 +8,10 @@ LL |             val = None;
    |             ---------- this reinitialization might get skipped
    |
    = note: move occurs because value has type `Struct`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     while let Some(ref foo) = val {
+   |                    +++
 
 error[E0382]: use of moved value: `foo`
   --> $DIR/issue-83760.rs:21:14
diff --git a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
index c6931ba7257..55948afca73 100644
--- a/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
+++ b/src/test/ui/borrowck/move-in-pattern-mut-in-loop.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(mut _x) = opt {}
    |                     ^^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `&mut i32`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `opt.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref mut _x) = opt {}
    |                     +++
diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr
index 2bf34b32176..dd3471e2c8b 100644
--- a/src/test/ui/borrowck/move-in-pattern-mut.stderr
+++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr
@@ -8,7 +8,7 @@ LL |     foo(s);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `s.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     if let Some(ref mut x) = s {
    |                 +++
@@ -23,7 +23,7 @@ LL |     bar(e);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `e.s`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     let E::V { s: ref mut x } = e;
    |                   +++
diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr
index 6b84c0032cd..250acbe5928 100644
--- a/src/test/ui/borrowck/move-in-pattern.stderr
+++ b/src/test/ui/borrowck/move-in-pattern.stderr
@@ -8,7 +8,7 @@ LL |     foo(s);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `s.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     if let Some(ref x) = s {
    |                 +++
@@ -23,7 +23,7 @@ LL |     bar(e);
    |         ^ value used here after partial move
    |
    = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `e.s`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |     let E::V { s: ref x } = e;
    |                   +++
diff --git a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
index 8b05b238822..74e7067c9af 100644
--- a/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
+++ b/src/test/ui/borrowck/mut-borrow-in-loop-2.stderr
@@ -4,9 +4,17 @@ error[E0382]: use of moved value: `value`
 LL | fn this_does_not<'a, R>(value: &'a mut Events<R>) {
    |                         ----- move occurs because `value` has type `&mut Events<R>`, which does not implement the `Copy` trait
 LL |     for _ in 0..3 {
+   |     ------------- inside of this loop
 LL |         Other::handle(value);
    |                       ^^^^^ value moved here, in previous iteration of loop
    |
+note: consider changing this parameter type in function `handle` to borrow instead if owning the value isn't necessary
+  --> $DIR/mut-borrow-in-loop-2.rs:9:22
+   |
+LL |     fn handle(value: T) -> Self;
+   |        ------        ^ this parameter takes ownership of the value
+   |        |
+   |        in this function
 help: consider creating a fresh reborrow of `value` here
    |
 LL |         Other::handle(&mut *value);
diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr
index dd5797c3f79..9501798bb06 100644
--- a/src/test/ui/borrowck/or-patterns.stderr
+++ b/src/test/ui/borrowck/or-patterns.stderr
@@ -8,6 +8,10 @@ LL |     &x.0 .0;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((ref y, _) | (_, y),) => (),
+   |           +++
 
 error[E0382]: borrow of moved value: `x.0.1`
   --> $DIR/or-patterns.rs:10:5
@@ -19,6 +23,10 @@ LL |     &x.0 .1;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ((y, _) | (_, ref y),) => (),
+   |                       +++
 
 error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
   --> $DIR/or-patterns.rs:18:5
@@ -77,6 +85,10 @@ LL |     &x.0 .0;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((ref y, _) | (_, y),) = x;
+   |           +++
 
 error[E0382]: borrow of moved value: `x.0.1`
   --> $DIR/or-patterns.rs:40:5
@@ -88,6 +100,10 @@ LL |     &x.0 .1;
    |     ^^^^^^^ value borrowed here after move
    |
    = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ((y, _) | (_, ref y),) = x;
+   |                       +++
 
 error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable
   --> $DIR/or-patterns.rs:46:5
diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr
index 9072cc925ff..080f6c39449 100644
--- a/src/test/ui/codemap_tests/tab_3.stderr
+++ b/src/test/ui/codemap_tests/tab_3.stderr
@@ -15,6 +15,10 @@ note: this function takes ownership of the receiver `self`, which moves `some_ve
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     some_vec.clone().into_iter();
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/drop/repeat-drop-2.stderr b/src/test/ui/drop/repeat-drop-2.stderr
index 7357551c4a7..f030228f71a 100644
--- a/src/test/ui/drop/repeat-drop-2.stderr
+++ b/src/test/ui/drop/repeat-drop-2.stderr
@@ -7,6 +7,11 @@ LL |     let _bar = foo;
    |                --- value moved here
 LL |     let _baz = [foo; 0];
    |                 ^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _bar = foo.clone();
+   |                   ++++++++
 
 error[E0493]: destructor of `String` cannot be evaluated at compile-time
   --> $DIR/repeat-drop-2.rs:7:25
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.rs b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs
new file mode 100644
index 00000000000..5774c8b2a67
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.rs
@@ -0,0 +1,52 @@
+// run-pass
+// edition:2021
+// check-run-results
+
+#![feature(dyn_star)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+
+use std::future::Future;
+
+async fn foo(f: dyn* Future<Output = i32>) {
+    println!("value: {}", f.await);
+}
+
+async fn async_main() {
+    foo(Box::pin(async { 1 })).await
+}
+
+// ------------------------------------------------------------------------- //
+// Implementation Details Below...
+
+use std::pin::Pin;
+use std::task::*;
+
+pub fn noop_waker() -> Waker {
+    let raw = RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE);
+
+    // SAFETY: the contracts for RawWaker and RawWakerVTable are upheld
+    unsafe { Waker::from_raw(raw) }
+}
+
+const NOOP_WAKER_VTABLE: RawWakerVTable = RawWakerVTable::new(noop_clone, noop, noop, noop);
+
+unsafe fn noop_clone(_p: *const ()) -> RawWaker {
+    RawWaker::new(std::ptr::null(), &NOOP_WAKER_VTABLE)
+}
+
+unsafe fn noop(_p: *const ()) {}
+
+fn main() {
+    let mut fut = async_main();
+
+    // Poll loop, just to test the future...
+    let waker = noop_waker();
+    let ctx = &mut Context::from_waker(&waker);
+
+    loop {
+        match unsafe { Pin::new_unchecked(&mut fut).poll(ctx) } {
+            Poll::Pending => {}
+            Poll::Ready(()) => break,
+        }
+    }
+}
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
new file mode 100644
index 00000000000..96c5ca6985f
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.run.stdout
@@ -0,0 +1 @@
+value: 1
diff --git a/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
new file mode 100644
index 00000000000..fdf74aa7efe
--- /dev/null
+++ b/src/test/ui/dyn-star/dispatch-on-pin-mut.stderr
@@ -0,0 +1,11 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dispatch-on-pin-mut.rs:5:12
+   |
+LL | #![feature(dyn_star)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
index b4ff8a22286..c12b16f1605 100644
--- a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.rs
@@ -1,7 +1,8 @@
-// check-pass
+// run-pass
+// check-run-results
 
 #![feature(dyn_star)]
-#![allow(incomplete_features)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
 
 trait AddOne {
     fn add1(&mut self) -> usize;
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout
new file mode 100644
index 00000000000..b4db3ed707d
--- /dev/null
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.run.stdout
@@ -0,0 +1,2 @@
+43
+44
diff --git a/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
new file mode 100644
index 00000000000..933c133831a
--- /dev/null
+++ b/src/test/ui/dyn-star/dont-unsize-coerce-dyn-star.stderr
@@ -0,0 +1,11 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/dont-unsize-coerce-dyn-star.rs:4:12
+   |
+LL | #![feature(dyn_star)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+warning: 1 warning emitted
+
diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
new file mode 100644
index 00000000000..a4eb669e321
--- /dev/null
+++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.rs
@@ -0,0 +1,13 @@
+#![feature(dyn_star, trait_upcasting)]
+//~^ WARN the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+
+trait A: B {}
+trait B {}
+impl A for usize {}
+impl B for usize {}
+
+fn main() {
+    let x: Box<dyn* A> = Box::new(1usize as dyn* A);
+    let y: Box<dyn* B> = x;
+    //~^ ERROR mismatched types
+}
diff --git a/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
new file mode 100644
index 00000000000..2fc751b3b4a
--- /dev/null
+++ b/src/test/ui/dyn-star/no-unsize-coerce-dyn-trait.stderr
@@ -0,0 +1,23 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/no-unsize-coerce-dyn-trait.rs:1:12
+   |
+LL | #![feature(dyn_star, trait_upcasting)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0308]: mismatched types
+  --> $DIR/no-unsize-coerce-dyn-trait.rs:11:26
+   |
+LL |     let y: Box<dyn* B> = x;
+   |            -----------   ^ expected trait `B`, found trait `A`
+   |            |
+   |            expected due to this
+   |
+   = note: expected struct `Box<dyn* B>`
+              found struct `Box<dyn* A>`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/src/test/ui/dyn-star/upcast.rs b/src/test/ui/dyn-star/upcast.rs
index cee76ada7df..c667ac143a3 100644
--- a/src/test/ui/dyn-star/upcast.rs
+++ b/src/test/ui/dyn-star/upcast.rs
@@ -1,7 +1,6 @@
-// run-pass
+// known-bug: #104800
 
 #![feature(dyn_star, trait_upcasting)]
-#![allow(incomplete_features)]
 
 trait Foo: Bar {
     fn hello(&self);
diff --git a/src/test/ui/dyn-star/upcast.stderr b/src/test/ui/dyn-star/upcast.stderr
new file mode 100644
index 00000000000..6a95f7754e6
--- /dev/null
+++ b/src/test/ui/dyn-star/upcast.stderr
@@ -0,0 +1,20 @@
+warning: the feature `dyn_star` is incomplete and may not be safe to use and/or cause compiler crashes
+  --> $DIR/upcast.rs:3:12
+   |
+LL | #![feature(dyn_star, trait_upcasting)]
+   |            ^^^^^^^^
+   |
+   = note: see issue #91611 <https://github.com/rust-lang/rust/issues/91611> for more information
+   = note: `#[warn(incomplete_features)]` on by default
+
+error[E0277]: `dyn* Foo` needs to be a pointer-sized type
+  --> $DIR/upcast.rs:30:23
+   |
+LL |     let w: dyn* Bar = w;
+   |                       ^ `dyn* Foo` needs to be a pointer-sized type
+   |
+   = help: the trait `PointerSized` is not implemented for `dyn* Foo`
+
+error: aborting due to previous error; 1 warning emitted
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr
index e39ddfc81c9..92ee5cf22b7 100644
--- a/src/test/ui/issues/issue-29723.stderr
+++ b/src/test/ui/issues/issue-29723.stderr
@@ -9,6 +9,11 @@ LL |         0 if { drop(s); false } => String::from("oops"),
 ...
 LL |             s
    |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         0 if { drop(s.clone()); false } => String::from("oops"),
+   |                      ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr
index f3e0e7b20a1..f2971df5db2 100644
--- a/src/test/ui/issues/issue-42796.stderr
+++ b/src/test/ui/issues/issue-42796.stderr
@@ -10,6 +10,10 @@ LL |     println!("{}", s);
    |                    ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut s_copy = s.clone();
+   |                       ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr
index 7c0e916eddc..d14cd6cb4e0 100644
--- a/src/test/ui/liveness/liveness-move-call-arg.stderr
+++ b/src/test/ui/liveness/liveness-move-call-arg.stderr
@@ -3,9 +3,23 @@ error[E0382]: use of moved value: `x`
    |
 LL |     let x: Box<isize> = Box::new(25);
    |         - move occurs because `x` has type `Box<isize>`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         take(x);
    |              ^ value moved here, in previous iteration of loop
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/liveness-move-call-arg.rs:1:13
+   |
+LL | fn take(_x: Box<isize>) {}
+   |    ----     ^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         take(x.clone());
+   |               ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr
index 832d4f8fa03..a060914f178 100644
--- a/src/test/ui/liveness/liveness-move-in-loop.stderr
+++ b/src/test/ui/liveness/liveness-move-in-loop.stderr
@@ -4,8 +4,22 @@ error[E0382]: use of moved value: `y`
 LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
+LL |         println!("{}", y);
+LL |         loop {
+   |         ---- inside of this loop
+LL |             loop {
+   |             ---- inside of this loop
+LL |                 loop {
+   |                 ---- inside of this loop
 LL |                     x = y;
    |                         ^ value moved here, in previous iteration of loop
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |                     x = y.clone();
+   |                          ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr
index b04a05fe409..4dff7447dd7 100644
--- a/src/test/ui/liveness/liveness-move-in-while.stderr
+++ b/src/test/ui/liveness/liveness-move-in-while.stderr
@@ -24,12 +24,22 @@ error[E0382]: borrow of moved value: `y`
 LL |     let y: Box<isize> = 42.into();
    |         - move occurs because `y` has type `Box<isize>`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
 LL |         println!("{}", y);
    |                        ^ value borrowed here after move
 LL |         while true { while true { while true { x = y; x.clone(); } } }
-   |                                                    - value moved here, in previous iteration of loop
+   |         ----------   ----------   ----------       - value moved here, in previous iteration of loop
+   |         |            |            |
+   |         |            |            inside of this loop
+   |         |            inside of this loop
+   |         inside of this loop
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         while true { while true { while true { x = y.clone(); x.clone(); } } }
+   |                                                     ++++++++
 
 error: aborting due to previous error; 3 warnings emitted
 
diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr
index 218b93c8e4f..3accba197a1 100644
--- a/src/test/ui/liveness/liveness-use-after-move.stderr
+++ b/src/test/ui/liveness/liveness-use-after-move.stderr
@@ -10,6 +10,10 @@ LL |     println!("{}", *x);
    |                    ^^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = x.clone();
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr
index 8edc0463fe5..65d55ca8f70 100644
--- a/src/test/ui/liveness/liveness-use-after-send.stderr
+++ b/src/test/ui/liveness/liveness-use-after-send.stderr
@@ -8,7 +8,16 @@ LL |     send(ch, message);
 LL |     println!("{}", message);
    |                    ^^^^^^^ value borrowed here after move
    |
+note: consider changing this parameter type in function `send` to borrow instead if owning the value isn't necessary
+  --> $DIR/liveness-use-after-send.rs:3:54
+   |
+LL | fn send<T:Send + std::fmt::Debug>(ch: Chan<T>, data: T) {
+   |    ---- in this function                             ^ this parameter takes ownership of the value
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     send(ch, message.clone());
+   |                     ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/borrow-closures-instead-of-move.stderr b/src/test/ui/moves/borrow-closures-instead-of-move.stderr
index 3146b695900..9a84ddef7e6 100644
--- a/src/test/ui/moves/borrow-closures-instead-of-move.stderr
+++ b/src/test/ui/moves/borrow-closures-instead-of-move.stderr
@@ -4,9 +4,17 @@ error[E0382]: use of moved value: `f`
 LL | fn takes_fn(f: impl Fn()) {
    |             - move occurs because `f` has type `impl Fn()`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         takes_fnonce(f);
    |                      ^ value moved here, in previous iteration of loop
    |
+note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-closures-instead-of-move.rs:34:20
+   |
+LL | fn takes_fnonce(_: impl FnOnce()) {}
+   |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 help: consider borrowing `f`
    |
 LL |         takes_fnonce(&f);
@@ -24,6 +32,13 @@ LL |         takes_fnonce(m);
 LL |     takes_fnonce(m);
    |                  ^ value used here after move
    |
+note: consider changing this parameter type in function `takes_fnonce` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-closures-instead-of-move.rs:34:20
+   |
+LL | fn takes_fnonce(_: impl FnOnce()) {}
+   |    ------------    ^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 help: consider mutably borrowing `m`
    |
 LL |         takes_fnonce(&mut m);
diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr
index baa87e3e9fd..94bc9e6f454 100644
--- a/src/test/ui/moves/issue-46099-move-in-macro.stderr
+++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr
@@ -5,6 +5,11 @@ LL |     let b = Box::new(true);
    |         - move occurs because `b` has type `Box<bool>`, which does not implement the `Copy` trait
 LL |     test!({b});
    |            ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     test!({b.clone()});
+   |             ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.rs b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
index d76b69ecdc8..56c225bab8c 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.rs
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.rs
@@ -25,7 +25,7 @@ fn moved_here_1() {
 fn moved_here_2() {
     let value = NonCopy{};
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used = value;
         //~^ NOTE value moved here
         loop {
@@ -38,7 +38,7 @@ fn moved_here_2() {
 fn moved_loop_1() {
     let value = NonCopy{};
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
     }
@@ -49,7 +49,7 @@ fn moved_loop_2() {
     //~^ NOTE move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
     let _used = value;
     value = NonCopy{};
-    loop {
+    loop { //~ NOTE inside of this loop
         let _used2 = value; //~ ERROR use of moved value: `value`
         //~^ NOTE value moved here, in previous iteration of loop
     }
diff --git a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
index 974994223a3..7e119fe8cda 100644
--- a/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
+++ b/src/test/ui/moves/issue-72649-uninit-in-loop.stderr
@@ -15,7 +15,9 @@ error[E0382]: use of moved value: `value`
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used = value;
    |                     ----- value moved here
 ...
@@ -27,7 +29,9 @@ error[E0382]: use of moved value: `value`
    |
 LL |     let value = NonCopy{};
    |         ----- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
-...
+LL |
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used = value;
    |                     ^^^^^ value moved here, in previous iteration of loop
 
@@ -37,6 +41,8 @@ error[E0382]: use of moved value: `value`
 LL |     let mut value = NonCopy{};
    |         --------- move occurs because `value` has type `NonCopy`, which does not implement the `Copy` trait
 ...
+LL |     loop {
+   |     ---- inside of this loop
 LL |         let _used2 = value;
    |                      ^^^^^ value moved here, in previous iteration of loop
 
diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr
index 3a686121a92..c13dc58826e 100644
--- a/src/test/ui/moves/move-fn-self-receiver.stderr
+++ b/src/test/ui/moves/move-fn-self-receiver.stderr
@@ -96,6 +96,10 @@ note: this function takes ownership of the receiver `self`, which moves `rc_foo`
    |
 LL |     fn use_rc_self(self: Rc<Self>) {}
    |                    ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     rc_foo.clone().use_rc_self();
+   |           ++++++++
 
 error[E0382]: use of moved value: `foo_add`
   --> $DIR/move-fn-self-receiver.rs:59:5
@@ -137,6 +141,11 @@ LL |     for _val in explicit_into_iter.into_iter() {}
    |                                    ----------- `explicit_into_iter` moved due to this method call
 LL |     explicit_into_iter;
    |     ^^^^^^^^^^^^^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     for _val in explicit_into_iter.clone().into_iter() {}
+   |                                   ++++++++
 
 error[E0382]: use of moved value: `container`
   --> $DIR/move-fn-self-receiver.rs:71:5
@@ -160,6 +169,7 @@ error[E0382]: use of moved value: `foo2`
 LL |     let foo2 = Foo;
    |         ---- move occurs because `foo2` has type `Foo`, which does not implement the `Copy` trait
 LL |     loop {
+   |     ---- inside of this loop
 LL |         foo2.use_self();
    |         ^^^^ ---------- `foo2` moved due to this method call, in previous iteration of loop
 
diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr
index 2048fefefa3..86e5f65248b 100644
--- a/src/test/ui/moves/move-guard-same-consts.stderr
+++ b/src/test/ui/moves/move-guard-same-consts.stderr
@@ -8,6 +8,18 @@ LL |         (1, 2) if take(x) => (),
    |                        - value moved here
 LL |         (1, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-guard-same-consts.rs:25:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (1, 2) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr
index 5e9aa66b90d..f04cb34d7c4 100644
--- a/src/test/ui/moves/move-in-guard-1.stderr
+++ b/src/test/ui/moves/move-in-guard-1.stderr
@@ -8,6 +8,18 @@ LL |         (1, _) if take(x) => (),
    |                        - value moved here
 LL |         (_, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-in-guard-1.rs:15:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (1, _) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr
index 8d636c11b78..26047861f55 100644
--- a/src/test/ui/moves/move-in-guard-2.stderr
+++ b/src/test/ui/moves/move-in-guard-2.stderr
@@ -6,6 +6,18 @@ LL |     let x: Box<_> = Box::new(1);
 ...
 LL |         (_, 2) if take(x) => (),
    |                        ^ value used here after move
+   |
+note: consider changing this parameter type in function `take` to borrow instead if owning the value isn't necessary
+  --> $DIR/move-in-guard-2.rs:13:15
+   |
+LL | fn take<T>(_: T) -> bool { false }
+   |    ----       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         (_, 2) if take(x.clone()) => (),
+   |                         ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
index 3cc8ca29144..a49ee31b466 100644
--- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
+++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr
@@ -13,6 +13,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     consume(x.clone().into_iter().next().unwrap());
+   |              ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
index a315bbaab33..db4382b58fc 100644
--- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
+++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr
@@ -8,7 +8,7 @@ LL |     consume(node) + r
    |             ^^^^ value used here after partial move
    |
    = note: partial move occurs because value has type `Box<List>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `node.next.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref right) => consume(right),
    |              +++
diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
index ee7971691a4..0930df14805 100644
--- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
+++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr
@@ -9,6 +9,11 @@ LL |     let _y = Foo { f:x };
 LL |
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:x.clone() };
+   |                       ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11
@@ -21,6 +26,11 @@ LL |     let _y = Foo { f:(((x))) };
 LL |
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:(((x))).clone() };
+   |                             ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr
index 9bcec36740d..838b1282cb4 100644
--- a/src/test/ui/moves/moves-based-on-type-exprs.stderr
+++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr
@@ -7,6 +7,11 @@ LL |     let _y = Foo { f:x };
    |                      - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = Foo { f:x.clone() };
+   |                       ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:18:11
@@ -17,6 +22,11 @@ LL |     let _y = (x, 3);
    |               - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = (x.clone(), 3);
+   |                ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:35:11
@@ -29,6 +39,11 @@ LL |         x
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         x.clone()
+   |          ++++++++
 
 error[E0382]: borrow of moved value: `y`
   --> $DIR/moves-based-on-type-exprs.rs:36:11
@@ -41,6 +56,11 @@ LL |         y
 ...
 LL |     touch(&y);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         y.clone()
+   |          ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:46:11
@@ -53,6 +73,11 @@ LL |         true => x,
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         true => x.clone(),
+   |                  ++++++++
 
 error[E0382]: borrow of moved value: `y`
   --> $DIR/moves-based-on-type-exprs.rs:47:11
@@ -65,6 +90,11 @@ LL |         false => y
 ...
 LL |     touch(&y);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false => y.clone()
+   |                   ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:58:11
@@ -77,6 +107,18 @@ LL |         _ if guard(x) => 10,
 ...
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+note: consider changing this parameter type in function `guard` to borrow instead if owning the value isn't necessary
+  --> $DIR/moves-based-on-type-exprs.rs:6:14
+   |
+LL | fn guard(_s: String) -> bool {panic!()}
+   |    -----     ^^^^^^ this parameter takes ownership of the value
+   |    |
+   |    in this function
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         _ if guard(x.clone()) => 10,
+   |                     ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:65:11
@@ -87,6 +129,11 @@ LL |     let _y = [x];
    |               - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = [x.clone()];
+   |                ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:71:11
@@ -97,6 +144,11 @@ LL |     let _y = vec![x];
    |                   - value moved here
 LL |     touch(&x);
    |           ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = vec![x.clone()];
+   |                    ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:77:11
@@ -113,6 +165,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = x.clone().into_iter().next().unwrap();
+   |               ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/moves-based-on-type-exprs.rs:83:11
@@ -129,6 +185,10 @@ note: this function takes ownership of the receiver `self`, which moves `x`
    |
 LL |     fn into_iter(self) -> Self::IntoIter;
    |                  ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = [x.clone().into_iter().next().unwrap(); 1];
+   |                ++++++++
 
 error: aborting due to 11 previous errors
 
diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
index ad1a2db8b52..225935532ea 100644
--- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
+++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr
@@ -8,6 +8,10 @@ LL |     touch(&x);
    |           ^^ value borrowed here after partial move
    |
    = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Foo {ref f} => {}
+   |              +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr
index eef8ce61fa9..0bcce301263 100644
--- a/src/test/ui/moves/moves-based-on-type-tuple.stderr
+++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr
@@ -8,6 +8,11 @@ LL |     Box::new((x, x))
    |               -  ^ value used here after move
    |               |
    |               value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     Box::new((x.clone(), x))
+   |                ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
index c25981e6f80..22e7951dbe3 100644
--- a/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
+++ b/src/test/ui/moves/use_of_moved_value_clone_suggestions.stderr
@@ -7,6 +7,11 @@ LL |     (t, t)
    |      -  ^ value used here after move
    |      |
    |      value moved here
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     (t.clone(), t)
+   |       ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr
index e9d7ca953d6..0a09353b8ec 100644
--- a/src/test/ui/nll/closure-access-spans.stderr
+++ b/src/test/ui/nll/closure-access-spans.stderr
@@ -67,6 +67,11 @@ LL |     || x.len();
    |     ^^ - borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:40:5
@@ -79,6 +84,11 @@ LL |     || x = String::new();
    |     ^^ - borrow occurs due to use in closure
    |     |
    |     value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = x.clone();
+   |              ++++++++
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/closure-access-spans.rs:45:5
diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
index 947c9e29b45..97ed414b1ec 100644
--- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
+++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr
@@ -37,6 +37,11 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
 LL |     t.0 = 10; t.1 = Box::new(20);
    |     ^^^^^^^^ value partially assigned here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t.clone());
+   |                                            ++++++++
 
 error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-use.rs:123:5
@@ -77,6 +82,11 @@ LL |     let mut t: T = (0, Box::new(0)); drop(t);
    |         move occurs because `t` has type `(u32, Box<u32>)`, which does not implement the `Copy` trait
 LL |     t.0 = 10;
    |     ^^^^^^^^ value partially assigned here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut t: T = (0, Box::new(0)); drop(t.clone());
+   |                                            ++++++++
 
 error[E0381]: partially assigned binding `s` isn't fully initialized
   --> $DIR/issue-21232-partial-init-and-use.rs:149:5
@@ -208,6 +218,11 @@ LL |         c2 => {
    |         -- value moved here
 LL |             c.0 = 2;
    |             ^^^^^^^ value partially assigned here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error[E0382]: assign to part of moved value: `c`
   --> $DIR/issue-21232-partial-init-and-use.rs:255:13
@@ -219,6 +234,11 @@ LL |         c2 => {
    |         -- value moved here
 LL |             (c.1).0 = 2;
    |             ^^^^^^^^^^^ value partially assigned here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error[E0382]: assign to part of moved value: `c.1`
   --> $DIR/issue-21232-partial-init-and-use.rs:263:13
@@ -229,6 +249,10 @@ LL |             ((c.1).1).0 = 3;
    |             ^^^^^^^^^^^^^^^ value partially assigned here after move
    |
    = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref c2 => {
+   |         +++
 
 error: aborting due to 23 previous errors
 
diff --git a/src/test/ui/nll/issue-51512.stderr b/src/test/ui/nll/issue-51512.stderr
index e591ca08290..072e96788b1 100644
--- a/src/test/ui/nll/issue-51512.stderr
+++ b/src/test/ui/nll/issue-51512.stderr
@@ -7,6 +7,11 @@ LL |     let r = range;
    |             ----- value moved here
 LL |     let x = range.start;
    |             ^^^^^^^^^^^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let r = range.clone();
+   |                  ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr
index 574a114340f..d8f58b59131 100644
--- a/src/test/ui/nll/issue-53807.stderr
+++ b/src/test/ui/nll/issue-53807.stderr
@@ -5,7 +5,7 @@ LL |         if let Some(thing) = maybe {
    |                     ^^^^^ value moved here, in previous iteration of loop
    |
    = note: move occurs because value has type `Vec<bool>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `maybe.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         if let Some(ref thing) = maybe {
    |                     +++
diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr
index 2d48a914218..f72ed3af718 100644
--- a/src/test/ui/nll/match-cfg-fake-edges.stderr
+++ b/src/test/ui/nll/match-cfg-fake-edges.stderr
@@ -26,6 +26,11 @@ LL |         false if { drop(x); true } => 1,
 LL |         true => {
 LL |             x;
    |             ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         false if { drop(x.clone()); true } => 1,
+   |                          ++++++++
 
 error: aborting due to 2 previous errors
 
diff --git a/src/test/ui/nll/ref-suggestion.stderr b/src/test/ui/nll/ref-suggestion.stderr
index a973c583a9d..b1f5117cb02 100644
--- a/src/test/ui/nll/ref-suggestion.stderr
+++ b/src/test/ui/nll/ref-suggestion.stderr
@@ -7,6 +7,11 @@ LL |     let y = x;
    |             - value moved here
 LL |     x;
    |     ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let y = x.clone();
+   |              ++++++++
 
 error[E0382]: use of moved value: `x`
   --> $DIR/ref-suggestion.rs:8:5
@@ -17,6 +22,11 @@ LL |     let mut y = x;
    |                 - value moved here
 LL |     x;
    |     ^ value used here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let mut y = x.clone();
+   |                  ++++++++
 
 error[E0382]: use of partially moved value: `x`
   --> $DIR/ref-suggestion.rs:16:5
@@ -28,7 +38,7 @@ LL |     x;
    |     ^ value used here after partial move
    |
    = note: partial move occurs because value has type `Vec<i32>`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         (Some(ref y), ()) => {},
    |               +++
diff --git a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
index fad84dda0e1..c8b45fd24d9 100644
--- a/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
+++ b/src/test/ui/pattern/bindings-after-at/bind-by-move-neither-can-live-while-the-other-survives-1.stderr
@@ -16,6 +16,11 @@ LL |         Some(_z @ ref _y) => {}
    |              |    value borrowed here after move
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Some(ref _z @ ref _y) => {}
+   |              +++
 
 error: cannot move out of value because it is borrowed
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:26:14
@@ -35,6 +40,11 @@ LL |         Some(_z @ ref mut _y) => {}
    |              |    value borrowed here after move
    |              value moved into `_z` here
    |              move occurs because `_z` has type `X` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Some(ref _z @ ref mut _y) => {}
+   |              +++
 
 error[E0382]: borrow of moved value
   --> $DIR/bind-by-move-neither-can-live-while-the-other-survives-1.rs:12:14
@@ -45,7 +55,7 @@ LL |         Some(ref _y @ _z) => {}
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref _y @ ref _z) => {}
    |                       +++
@@ -59,7 +69,7 @@ LL |         Some(ref mut _y @ _z) => {}
    |              value borrowed here after move
    |
    = note: move occurs because value has type `X`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving `x.0`
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         Some(ref mut _y @ ref _z) => {}
    |                           +++
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
index a227cc583d6..32489715112 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr
@@ -6,6 +6,11 @@ LL |     let a @ b = U;
    |         |   |
    |         |   value moved here
    |         value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++     +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:13:9
@@ -16,6 +21,10 @@ LL |     let a @ (b, c) = (U, U);
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, ref c) = (U, U);
+   |         +++         +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:15:9
@@ -26,6 +35,10 @@ LL |     let a @ (b, c) = (u(), u());
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, ref c) = (u(), u());
+   |         +++         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:18:16
@@ -36,6 +49,11 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |         -      ^ value used here after move
    |         |
    |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Ok(b) | a @ Err(b) => {}
+   |         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:18:29
@@ -46,6 +64,11 @@ LL |         a @ Ok(b) | a @ Err(b) => {}
    |                     -       ^ value used here after move
    |                     |
    |                     value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Ok(b) | ref a @ Err(b) => {}
+   |                     +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:25:9
@@ -56,6 +79,10 @@ LL |         xs @ [a, .., b] => {}
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref xs @ [a, .., ref b] => {}
+   |         +++              +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-move-and-move.rs:29:9
@@ -66,6 +93,10 @@ LL |         xs @ [_, ys @ .., _] => {}
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref xs @ [_, ref ys @ .., _] => {}
+   |         +++          +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-move-and-move.rs:22:12
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
index 002c7609f61..f27df32ccfa 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr
@@ -79,6 +79,10 @@ LL |     let ref a @ box b = Box::new(NC);
    |         value borrowed here after move
    |
    = note: move occurs because value has type `NC`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ box ref b = Box::new(NC);
+   |                     +++
 
 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable
   --> $DIR/borrowck-pat-at-and-box.rs:38:9
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
index be4e81c61aa..d6474f1b49f 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr
@@ -7,6 +7,11 @@ LL |     let a @ ref b = U;
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
index a9e66de0842..389e86e6464 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr
@@ -7,6 +7,11 @@ LL |     let a @ ref b = U;
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = U;
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
@@ -18,6 +23,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, d @ ref e) = (U, U);
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:14
@@ -28,6 +38,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |              |       value borrowed here after move
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (ref mut b @ ref mut c, d @ ref e) = (U, U);
+   |              +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:33
@@ -38,6 +53,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |                                 |   value borrowed here after move
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+   |                                 +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:29:9
@@ -49,6 +69,11 @@ LL |     let a @ [ref mut b, ref c] = [U, U];
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ [ref mut b, ref c] = [U, U];
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9
@@ -59,6 +84,11 @@ LL |     let a @ ref b = u();
    |         |   value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = u();
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
@@ -70,6 +100,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         |            value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:14
@@ -80,6 +115,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |              |       value borrowed here after move
    |              value moved into `b` here
    |              move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (ref mut b @ ref mut c, d @ ref e) = (u(), u());
+   |              +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:33
@@ -90,6 +130,11 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |                                 |   value borrowed here after move
    |                                 value moved into `d` here
    |                                 move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+   |                                 +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9
@@ -101,6 +146,11 @@ LL |     let a @ [ref mut b, ref c] = [u(), u()];
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ [ref mut b, ref c] = [u(), u()];
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:42:9
@@ -111,6 +161,11 @@ LL |         a @ Some(ref b) => {}
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:9
@@ -122,6 +177,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:19
@@ -132,6 +192,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   |       value borrowed here after move
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
@@ -142,6 +207,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      |   value borrowed here after move
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:9
@@ -153,6 +223,11 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref mut a @ Some([ref b, ref mut c]) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9
@@ -163,6 +238,11 @@ LL |         a @ Some(ref b) => {}
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<U>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:9
@@ -174,6 +254,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         |                 value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:19
@@ -184,6 +269,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                   |       value borrowed here after move
    |                   value moved into `b` here
    |                   move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((ref mut b @ ref mut c, d @ ref e)) => {}
+   |                   +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
@@ -194,6 +284,11 @@ LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |                                      |   value borrowed here after move
    |                                      value moved into `d` here
    |                                      move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         a @ Some((mut b @ ref mut c, ref d @ ref e)) => {}
+   |                                      +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:9
@@ -205,6 +300,11 @@ LL |         mut a @ Some([ref b, ref mut c]) => {}
    |         |             value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref mut a @ Some([ref b, ref mut c]) => {}
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:11:11
@@ -215,6 +315,11 @@ LL |     fn f1(a @ ref b: U) {}
    |           |   value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f1(ref a @ ref b: U) {}
+   |           +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11
@@ -226,6 +331,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |           |            value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(ref mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
+   |           +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:20
@@ -236,6 +346,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                    |   value borrowed here after move
    |                    value moved into `b` here
    |                    move occurs because `b` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(mut a @ (ref b @ ref c, mut d @ ref e): (U, U)) {}
+   |                    +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:31
@@ -246,6 +361,11 @@ LL |     fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {}
    |                               |       value borrowed here after move
    |                               value moved into `d` here
    |                               move occurs because `d` has type `U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f2(mut a @ (b @ ref c, ref mut d @ ref e): (U, U)) {}
+   |                               +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:19:11
@@ -257,6 +377,11 @@ LL |     fn f3(a @ [ref mut b, ref c]: [U; 2]) {}
    |           |    value borrowed here after move
    |           value moved into `a` here
    |           move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     fn f3(ref a @ [ref mut b, ref c]: [U; 2]) {}
+   |           +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:24:9
@@ -267,6 +392,10 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (U, U);
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, ref d @ ref e) = (U, U);
+   |         +++                         +++
 
 error[E0382]: use of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:33:9
@@ -277,6 +406,10 @@ LL |     let a @ (mut b @ ref mut c, d @ ref e) = (u(), u());
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (mut b @ ref mut c, ref d @ ref e) = (u(), u());
+   |         +++                         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:47:38
@@ -285,6 +418,11 @@ LL |     match Some((U, U)) {
    |           ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         - value moved here           ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:55:30
@@ -305,6 +443,11 @@ LL |         a @ Some(ref b) => {}
    |         -        ^^^^^ value borrowed here after move
    |         |
    |         value moved here
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some(ref b) => {}
+   |         +++
 
 error[E0382]: use of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:67:38
@@ -313,6 +456,11 @@ LL |     match Some((u(), u())) {
    |           ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait
 LL |         a @ Some((mut b @ ref mut c, d @ ref e)) => {}
    |         - value moved here           ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         ref a @ Some((mut b @ ref mut c, d @ ref e)) => {}
+   |         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:75:30
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
index b2f22fe8638..770bb89530c 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref.stderr
@@ -242,6 +242,10 @@ LL |     let ref mut a @ [b, mut c] = [U, U];
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ [b, ref mut c] = [U, U];
+   |                         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:33:9
@@ -251,6 +255,11 @@ LL |     let ref a @ b = u();
    |         |       |
    |         |       value moved here
    |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ ref b = u();
+   |                 +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:18
@@ -261,6 +270,10 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                  value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref b @ ref mut c, ref d @ e) = (u(), u());
+   |                          +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:36:33
@@ -271,6 +284,10 @@ LL |     let ref a @ (ref b @ mut c, ref d @ e) = (u(), u());
    |                                 value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref b @ mut c, ref d @ ref e) = (u(), u());
+   |                                         +++
 
 error[E0382]: borrow of partially moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:42:9
@@ -281,6 +298,10 @@ LL |     let ref mut a @ [b, mut c] = [u(), u()];
    |         value borrowed here after partial move
    |
    = note: partial move occurs because value has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ [b, ref mut c] = [u(), u()];
+   |                         +++
 
 error[E0382]: borrow of moved value
   --> $DIR/borrowck-pat-by-move-and-ref.rs:69:23
@@ -291,7 +312,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                       value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving the value
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         ref a @ Some((ref b @ ref mut c, ref d @ e)) => {}
    |                               +++
@@ -305,7 +326,7 @@ LL |         ref a @ Some((ref b @ mut c, ref d @ e)) => {}
    |                                      value borrowed here after move
    |
    = note: move occurs because value has type `U`, which does not implement the `Copy` trait
-help: borrow this field in the pattern to avoid moving the value
+help: borrow this binding in the pattern to avoid moving the value
    |
 LL |         ref a @ Some((ref b @ mut c, ref d @ ref e)) => {}
    |                                              +++
diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
index 384a57b2ee0..ad4ce7952ca 100644
--- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
+++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr
@@ -97,6 +97,11 @@ LL |     let a @ (ref mut b, ref mut c) = (U, U);
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (ref mut b, ref mut c) = (U, U);
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:67:9
@@ -109,6 +114,11 @@ LL |     let a @ (b, [c, d]) = &mut val; // Same as ^--
    |         |    value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ (b, [c, d]) = &mut val; // Same as ^--
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9
@@ -119,6 +129,11 @@ LL |     let a @ &mut ref mut b = &mut U;
    |         |        value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut U` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ &mut ref mut b = &mut U;
+   |         +++
 
 error: borrow of moved value
   --> $DIR/borrowck-pat-ref-mut-twice.rs:72:9
@@ -130,6 +145,11 @@ LL |     let a @ &mut (ref mut b, ref mut c) = &mut (U, U);
    |         |         value borrowed here after move
    |         value moved into `a` here
    |         move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ &mut (ref mut b, ref mut c) = &mut (U, U);
+   |         +++
 
 error: cannot borrow value as mutable more than once at a time
   --> $DIR/borrowck-pat-ref-mut-twice.rs:76:9
diff --git a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
index cd3234952fa..e0e623fa544 100644
--- a/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
+++ b/src/test/ui/pattern/bindings-after-at/copy-and-move-mixed.stderr
@@ -7,6 +7,10 @@ LL |     let a @ NC(b, c @ NC(d, e)) = NC(C, NC(C, C));
    |         value used here after partial move
    |
    = note: partial move occurs because value has type `NC<C, C>`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref a @ NC(b, ref c @ NC(d, e)) = NC(C, NC(C, C));
+   |         +++           +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
index 840a513d6c6..638bdd6db76 100644
--- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
+++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr
@@ -34,6 +34,11 @@ LL |         Ok(ref a @ b) | Err(b @ ref a) => {
    |                             |   value borrowed here after move
    |                             value moved into `b` here
    |                             move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |         Ok(ref a @ b) | Err(ref b @ ref a) => {
+   |                             +++
 
 error: cannot move out of value because it is borrowed
   --> $DIR/default-binding-modes-both-sides-independent.rs:42:9
@@ -52,6 +57,11 @@ LL |     let ref mut a @ b = NotCopy;
    |         |           |
    |         |           value moved here
    |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref mut a @ ref b = NotCopy;
+   |                     +++
 
 error: aborting due to 6 previous errors
 
diff --git a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
index bac2db6ce82..bb7b818368b 100644
--- a/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
+++ b/src/test/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr
@@ -129,6 +129,10 @@ LL |     drop(tup.1);
    |          ^^^^^ value used here after move
    |
    = note: move occurs because `tup.1` has type `U`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let (ref _x0, ref _x1, ref _x2, ..) = tup;
+   |                   +++
 
 error[E0382]: borrow of moved value: `tup.1`
   --> $DIR/borrowck-move-ref-pattern.rs:29:20
diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
index 5611b5f4ece..06699b947be 100644
--- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
+++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-move-semantics.stderr
@@ -7,6 +7,12 @@ LL |     let _ = dbg!(a);
    |             ------- value moved here
 LL |     let _ = dbg!(a);
    |                  ^ value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+  --> $SRC_DIR/std/src/macros.rs:LL:COL
+   |
+LL |             ref tmp => {
+   |             +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/rfc-2497-if-let-chains/issue-99938.rs b/src/test/ui/rfc-2497-if-let-chains/issue-99938.rs
new file mode 100644
index 00000000000..bd81ce0b19c
--- /dev/null
+++ b/src/test/ui/rfc-2497-if-let-chains/issue-99938.rs
@@ -0,0 +1,31 @@
+// compile-flags: -Zvalidate-mir -C opt-level=3
+// build-pass
+#![feature(let_chains)]
+struct TupleIter<T, I: Iterator<Item = T>> {
+    inner: I,
+}
+
+impl<T, I: Iterator<Item = T>> Iterator for TupleIter<T, I> {
+    type Item = (T, T, T);
+
+    fn next(&mut self) -> Option<Self::Item> {
+        let inner = &mut self.inner;
+
+        if let Some(first) = inner.next()
+            && let Some(second) = inner.next()
+            && let Some(third) = inner.next()
+        {
+            Some((first, second, third))
+        } else {
+            None
+        }
+    }
+}
+
+fn main() {
+    let vec: Vec<u8> = Vec::new();
+    let mut tup_iter = TupleIter {
+        inner: vec.into_iter(),
+    };
+    tup_iter.next();
+}
diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr
index 1059e3d1525..0cc8994fe1f 100644
--- a/src/test/ui/suggestions/borrow-for-loop-head.stderr
+++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr
@@ -12,6 +12,7 @@ error[E0382]: use of moved value: `a`
 LL |     let a = vec![1, 2, 3];
    |         - move occurs because `a` has type `Vec<i32>`, which does not implement the `Copy` trait
 LL |     for i in &a {
+   |     ----------- inside of this loop
 LL |         for j in a {
    |                  ^ `a` moved due to this implicit call to `.into_iter()`, in previous iteration of loop
    |
diff --git a/src/test/ui/suggestions/ref-pattern-binding.fixed b/src/test/ui/suggestions/ref-pattern-binding.fixed
new file mode 100644
index 00000000000..c36040eeca3
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.fixed
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused)]
+
+struct S {
+    f: String,
+}
+
+fn main() {
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ ref _from = String::from("foo"); //~ ERROR
+    //~^ ERROR
+    let ref _moved @ ref _from = String::from("foo"); // ok
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+    //~^ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+}
diff --git a/src/test/ui/suggestions/ref-pattern-binding.rs b/src/test/ui/suggestions/ref-pattern-binding.rs
new file mode 100644
index 00000000000..c0d4feb0330
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.rs
@@ -0,0 +1,19 @@
+// run-rustfix
+#![allow(unused)]
+
+struct S {
+    f: String,
+}
+
+fn main() {
+    let _moved @ _from = String::from("foo"); //~ ERROR
+    let _moved @ ref _from = String::from("foo"); //~ ERROR
+    let ref _moved @ _from = String::from("foo"); //~ ERROR
+    //~^ ERROR
+    let ref _moved @ ref _from = String::from("foo"); // ok
+    let _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR
+    let ref _moved @ S { f } = S { f: String::from("foo") }; //~ ERROR
+    //~^ ERROR
+    let ref _moved @ S { ref f } = S { f: String::from("foo") }; // ok
+    let _moved @ S { ref f } = S { f: String::from("foo") }; //~ ERROR
+}
diff --git a/src/test/ui/suggestions/ref-pattern-binding.stderr b/src/test/ui/suggestions/ref-pattern-binding.stderr
new file mode 100644
index 00000000000..10447ba7089
--- /dev/null
+++ b/src/test/ui/suggestions/ref-pattern-binding.stderr
@@ -0,0 +1,107 @@
+error: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:10:9
+   |
+LL |     let _moved @ ref _from = String::from("foo");
+   |         ------^^^---------
+   |         |        |
+   |         |        value borrowed here after move
+   |         value moved into `_moved` here
+   |         move occurs because `_moved` has type `String` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++
+
+error: cannot move out of value because it is borrowed
+  --> $DIR/ref-pattern-binding.rs:11:9
+   |
+LL |     let ref _moved @ _from = String::from("foo");
+   |         ----------^^^-----
+   |         |            |
+   |         |            value moved into `_from` here
+   |         value borrowed, by `_moved`, here
+
+error: cannot move out of value because it is borrowed
+  --> $DIR/ref-pattern-binding.rs:15:9
+   |
+LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
+   |         ----------^^^^^^^-^^
+   |         |                |
+   |         |                value moved into `f` here
+   |         value borrowed, by `_moved`, here
+
+error: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:18:9
+   |
+LL |     let _moved @ S { ref f } = S { f: String::from("foo") };
+   |         ------^^^^^^^-----^^
+   |         |            |
+   |         |            value borrowed here after move
+   |         value moved into `_moved` here
+   |         move occurs because `_moved` has type `S` which does not implement the `Copy` trait
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |         +++
+
+error[E0382]: use of moved value
+  --> $DIR/ref-pattern-binding.rs:9:9
+   |
+LL |     let _moved @ _from = String::from("foo");
+   |         ^^^^^^   -----   ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait
+   |         |        |
+   |         |        value moved here
+   |         value used here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++          +++
+
+error[E0382]: borrow of moved value
+  --> $DIR/ref-pattern-binding.rs:11:9
+   |
+LL |     let ref _moved @ _from = String::from("foo");
+   |         ^^^^^^^^^^   -----   ------------------- move occurs because value has type `String`, which does not implement the `Copy` trait
+   |         |            |
+   |         |            value moved here
+   |         value borrowed here after move
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |                      +++
+
+error[E0382]: use of partially moved value
+  --> $DIR/ref-pattern-binding.rs:14:9
+   |
+LL |     let _moved @ S { f } = S { f: String::from("foo") };
+   |         ^^^^^^       - value partially moved here
+   |         |
+   |         value used here after partial move
+   |
+   = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |         +++              +++
+
+error[E0382]: borrow of partially moved value
+  --> $DIR/ref-pattern-binding.rs:15:9
+   |
+LL |     let ref _moved @ S { f } = S { f: String::from("foo") };
+   |         ^^^^^^^^^^       - value partially moved here
+   |         |
+   |         value borrowed here after partial move
+   |
+   = note: partial move occurs because value has type `String`, which does not implement the `Copy` trait
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ S { ref f } = S { f: String::from("foo") };
+   |                          +++
+
+error: aborting due to 8 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/track-diagnostics/track2.stderr b/src/test/ui/track-diagnostics/track2.stderr
index 38a621da816..fe13e5ef3f5 100644
--- a/src/test/ui/track-diagnostics/track2.stderr
+++ b/src/test/ui/track-diagnostics/track2.stderr
@@ -7,6 +7,11 @@ LL |     let _moved @ _from = String::from("foo");
    |         |        value moved here
    |         value used here after move
 -Ztrack-diagnostics: created at compiler/rustc_borrowck/src/borrowck_errors.rs:LL:CC
+   |
+help: borrow this binding in the pattern to avoid moving the value
+   |
+LL |     let ref _moved @ ref _from = String::from("foo");
+   |         +++          +++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
index 5f5a2574bab..d624187561e 100644
--- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
+++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.rs
@@ -7,7 +7,11 @@ use core::ops::Deref;
 // issue 89190
 trait A {}
 trait B: A {}
+
 impl<'a> Deref for dyn 'a + B {
+    //~^ ERROR `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
+    //~| WARN this was previously accepted by the compiler but is being phased out;
+
     type Target = dyn A;
     fn deref(&self) -> &Self::Target {
         todo!()
@@ -18,8 +22,6 @@ fn take_a(_: &dyn A) {}
 
 fn whoops(b: &dyn B) {
     take_a(b)
-    //~^ ERROR `dyn B` implements `Deref` with supertrait `A` as output
-    //~^^ WARN this was previously accepted by the compiler but is being phased out;
 }
 
 fn main() {}
diff --git a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
index 41381a3ffd1..4533b116342 100644
--- a/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
+++ b/src/test/ui/traits/trait-upcasting/migrate-lint-deny.stderr
@@ -1,8 +1,11 @@
-error: `dyn B` implements `Deref` with supertrait `A` as output
-  --> $DIR/migrate-lint-deny.rs:20:12
+error: `(dyn B + 'a)` implements `Deref` with supertrait `A` as target
+  --> $DIR/migrate-lint-deny.rs:11:1
    |
-LL |     take_a(b)
-   |            ^
+LL | impl<'a> Deref for dyn 'a + B {
+   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+...
+LL |     type Target = dyn A;
+   |     -------------------- target type is set here
    |
    = warning: 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 #89460 <https://github.com/rust-lang/rust/issues/89460>
diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
index c9f2a3ed9f4..f738b03eed6 100644
--- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
+++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr
@@ -23,6 +23,10 @@ LL |         println!("{}", x);
    |                        ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |             ::std::mem::drop(x.clone());
+   |                               ++++++++
 
 error[E0506]: cannot assign to `i` because it is borrowed
   --> $DIR/try-block-maybe-bad-lifetime.rs:40:9
diff --git a/src/test/ui/union/union-move.mirunsafeck.stderr b/src/test/ui/union/union-move.mirunsafeck.stderr
index 53050cf539e..6381ae874ba 100644
--- a/src/test/ui/union/union-move.mirunsafeck.stderr
+++ b/src/test/ui/union/union-move.mirunsafeck.stderr
@@ -8,6 +8,14 @@ LL |         move_out(x.f1_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f2_nocopy);
    |                  ^^^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:45:18
@@ -19,6 +27,14 @@ LL |         move_out(x.f2_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f3_copy);
    |                  ^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:52:18
diff --git a/src/test/ui/union/union-move.thirunsafeck.stderr b/src/test/ui/union/union-move.thirunsafeck.stderr
index 53050cf539e..6381ae874ba 100644
--- a/src/test/ui/union/union-move.thirunsafeck.stderr
+++ b/src/test/ui/union/union-move.thirunsafeck.stderr
@@ -8,6 +8,14 @@ LL |         move_out(x.f1_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f2_nocopy);
    |                  ^^^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/union-move.rs:45:18
@@ -19,6 +27,14 @@ LL |         move_out(x.f2_nocopy);
    |                  ----------- value moved here
 LL |         move_out(x.f3_copy);
    |                  ^^^^^^^^^ value used here after move
+   |
+note: consider changing this parameter type in function `move_out` to borrow instead if owning the value isn't necessary
+  --> $DIR/union-move.rs:10:19
+   |
+LL | fn move_out<T>(x: T) {}
+   |    --------       ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait
   --> $DIR/union-move.rs:52:18
diff --git a/src/test/ui/unop-move-semantics.stderr b/src/test/ui/unop-move-semantics.stderr
index 65d866c716e..d52a92b8888 100644
--- a/src/test/ui/unop-move-semantics.stderr
+++ b/src/test/ui/unop-move-semantics.stderr
@@ -14,6 +14,10 @@ note: calling this operator moves the left-hand side
    |
 LL |     fn not(self) -> Self::Output;
    |            ^^^^
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     !x.clone();
+   |       ++++++++
 help: consider further restricting this bound
    |
 LL | fn move_then_borrow<T: Not<Output=T> + Clone + Copy>(x: T) {
diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr
index 28ae1c0688c..d8bffd4f9cf 100644
--- a/src/test/ui/unsized-locals/borrow-after-move.stderr
+++ b/src/test/ui/unsized-locals/borrow-after-move.stderr
@@ -28,6 +28,14 @@ LL |         drop_unsized(y);
 ...
 LL |         println!("{}", &y);
    |                        ^^ value borrowed here after move
+   |
+note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
+  --> $DIR/borrow-after-move.rs:14:31
+   |
+LL | fn drop_unsized<T: ?Sized>(_: T) {}
+   |    ------------               ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: borrow of moved value: `x`
   --> $DIR/borrow-after-move.rs:31:24
@@ -66,6 +74,11 @@ LL |         x.foo();
    |         - value moved here
 LL |         println!("{}", &x);
    |                        ^^ value borrowed here after move
+   |
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |         x.clone().foo();
+   |          ++++++++
 
 error: aborting due to 5 previous errors; 1 warning emitted
 
diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr
index dfae6cc75d9..71534818141 100644
--- a/src/test/ui/unsized-locals/double-move.stderr
+++ b/src/test/ui/unsized-locals/double-move.stderr
@@ -16,6 +16,14 @@ LL |         drop_unsized(y);
    |                      - value moved here
 LL |         drop_unsized(y);
    |                      ^ value used here after move
+   |
+note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
+  --> $DIR/double-move.rs:14:31
+   |
+LL | fn drop_unsized<T: ?Sized>(_: T) {}
+   |    ------------               ^ this parameter takes ownership of the value
+   |    |
+   |    in this function
 
 error[E0382]: use of moved value: `x`
   --> $DIR/double-move.rs:27:22
diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr
index 445f14d65e3..7b4d2454994 100644
--- a/src/test/ui/use/use-after-move-based-on-type.stderr
+++ b/src/test/ui/use/use-after-move-based-on-type.stderr
@@ -9,6 +9,10 @@ LL |     println!("{}", x);
    |                    ^ value borrowed here after move
    |
    = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
+help: consider cloning the value if the performance cost is acceptable
+   |
+LL |     let _y = x.clone();
+   |               ++++++++
 
 error: aborting due to previous error
 
diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
index 26804216d9d..dfa0c04836e 100644
--- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
+++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr
@@ -9,6 +9,14 @@ LL |     l.push(n);
 LL |
 LL |     let x = n.to_string();
    |             ^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: consider changing this parameter type in method `push` to borrow instead if owning the value isn't necessary
+  --> $DIR/use-after-move-implicity-coerced-object.rs:17:27
+   |
+LL |     fn push(&mut self, n: Box<dyn ToString + 'static>) {
+   |        ----               ^^^^^^^^^^^^^^^^^^^^^^^^^^^ this parameter takes ownership of the value
+   |        |
+   |        in this method
 
 error: aborting due to previous error
 
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index 06a39c5997e..b4210d87510 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -1,6 +1,6 @@
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, implements_trait, is_copy};
+use clippy_utils::ty::{implements_trait, is_copy};
 use rustc_errors::Applicability;
 use rustc_hir::Expr;
 use rustc_lint::LateContext;
@@ -25,7 +25,7 @@ pub(super) fn check<'tcx>(
         && let Some(method_id) = typeck.type_dependent_def_id(cloned_call.hir_id)
         && cx.tcx.trait_of_item(method_id) == Some(iter_id)
         && let cloned_recv_ty = typeck.expr_ty_adjusted(cloned_recv)
-        && let Some(iter_assoc_ty) = get_associated_type(cx, cloned_recv_ty, iter_id, "Item")
+        && let Some(iter_assoc_ty) = cx.get_associated_type(cloned_recv_ty, iter_id, "Item")
         && matches!(*iter_assoc_ty.kind(), ty::Ref(_, ty, _) if !is_copy(cx, ty))
     {
         if needs_into_iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
index 4eb579af7a1..52a4ff7d1ae 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_iter_cloned.rs
@@ -2,7 +2,7 @@ use super::utils::clone_or_copy_needed;
 use clippy_utils::diagnostics::span_lint_and_then;
 use clippy_utils::higher::ForLoop;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait};
 use clippy_utils::{fn_def_id, get_parent_expr};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, Expr, ExprKind};
@@ -54,7 +54,7 @@ pub fn check_for_loop_iter(
                 if let Some(into_iterator_trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator);
                 let collection_ty = cx.typeck_results().expr_ty(collection);
                 if implements_trait(cx, collection_ty, into_iterator_trait_id, &[]);
-                if let Some(into_iter_item_ty) = get_associated_type(cx, collection_ty, into_iterator_trait_id, "Item");
+                if let Some(into_iter_item_ty) = cx.get_associated_type(collection_ty, into_iterator_trait_id, "Item");
 
                 if iter_item_ty == into_iter_item_ty;
                 if let Some(collection_snippet) = snippet_opt(cx, collection.span);
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 375ebc903b4..8b000cd754c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -2,9 +2,11 @@ use super::implicit_clone::is_clone_like;
 use super::unnecessary_iter_cloned::{self, is_into_iter};
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::source::snippet_opt;
-use clippy_utils::ty::{get_associated_type, get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
+use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
 use clippy_utils::visitors::find_all_ret_expressions;
-use clippy_utils::{fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty};
+use clippy_utils::{
+    fn_def_id, get_parent_expr, is_diag_item_method, is_diag_trait_item, return_ty,
+};
 use clippy_utils::{meets_msrv, msrvs};
 use rustc_errors::Applicability;
 use rustc_hir::{def_id::DefId, BorrowKind, Expr, ExprKind, ItemKind, Node};
@@ -18,7 +20,9 @@ use rustc_middle::ty::EarlyBinder;
 use rustc_middle::ty::{self, ParamTy, PredicateKind, ProjectionPredicate, TraitPredicate, Ty};
 use rustc_semver::RustcVersion;
 use rustc_span::{sym, Symbol};
-use rustc_trait_selection::traits::{query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause};
+use rustc_trait_selection::traits::{
+    query::evaluate_obligation::InferCtxtExt as _, Obligation, ObligationCause,
+};
 use std::cmp::max;
 
 use super::UNNECESSARY_TO_OWNED;
@@ -146,7 +150,7 @@ fn check_addr_of_expr(
             if_chain! {
                 if let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref);
                 if implements_trait(cx, receiver_ty, deref_trait_id, &[]);
-                if get_associated_type(cx, receiver_ty, deref_trait_id, "Target") == Some(target_ty);
+                if cx.get_associated_type(receiver_ty, deref_trait_id, "Target") == Some(target_ty);
                 then {
                     if n_receiver_refs > 0 {
                         span_lint_and_sugg(
@@ -341,13 +345,13 @@ fn get_input_traits_and_projections<'tcx>(
                 if trait_predicate.trait_ref.self_ty() == input {
                     trait_predicates.push(trait_predicate);
                 }
-            },
+            }
             PredicateKind::Projection(projection_predicate) => {
                 if projection_predicate.projection_ty.self_ty() == input {
                     projection_predicates.push(projection_predicate);
                 }
-            },
-            _ => {},
+            }
+            _ => {}
         }
     }
     (trait_predicates, projection_predicates)
@@ -462,7 +466,12 @@ fn is_cloned_or_copied(cx: &LateContext<'_>, method_name: Symbol, method_def_id:
 
 /// Returns true if the named method can be used to convert the receiver to its "owned"
 /// representation.
-fn is_to_owned_like<'a>(cx: &LateContext<'a>, call_expr: &Expr<'a>, method_name: Symbol, method_def_id: DefId) -> bool {
+fn is_to_owned_like<'a>(
+    cx: &LateContext<'a>,
+    call_expr: &Expr<'a>,
+    method_name: Symbol,
+    method_def_id: DefId,
+) -> bool {
     is_clone_like(cx, method_name.as_str(), method_def_id)
         || is_cow_into_owned(cx, method_name, method_def_id)
         || is_to_string_on_string_like(cx, call_expr, method_name, method_def_id)
@@ -490,7 +499,7 @@ fn is_to_string_on_string_like<'a>(
         && let GenericArgKind::Type(ty) = generic_arg.unpack()
         && let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
         && let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
-        && (get_associated_type(cx, ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
+        && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
             implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
             true
         } else {
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index 78e83880e1a..e111c7d2291 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -582,7 +582,7 @@ fn ident_difference_expr_with_base_location(
         | (Block(_, _), Block(_, _))
         | (Closure(_), Closure(_))
         | (Match(_, _), Match(_, _))
-        | (Loop(_, _), Loop(_, _))
+        | (Loop(_, _, _), Loop(_, _, _))
         | (ForLoop(_, _, _, _), ForLoop(_, _, _, _))
         | (While(_, _, _), While(_, _, _))
         | (If(_, _, _), If(_, _, _))
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index 5c595f74eff..6bcf0bbd7eb 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -171,7 +171,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
         (ForLoop(lp, li, lt, ll), ForLoop(rp, ri, rt, rl)) => {
             eq_label(ll, rl) && eq_pat(lp, rp) && eq_expr(li, ri) && eq_block(lt, rt)
         },
-        (Loop(lt, ll), Loop(rt, rl)) => eq_label(ll, rl) && eq_block(lt, rt),
+        (Loop(lt, ll, _), Loop(rt, rl, _)) => eq_label(ll, rl) && eq_block(lt, rt),
         (Block(lb, ll), Block(rb, rl)) => eq_label(ll, rl) && eq_block(lb, rb),
         (TryBlock(l), TryBlock(r)) => eq_block(l, r),
         (Yield(l), Yield(r)) | (Ret(l), Ret(r)) => eq_expr_opt(l, r),
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 1b65b701409..8284dc5c28c 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -117,24 +117,7 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'
 pub fn get_iterator_item_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
     cx.tcx
         .get_diagnostic_item(sym::Iterator)
-        .and_then(|iter_did| get_associated_type(cx, ty, iter_did, "Item"))
-}
-
-/// Returns the associated type `name` for `ty` as an implementation of `trait_id`.
-/// Do not invoke without first verifying that the type implements the trait.
-pub fn get_associated_type<'tcx>(
-    cx: &LateContext<'tcx>,
-    ty: Ty<'tcx>,
-    trait_id: DefId,
-    name: &str,
-) -> Option<Ty<'tcx>> {
-    cx.tcx
-        .associated_items(trait_id)
-        .find_by_name_and_kind(cx.tcx, Ident::from_str(name), ty::AssocKind::Type, trait_id)
-        .and_then(|assoc| {
-            let proj = cx.tcx.mk_projection(assoc.def_id, cx.tcx.mk_substs_trait(ty, []));
-            cx.tcx.try_normalize_erasing_regions(cx.param_env, proj).ok()
-        })
+        .and_then(|iter_did| cx.get_associated_type(ty, iter_did, "Item"))
 }
 
 /// Get the diagnostic name of a type, e.g. `sym::HashMap`. To check if a type
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 8931c17bbdc..41c5d36671d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -222,6 +222,16 @@ dependencies = [
 ]
 
 [[package]]
+name = "command-group"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7a8a86f409b4a59df3a3e4bee2de0b83f1755fdd2a25e3a9684c396fc4bed2c"
+dependencies = [
+ "nix",
+ "winapi",
+]
+
+[[package]]
 name = "countme"
 version = "3.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -300,7 +310,7 @@ dependencies = [
  "hashbrown",
  "lock_api",
  "once_cell",
- "parking_lot_core 0.9.3",
+ "parking_lot_core 0.9.4",
 ]
 
 [[package]]
@@ -359,14 +369,14 @@ dependencies = [
 
 [[package]]
 name = "filetime"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e94a7bbaa59354bc20dd75b67f23e2797b4490e9d6928203fb105c79e448c86c"
+checksum = "4b9663d381d07ae25dc88dbdf27df458faa83a9b25336bcac83d5e452b5fc9d3"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
- "windows-sys 0.36.1",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -390,6 +400,7 @@ name = "flycheck"
 version = "0.0.0"
 dependencies = [
  "cargo_metadata",
+ "command-group",
  "crossbeam-channel",
  "jod-thread",
  "paths",
@@ -963,11 +974,24 @@ dependencies = [
 
 [[package]]
 name = "miow"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7377f7792b3afb6a3cba68daa54ca23c032137010460d667fda53a8d66be00e"
+checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123"
 dependencies = [
- "windows-sys 0.28.0",
+ "windows-sys 0.42.0",
+]
+
+[[package]]
+name = "nix"
+version = "0.22.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e4916f159ed8e5de0082076562152a76b7a1f64a01fd9d1e0fea002c37624faf"
+dependencies = [
+ "bitflags",
+ "cc",
+ "cfg-if",
+ "libc",
+ "memoffset",
 ]
 
 [[package]]
@@ -1037,7 +1061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
 dependencies = [
  "lock_api",
- "parking_lot_core 0.9.3",
+ "parking_lot_core 0.9.4",
 ]
 
 [[package]]
@@ -1056,15 +1080,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929"
+checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-sys 0.36.1",
+ "windows-sys 0.42.0",
 ]
 
 [[package]]
@@ -1981,19 +2005,6 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-sys"
-version = "0.28.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "82ca39602d5cbfa692c4b67e3bcbb2751477355141c1ed434c94da4186836ff6"
-dependencies = [
- "windows_aarch64_msvc 0.28.0",
- "windows_i686_gnu 0.28.0",
- "windows_i686_msvc 0.28.0",
- "windows_x86_64_gnu 0.28.0",
- "windows_x86_64_msvc 0.28.0",
-]
-
-[[package]]
-name = "windows-sys"
 version = "0.36.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2"
@@ -2006,10 +2017,25 @@ dependencies = [
 ]
 
 [[package]]
-name = "windows_aarch64_msvc"
-version = "0.28.0"
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc 0.42.0",
+ "windows_i686_gnu 0.42.0",
+ "windows_i686_msvc 0.42.0",
+ "windows_x86_64_gnu 0.42.0",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc 0.42.0",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52695a41e536859d5308cc613b4a022261a274390b25bd29dfff4bf08505f3c2"
+checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
 
 [[package]]
 name = "windows_aarch64_msvc"
@@ -2018,10 +2044,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47"
 
 [[package]]
-name = "windows_i686_gnu"
-version = "0.28.0"
+name = "windows_aarch64_msvc"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f54725ac23affef038fecb177de6c9bf065787c2f432f79e3c373da92f3e1d8a"
+checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
 
 [[package]]
 name = "windows_i686_gnu"
@@ -2030,10 +2056,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6"
 
 [[package]]
-name = "windows_i686_msvc"
-version = "0.28.0"
+name = "windows_i686_gnu"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51d5158a43cc43623c0729d1ad6647e62fa384a3d135fd15108d37c683461f64"
+checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
 
 [[package]]
 name = "windows_i686_msvc"
@@ -2042,10 +2068,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024"
 
 [[package]]
-name = "windows_x86_64_gnu"
-version = "0.28.0"
+name = "windows_i686_msvc"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bc31f409f565611535130cfe7ee8e6655d3fa99c1c61013981e491921b5ce954"
+checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
 
 [[package]]
 name = "windows_x86_64_gnu"
@@ -2054,10 +2080,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1"
 
 [[package]]
-name = "windows_x86_64_msvc"
-version = "0.28.0"
+name = "windows_x86_64_gnu"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f2b8c7cbd3bfdddd9ab98769f9746a7fad1bca236554cd032b78d768bc0e89f"
+checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
 
 [[package]]
 name = "windows_x86_64_msvc"
@@ -2066,6 +2098,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
 
 [[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+
+[[package]]
 name = "write-json"
 version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rust-analyzer/crates/base-db/Cargo.toml b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
index f02a51ab6c4..a484ecec682 100644
--- a/src/tools/rust-analyzer/crates/base-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/base-db/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/cfg/Cargo.toml b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
index ee1ad677a95..2857420c285 100644
--- a/src/tools/rust-analyzer/crates/cfg/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/cfg/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
index 2ad32d24837..514d567fcce 100644
--- a/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/flycheck/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
@@ -17,6 +17,7 @@ rustc-hash = "1.1.0"
 serde = { version = "1.0.137", features = ["derive"] }
 serde_json = "1.0.86"
 jod-thread = "0.1.2"
+command-group = "1.0.8"
 
 toolchain = { path = "../toolchain", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
index 8a91d606661..8f93dad06e3 100644
--- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs
@@ -10,11 +10,12 @@ use std::{
     time::Duration,
 };
 
+use command_group::{CommandGroup, GroupChild};
 use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
 use paths::AbsPathBuf;
 use rustc_hash::FxHashMap;
 use serde::Deserialize;
-use stdx::{process::streaming_output, JodChild};
+use stdx::process::streaming_output;
 
 pub use cargo_metadata::diagnostic::{
     Applicability, Diagnostic, DiagnosticCode, DiagnosticLevel, DiagnosticSpan,
@@ -39,7 +40,7 @@ pub enum InvocationLocation {
 pub enum FlycheckConfig {
     CargoCommand {
         command: String,
-        target_triple: Option<String>,
+        target_triples: Vec<String>,
         all_targets: bool,
         no_default_features: bool,
         all_features: bool,
@@ -285,7 +286,7 @@ impl FlycheckActor {
         let (mut cmd, args) = match &self.config {
             FlycheckConfig::CargoCommand {
                 command,
-                target_triple,
+                target_triples,
                 no_default_features,
                 all_targets,
                 all_features,
@@ -299,7 +300,7 @@ impl FlycheckActor {
                 cmd.args(&["--workspace", "--message-format=json", "--manifest-path"])
                     .arg(self.root.join("Cargo.toml").as_os_str());
 
-                if let Some(target) = target_triple {
+                for target in target_triples {
                     cmd.args(&["--target", target.as_str()]);
                 }
                 if *all_targets {
@@ -359,10 +360,12 @@ impl FlycheckActor {
     }
 }
 
+struct JodChild(GroupChild);
+
 /// A handle to a cargo process used for fly-checking.
 struct CargoHandle {
     /// The handle to the actual cargo process. As we cannot cancel directly from with
-    /// a read syscall dropping and therefor terminating the process is our best option.
+    /// a read syscall dropping and therefore terminating the process is our best option.
     child: JodChild,
     thread: jod_thread::JoinHandle<io::Result<(bool, String)>>,
     receiver: Receiver<CargoMessage>,
@@ -371,10 +374,10 @@ struct CargoHandle {
 impl CargoHandle {
     fn spawn(mut command: Command) -> std::io::Result<CargoHandle> {
         command.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
-        let mut child = JodChild::spawn(command)?;
+        let mut child = command.group_spawn().map(JodChild)?;
 
-        let stdout = child.stdout.take().unwrap();
-        let stderr = child.stderr.take().unwrap();
+        let stdout = child.0.inner().stdout.take().unwrap();
+        let stderr = child.0.inner().stderr.take().unwrap();
 
         let (sender, receiver) = unbounded();
         let actor = CargoActor::new(sender, stdout, stderr);
@@ -386,13 +389,13 @@ impl CargoHandle {
     }
 
     fn cancel(mut self) {
-        let _ = self.child.kill();
-        let _ = self.child.wait();
+        let _ = self.child.0.kill();
+        let _ = self.child.0.wait();
     }
 
     fn join(mut self) -> io::Result<()> {
-        let _ = self.child.kill();
-        let exit_status = self.child.wait()?;
+        let _ = self.child.0.kill();
+        let exit_status = self.child.0.wait()?;
         let (read_at_least_one_message, error) = self.thread.join()?;
         if read_at_least_one_message || exit_status.success() {
             Ok(())
diff --git a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
index 4ad8e75970b..22f98ea7cd4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-def/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
index 2dc69b00ace..9c769690864 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -236,11 +236,19 @@ impl TraitData {
             .by_key("rustc_skip_array_during_method_dispatch")
             .exists();
 
-        let mut collector =
-            AssocItemCollector::new(db, module_id, tree_id.file_id(), ItemContainerId::TraitId(tr));
-        collector.collect(&item_tree, tree_id.tree_id(), &tr_def.items);
-        let (items, attribute_calls, diagnostics) = collector.finish();
-
+        let (items, attribute_calls, diagnostics) = match &tr_def.items {
+            Some(items) => {
+                let mut collector = AssocItemCollector::new(
+                    db,
+                    module_id,
+                    tree_id.file_id(),
+                    ItemContainerId::TraitId(tr),
+                );
+                collector.collect(&item_tree, tree_id.tree_id(), items);
+                collector.finish()
+            }
+            None => Default::default(),
+        };
         (
             Arc::new(TraitData {
                 name,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
index 570344596de..0aa531eff71 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs
@@ -666,7 +666,8 @@ pub struct Trait {
     pub generic_params: Interned<GenericParams>,
     pub is_auto: bool,
     pub is_unsafe: bool,
-    pub items: Box<[AssocItem]>,
+    /// This is [`None`] if this Trait is a trait alias.
+    pub items: Option<Box<[AssocItem]>>,
     pub ast_id: FileAstId<ast::Trait>,
 }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
index 79249757d9e..b25274bccc9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/lower.rs
@@ -451,15 +451,7 @@ impl<'a> Ctx<'a> {
                 .collect()
         });
         let ast_id = self.source_ast_id_map.ast_id(trait_def);
-        let res = Trait {
-            name,
-            visibility,
-            generic_params,
-            is_auto,
-            is_unsafe,
-            items: items.unwrap_or_default(),
-            ast_id,
-        };
+        let res = Trait { name, visibility, generic_params, is_auto, is_unsafe, items, ast_id };
         Some(id(self.data().traits.alloc(res)))
     }
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
index da1643152c2..48c40df22ff 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree/pretty.rs
@@ -375,12 +375,21 @@ impl<'a> Printer<'a> {
                 }
                 w!(self, "trait {}", name);
                 self.print_generic_params(generic_params);
-                self.print_where_clause_and_opening_brace(generic_params);
-                self.indented(|this| {
-                    for item in &**items {
-                        this.print_mod_item((*item).into());
+                match items {
+                    Some(items) => {
+                        self.print_where_clause_and_opening_brace(generic_params);
+                        self.indented(|this| {
+                            for item in &**items {
+                                this.print_mod_item((*item).into());
+                            }
+                        });
                     }
-                });
+                    None => {
+                        w!(self, " = ");
+                        // FIXME: Print the aliased traits
+                        self.print_where_clause_and_opening_brace(generic_params);
+                    }
+                }
                 wln!(self, "}}");
             }
             ModItem::Impl(it) => {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
index bc162d0fa20..fc90c6e9f37 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe/matching.rs
@@ -94,11 +94,11 @@ macro_rules! m {
     ($($s:stmt)*) => (stringify!($($s |)*);)
 }
 stringify!(;
-|;
-|92|;
-|let x = 92|;
+| ;
+|92| ;
+|let x = 92| ;
 |loop {}
-|;
+| ;
 |);
 "#]],
     );
@@ -118,7 +118,7 @@ m!(.. .. ..);
 macro_rules! m {
     ($($p:pat)*) => (stringify!($($p |)*);)
 }
-stringify!(.. .. ..|);
+stringify!(.. .. .. |);
 "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
index 029821e5e87..118c14ed843 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs
@@ -82,14 +82,14 @@ fn attribute_macro_syntax_completion_2() {
 #[proc_macros::identity_when_valid]
 fn foo() { bar.; blub }
 "#,
-        expect![[r##"
+        expect![[r#"
 #[proc_macros::identity_when_valid]
 fn foo() { bar.; blub }
 
 fn foo() {
-    bar.;
+    bar. ;
     blub
-}"##]],
+}"#]],
     );
 }
 
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 9ffc218818c..b0dd01f9dbe 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
@@ -212,6 +212,7 @@ impl Import {
 
 #[derive(Debug, Eq, PartialEq)]
 struct ImportDirective {
+    /// The module this import directive is in.
     module_id: LocalModuleId,
     import: Import,
     status: PartialResolvedImport,
@@ -963,8 +964,10 @@ impl DefCollector<'_> {
 
     fn update(
         &mut self,
+        // The module for which `resolutions` have been resolve
         module_id: LocalModuleId,
         resolutions: &[(Option<Name>, PerNs)],
+        // Visibility this import will have
         vis: Visibility,
         import_type: ImportType,
     ) {
@@ -974,6 +977,7 @@ impl DefCollector<'_> {
 
     fn update_recursive(
         &mut self,
+        // The module for which `resolutions` have been resolve
         module_id: LocalModuleId,
         resolutions: &[(Option<Name>, PerNs)],
         // All resolutions are imported with this visibility; the visibilities in
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
index 8dfda6df64e..20d39ec6cb9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs
@@ -73,7 +73,10 @@ impl DefMap {
     pub(crate) fn resolve_visibility(
         &self,
         db: &dyn DefDatabase,
+        // module to import to
         original_module: LocalModuleId,
+        // pub(path)
+        //     ^^^^ this
         visibility: &RawVisibility,
     ) -> Option<Visibility> {
         let mut vis = match visibility {
@@ -115,6 +118,7 @@ impl DefMap {
         &self,
         db: &dyn DefDatabase,
         mode: ResolveMode,
+        // module to import to
         mut original_module: LocalModuleId,
         path: &ModPath,
         shadow: BuiltinShadowMode,
@@ -361,6 +365,9 @@ impl DefMap {
                     );
                 }
             };
+
+            curr_per_ns = curr_per_ns
+                .filter_visibility(|vis| vis.is_visible_from_def_map(db, self, original_module));
         }
 
         ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
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 70dd2eb3ade..0d90047c28f 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
@@ -58,9 +58,9 @@ extern {
 "#,
         expect![[r#"
             crate
-            E: t
+            E: _
             S: t v
-            V: t v
+            V: _
             foo: t
 
             crate::foo
@@ -307,7 +307,7 @@ pub struct FromLib;
             Bar: t v
 
             crate::foo
-            Bar: t v
+            Bar: _
             FromLib: 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 b2a6a592cf3..88a3c76393f 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
@@ -119,7 +119,7 @@ use foo::*;
 use foo::bar::*;
 
 //- /foo/mod.rs
-mod bar;
+pub mod bar;
 fn Foo() {};
 pub struct Foo {};
 
@@ -132,6 +132,7 @@ pub(crate) struct PubCrateStruct;
             crate
             Foo: t
             PubCrateStruct: t v
+            bar: t
             foo: t
 
             crate::foo
@@ -336,3 +337,33 @@ mod d {
         "#]],
     );
 }
+
+#[test]
+fn glob_name_collision_check_visibility() {
+    check(
+        r#"
+mod event {
+    mod serenity {
+        pub fn Event() {}
+    }
+    use serenity::*;
+
+    pub struct Event {}
+}
+
+use event::Event;
+        "#,
+        expect![[r#"
+            crate
+            Event: t
+            event: t
+
+            crate::event
+            Event: t v
+            serenity: t
+
+            crate::event::serenity
+            Event: v
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
index ba3bf8b5a5c..c575bf7cac2 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/mod_resolution.rs
@@ -580,7 +580,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() {
 //- /main.rs
 mod foo {
     #[path = "baz.rs"]
-    mod bar;
+    pub mod bar;
 }
 use self::foo::bar::Baz;
 
diff --git a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
index 3359c99b396..77eb1fd4504 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-expand/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
index 893e6fe4b82..a4abe75626e 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs
@@ -4,6 +4,7 @@ use std::mem;
 
 use mbe::{SyntheticToken, SyntheticTokenId, TokenMap};
 use rustc_hash::FxHashMap;
+use smallvec::SmallVec;
 use syntax::{
     ast::{self, AstNode, HasLoopBody},
     match_ast, SyntaxElement, SyntaxKind, SyntaxNode, TextRange,
@@ -292,25 +293,34 @@ pub(crate) fn reverse_fixups(
     token_map: &TokenMap,
     undo_info: &SyntaxFixupUndoInfo,
 ) {
-    tt.token_trees.retain(|tt| match tt {
-        tt::TokenTree::Leaf(leaf) => {
-            token_map.synthetic_token_id(leaf.id()).is_none()
-                || token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID)
-        }
-        tt::TokenTree::Subtree(st) => st.delimiter.map_or(true, |d| {
-            token_map.synthetic_token_id(d.id).is_none()
-                || token_map.synthetic_token_id(d.id) != Some(EMPTY_ID)
-        }),
-    });
-    tt.token_trees.iter_mut().for_each(|tt| match tt {
-        tt::TokenTree::Subtree(tt) => reverse_fixups(tt, token_map, undo_info),
-        tt::TokenTree::Leaf(leaf) => {
-            if let Some(id) = token_map.synthetic_token_id(leaf.id()) {
-                let original = &undo_info.original[id.0 as usize];
-                *tt = tt::TokenTree::Subtree(original.clone());
+    let tts = std::mem::take(&mut tt.token_trees);
+    tt.token_trees = tts
+        .into_iter()
+        .filter(|tt| match tt {
+            tt::TokenTree::Leaf(leaf) => token_map.synthetic_token_id(leaf.id()) != Some(EMPTY_ID),
+            tt::TokenTree::Subtree(st) => {
+                st.delimiter.map_or(true, |d| token_map.synthetic_token_id(d.id) != Some(EMPTY_ID))
             }
-        }
-    });
+        })
+        .flat_map(|tt| match tt {
+            tt::TokenTree::Subtree(mut tt) => {
+                reverse_fixups(&mut tt, token_map, undo_info);
+                SmallVec::from_const([tt.into()])
+            }
+            tt::TokenTree::Leaf(leaf) => {
+                if let Some(id) = token_map.synthetic_token_id(leaf.id()) {
+                    let original = undo_info.original[id.0 as usize].clone();
+                    if original.delimiter.is_none() {
+                        original.token_trees.into()
+                    } else {
+                        SmallVec::from_const([original.into()])
+                    }
+                } else {
+                    SmallVec::from_const([leaf.into()])
+                }
+            }
+        })
+        .collect();
 }
 
 #[cfg(test)]
@@ -319,6 +329,31 @@ mod tests {
 
     use super::reverse_fixups;
 
+    // The following three functions are only meant to check partial structural equivalence of
+    // `TokenTree`s, see the last assertion in `check()`.
+    fn check_leaf_eq(a: &tt::Leaf, b: &tt::Leaf) -> bool {
+        match (a, b) {
+            (tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.text == b.text,
+            (tt::Leaf::Punct(a), tt::Leaf::Punct(b)) => a.char == b.char,
+            (tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.text == b.text,
+            _ => false,
+        }
+    }
+
+    fn check_subtree_eq(a: &tt::Subtree, b: &tt::Subtree) -> bool {
+        a.delimiter.map(|it| it.kind) == b.delimiter.map(|it| it.kind)
+            && a.token_trees.len() == b.token_trees.len()
+            && a.token_trees.iter().zip(&b.token_trees).all(|(a, b)| check_tt_eq(a, b))
+    }
+
+    fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool {
+        match (a, b) {
+            (tt::TokenTree::Leaf(a), tt::TokenTree::Leaf(b)) => check_leaf_eq(a, b),
+            (tt::TokenTree::Subtree(a), tt::TokenTree::Subtree(b)) => check_subtree_eq(a, b),
+            _ => false,
+        }
+    }
+
     #[track_caller]
     fn check(ra_fixture: &str, mut expect: Expect) {
         let parsed = syntax::SourceFile::parse(ra_fixture);
@@ -331,17 +366,15 @@ mod tests {
             fixups.append,
         );
 
-        let mut actual = tt.to_string();
-        actual.push('\n');
+        let actual = format!("{}\n", tt);
 
         expect.indent(false);
         expect.assert_eq(&actual);
 
         // the fixed-up tree should be syntactically valid
         let (parse, _) = mbe::token_tree_to_syntax_node(&tt, ::mbe::TopEntryPoint::MacroItems);
-        assert_eq!(
-            parse.errors(),
-            &[],
+        assert!(
+            parse.errors().is_empty(),
             "parse has syntax errors. parse tree:\n{:#?}",
             parse.syntax_node()
         );
@@ -349,9 +382,12 @@ mod tests {
         reverse_fixups(&mut tt, &tmap, &fixups.undo_info);
 
         // the fixed-up + reversed version should be equivalent to the original input
-        // (but token IDs don't matter)
+        // modulo token IDs and `Punct`s' spacing.
         let (original_as_tt, _) = mbe::syntax_node_to_token_tree(&parsed.syntax_node());
-        assert_eq!(tt.to_string(), original_as_tt.to_string());
+        assert!(
+            check_subtree_eq(&tt, &original_as_tt),
+            "different token tree: {tt:?}, {original_as_tt:?}"
+        );
     }
 
     #[test]
@@ -468,7 +504,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {a .__ra_fixup}
+fn foo () {a . __ra_fixup}
 "#]],
         )
     }
@@ -482,7 +518,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {a .__ra_fixup ;}
+fn foo () {a . __ra_fixup ;}
 "#]],
         )
     }
@@ -497,7 +533,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {a .__ra_fixup ; bar () ;}
+fn foo () {a . __ra_fixup ; bar () ;}
 "#]],
         )
     }
@@ -525,7 +561,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {let x = a .__ra_fixup ;}
+fn foo () {let x = a . __ra_fixup ;}
 "#]],
         )
     }
@@ -541,7 +577,7 @@ fn foo() {
 }
 "#,
             expect![[r#"
-fn foo () {a .b ; bar () ;}
+fn foo () {a . b ; bar () ;}
 "#]],
         )
     }
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
index a5b499fe8d9..7352b003a49 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs
@@ -814,7 +814,7 @@ impl<'a> InFile<&'a SyntaxNode> {
 
     pub fn original_syntax_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
         // This kind of upmapping can only be achieved in attribute expanded files,
-        // as we don't have node inputs otherwise and  therefor can't find an `N` node in the input
+        // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
         if !self.file_id.is_macro() {
             return Some(self.map(Clone::clone));
         } else if !self.file_id.is_attr_macro(db) {
@@ -926,7 +926,7 @@ impl<N: AstNode> InFile<N> {
 
     pub fn original_ast_node(self, db: &dyn db::AstDatabase) -> Option<InFile<N>> {
         // This kind of upmapping can only be achieved in attribute expanded files,
-        // as we don't have node inputs otherwise and  therefor can't find an `N` node in the input
+        // as we don't have node inputs otherwise and therefore can't find an `N` node in the input
         if !self.file_id.is_macro() {
             return Some(self);
         } else if !self.file_id.is_attr_macro(db) {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
index ed13275bab8..a1d6835bfae 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir-ty/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
index b68c764bdca..39514fc44e6 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -53,7 +53,7 @@ pub use builder::{ParamKind, TyBuilder};
 pub use chalk_ext::*;
 pub use infer::{
     could_coerce, could_unify, Adjust, Adjustment, AutoBorrow, BindingMode, InferenceDiagnostic,
-    InferenceResult,
+    InferenceResult, OverloadedDeref, PointerCast,
 };
 pub use interner::Interner;
 pub use lower::{
@@ -523,7 +523,7 @@ where
 }
 
 pub fn callable_sig_from_fnonce(
-    self_ty: &Canonical<Ty>,
+    self_ty: &Ty,
     env: Arc<TraitEnvironment>,
     db: &dyn HirDatabase,
 ) -> Option<CallableSig> {
@@ -531,27 +531,28 @@ pub fn callable_sig_from_fnonce(
     let fn_once_trait = FnTrait::FnOnce.get_id(db, krate)?;
     let output_assoc_type = db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
 
-    let mut kinds = self_ty.binders.interned().to_vec();
     let b = TyBuilder::trait_ref(db, fn_once_trait);
     if b.remaining() != 2 {
         return None;
     }
-    let fn_once = b
-        .push(self_ty.value.clone())
-        .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
-        .build();
-    kinds.extend(fn_once.substitution.iter(Interner).skip(1).map(|x| {
-        let vk = match x.data(Interner) {
-            chalk_ir::GenericArgData::Ty(_) => {
-                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
-            }
-            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
-            chalk_ir::GenericArgData::Const(c) => {
-                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
-            }
-        };
-        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
-    }));
+    let fn_once = b.push(self_ty.clone()).fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
+    let kinds = fn_once
+        .substitution
+        .iter(Interner)
+        .skip(1)
+        .map(|x| {
+            let vk = match x.data(Interner) {
+                chalk_ir::GenericArgData::Ty(_) => {
+                    chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
+                }
+                chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+                chalk_ir::GenericArgData::Const(c) => {
+                    chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
+                }
+            };
+            chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
+        })
+        .collect::<Vec<_>>();
 
     // FIXME: chalk refuses to solve `<Self as FnOnce<^0.0>>::Output == ^0.1`, so we first solve
     // `<Self as FnOnce<^0.0>>` and then replace `^0.0` with the concrete argument tuple.
@@ -563,21 +564,16 @@ pub fn callable_sig_from_fnonce(
         Some(Solution::Unique(vars)) => vars.value.subst,
         _ => return None,
     };
-    let args = subst.at(Interner, self_ty.binders.interned().len()).ty(Interner)?;
+    let args = subst.at(Interner, 0).ty(Interner)?;
     let params = match args.kind(Interner) {
         chalk_ir::TyKind::Tuple(_, subst) => {
             subst.iter(Interner).filter_map(|arg| arg.ty(Interner).cloned()).collect::<Vec<_>>()
         }
         _ => return None,
     };
-    if params.iter().any(|ty| ty.is_unknown()) {
-        return None;
-    }
 
-    let fn_once = TyBuilder::trait_ref(db, fn_once_trait)
-        .push(self_ty.value.clone())
-        .push(args.clone())
-        .build();
+    let fn_once =
+        TyBuilder::trait_ref(db, fn_once_trait).push(self_ty.clone()).push(args.clone()).build();
     let projection =
         TyBuilder::assoc_type_projection(db, output_assoc_type, Some(fn_once.substitution.clone()))
             .build();
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 50859475e1d..8bcfa2728f0 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
@@ -541,7 +541,7 @@ pub struct ReceiverAdjustments {
 
 impl ReceiverAdjustments {
     pub(crate) fn apply(&self, table: &mut InferenceTable<'_>, ty: Ty) -> (Ty, Vec<Adjustment>) {
-        let mut ty = ty;
+        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()) {
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 ac8edb841a5..5d76d185ffc 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
@@ -164,16 +164,16 @@ fn infer_associated_method_with_modules() {
     check_infer(
         r#"
         mod a {
-            struct A;
+            pub struct A;
             impl A { pub fn thing() -> A { A {} }}
         }
 
         mod b {
-            struct B;
+            pub struct B;
             impl B { pub fn thing() -> u32 { 99 }}
 
-            mod c {
-                struct C;
+            pub mod c {
+                pub struct C;
                 impl C { pub fn thing() -> C { C {} }}
             }
         }
@@ -186,22 +186,22 @@ fn infer_associated_method_with_modules() {
         }
         "#,
         expect![[r#"
-            55..63 '{ A {} }': A
-            57..61 'A {}': A
-            125..131 '{ 99 }': u32
-            127..129 '99': u32
-            201..209 '{ C {} }': C
-            203..207 'C {}': C
-            240..324 '{     ...g(); }': ()
-            250..251 'x': A
-            254..265 'a::A::thing': fn thing() -> A
-            254..267 'a::A::thing()': A
-            277..278 'y': u32
-            281..292 'b::B::thing': fn thing() -> u32
-            281..294 'b::B::thing()': u32
-            304..305 'z': C
-            308..319 'c::C::thing': fn thing() -> C
-            308..321 'c::C::thing()': C
+            59..67 '{ A {} }': A
+            61..65 'A {}': A
+            133..139 '{ 99 }': u32
+            135..137 '99': u32
+            217..225 '{ C {} }': C
+            219..223 'C {}': C
+            256..340 '{     ...g(); }': ()
+            266..267 'x': A
+            270..281 'a::A::thing': fn thing() -> A
+            270..283 'a::A::thing()': A
+            293..294 'y': u32
+            297..308 'b::B::thing': fn thing() -> u32
+            297..310 'b::B::thing()': u32
+            320..321 'z': C
+            324..335 'c::C::thing': fn thing() -> C
+            324..337 'c::C::thing()': C
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
index a155adcec6c..4e46397459d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/regression.rs
@@ -1707,3 +1707,19 @@ impl<T, const N: usize> Trait for [T; N] {
         "#,
     );
 }
+
+#[test]
+fn unsize_array_with_inference_variable() {
+    check_types(
+        r#"
+//- minicore: try, slice
+use core::ops::ControlFlow;
+fn foo() -> ControlFlow<(), [usize; 1]> { loop {} }
+fn bar() -> ControlFlow<(), ()> {
+    let a = foo()?.len();
+      //^ usize
+    ControlFlow::Continue(())
+}
+"#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 080e2ac1b8e..d7431443b83 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -214,7 +214,7 @@ fn infer_paths() {
 fn a() -> u32 { 1 }
 
 mod b {
-    fn c() -> u32 { 1 }
+    pub fn c() -> u32 { 1 }
 }
 
 fn test() {
@@ -225,13 +225,13 @@ fn test() {
         expect![[r#"
             14..19 '{ 1 }': u32
             16..17 '1': u32
-            47..52 '{ 1 }': u32
-            49..50 '1': u32
-            66..90 '{     ...c(); }': ()
-            72..73 'a': fn a() -> u32
-            72..75 'a()': u32
-            81..85 'b::c': fn c() -> u32
-            81..87 'b::c()': u32
+            51..56 '{ 1 }': u32
+            53..54 '1': u32
+            70..94 '{     ...c(); }': ()
+            76..77 'a': fn a() -> u32
+            76..79 'a()': u32
+            85..89 'b::c': fn c() -> u32
+            85..91 'b::c()': u32
         "#]],
     );
 }
@@ -1856,7 +1856,7 @@ fn not_shadowing_module_by_primitive() {
     check_types(
         r#"
 //- /str.rs
-fn foo() -> u32 {0}
+pub fn foo() -> u32 {0}
 
 //- /main.rs
 mod str;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 7d42b8b9bc8..3d7194b6f44 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -1706,7 +1706,7 @@ fn where_clause_trait_in_scope_for_method_resolution() {
     check_types(
         r#"
 mod foo {
-    trait Trait {
+    pub trait Trait {
         fn foo(&self) -> u32 { 0 }
     }
 }
@@ -1723,7 +1723,7 @@ fn super_trait_method_resolution() {
     check_infer(
         r#"
 mod foo {
-    trait SuperTrait {
+    pub trait SuperTrait {
         fn foo(&self) -> u32 {}
     }
 }
@@ -1735,15 +1735,15 @@ fn test<T: Trait1, U: Trait2>(x: T, y: U) {
     y.foo();
 }"#,
         expect![[r#"
-            49..53 'self': &Self
-            62..64 '{}': u32
-            181..182 'x': T
-            187..188 'y': U
-            193..222 '{     ...o(); }': ()
-            199..200 'x': T
-            199..206 'x.foo()': u32
-            212..213 'y': U
-            212..219 'y.foo()': u32
+            53..57 'self': &Self
+            66..68 '{}': u32
+            185..186 'x': T
+            191..192 'y': U
+            197..226 '{     ...o(); }': ()
+            203..204 'x': T
+            203..210 'x.foo()': u32
+            216..217 'y': U
+            216..223 'y.foo()': u32
         "#]],
     );
 }
@@ -1754,7 +1754,7 @@ fn super_trait_impl_trait_method_resolution() {
         r#"
 //- minicore: sized
 mod foo {
-    trait SuperTrait {
+    pub trait SuperTrait {
         fn foo(&self) -> u32 {}
     }
 }
@@ -1764,12 +1764,12 @@ fn test(x: &impl Trait1) {
     x.foo();
 }"#,
         expect![[r#"
-            49..53 'self': &Self
-            62..64 '{}': u32
-            115..116 'x': &impl Trait1
-            132..148 '{     ...o(); }': ()
-            138..139 'x': &impl Trait1
-            138..145 'x.foo()': u32
+            53..57 'self': &Self
+            66..68 '{}': u32
+            119..120 'x': &impl Trait1
+            136..152 '{     ...o(); }': ()
+            142..143 'x': &impl Trait1
+            142..149 'x.foo()': u32
         "#]],
     );
 }
diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml
index e1418de3cdc..f780e3f53c8 100644
--- a/src/tools/rust-analyzer/crates/hir/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index cbd9bf32a54..cbbcaebb428 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -117,7 +117,7 @@ pub use {
         name::{known, Name},
         ExpandResult, HirFileId, InFile, MacroFile, Origin,
     },
-    hir_ty::display::HirDisplay,
+    hir_ty::{display::HirDisplay, PointerCast, Safety},
 };
 
 // These are negative re-exports: pub using these names is forbidden, they
@@ -2997,8 +2997,7 @@ impl Type {
             TyKind::Function(_) => Callee::FnPtr,
             TyKind::FnDef(..) => Callee::Def(self.ty.callable_def(db)?),
             _ => {
-                let ty = hir_ty::replace_errors_with_variables(&self.ty);
-                let sig = hir_ty::callable_sig_from_fnonce(&ty, self.env.clone(), db)?;
+                let sig = hir_ty::callable_sig_from_fnonce(&self.ty, self.env.clone(), db)?;
                 return Some(Callable {
                     ty: self.clone(),
                     sig,
@@ -3651,6 +3650,28 @@ impl From<ItemInNs> for ScopeDef {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum Adjust {
+    /// Go from ! to any type.
+    NeverToAny,
+    /// Dereference once, producing a place.
+    Deref(Option<OverloadedDeref>),
+    /// Take the address and produce either a `&` or `*` pointer.
+    Borrow(AutoBorrow),
+    Pointer(PointerCast),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub enum AutoBorrow {
+    /// Converts from T to &T.
+    Ref(Mutability),
+    /// Converts from T to *T.
+    RawPtr(Mutability),
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct OverloadedDeref(pub Mutability);
+
 pub trait HasVisibility {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility;
     fn is_visible_from(&self, db: &dyn HirDatabase, module: Module) -> bool {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 119ec3210e1..2e1f88ba090 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -29,9 +29,10 @@ use crate::{
     db::HirDatabase,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    Access, BindingMode, BuiltinAttr, Callable, ConstParam, Crate, DeriveHelper, Field, Function,
-    HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
-    Name, Path, ScopeDef, ToolModule, Trait, Type, TypeAlias, TypeParam, VariantDef,
+    Access, Adjust, AutoBorrow, BindingMode, BuiltinAttr, Callable, ConstParam, Crate,
+    DeriveHelper, Field, Function, HasSource, HirFileId, Impl, InFile, Label, LifetimeParam, Local,
+    Macro, Module, ModuleDef, Name, OverloadedDeref, Path, ScopeDef, ToolModule, Trait, Type,
+    TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -333,9 +334,8 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_trait(trait_)
     }
 
-    // FIXME: Figure out a nice interface to inspect adjustments
-    pub fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
-        self.imp.is_implicit_reborrow(expr)
+    pub fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+        self.imp.expr_adjustments(expr)
     }
 
     pub fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
@@ -1067,8 +1067,29 @@ impl<'db> SemanticsImpl<'db> {
         }
     }
 
-    fn is_implicit_reborrow(&self, expr: &ast::Expr) -> Option<Mutability> {
-        self.analyze(expr.syntax())?.is_implicit_reborrow(self.db, expr)
+    fn expr_adjustments(&self, expr: &ast::Expr) -> Option<Vec<Adjust>> {
+        let mutability = |m| match m {
+            hir_ty::Mutability::Not => Mutability::Shared,
+            hir_ty::Mutability::Mut => Mutability::Mut,
+        };
+        self.analyze(expr.syntax())?.expr_adjustments(self.db, expr).map(|it| {
+            it.iter()
+                .map(|adjust| match adjust.kind {
+                    hir_ty::Adjust::NeverToAny => Adjust::NeverToAny,
+                    hir_ty::Adjust::Deref(Some(hir_ty::OverloadedDeref(m))) => {
+                        Adjust::Deref(Some(OverloadedDeref(mutability(m))))
+                    }
+                    hir_ty::Adjust::Deref(None) => Adjust::Deref(None),
+                    hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::RawPtr(m)) => {
+                        Adjust::Borrow(AutoBorrow::RawPtr(mutability(m)))
+                    }
+                    hir_ty::Adjust::Borrow(hir_ty::AutoBorrow::Ref(m)) => {
+                        Adjust::Borrow(AutoBorrow::Ref(mutability(m)))
+                    }
+                    hir_ty::Adjust::Pointer(pc) => Adjust::Pointer(pc),
+                })
+                .collect()
+        })
     }
 
     fn type_of_expr(&self, expr: &ast::Expr) -> Option<TypeInfo> {
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 f86c5710053..91ea1c24d14 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -38,8 +38,7 @@ use hir_ty::{
         UnsafeExpr,
     },
     method_resolution::{self, lang_names_for_bin_op},
-    Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind,
-    TyLoweringContext,
+    Adjustment, InferenceResult, Interner, Substitution, Ty, TyExt, TyKind, TyLoweringContext,
 };
 use itertools::Itertools;
 use smallvec::SmallVec;
@@ -156,21 +155,14 @@ impl SourceAnalyzer {
         Some(res)
     }
 
-    pub(crate) fn is_implicit_reborrow(
+    pub(crate) fn expr_adjustments(
         &self,
         db: &dyn HirDatabase,
         expr: &ast::Expr,
-    ) -> Option<Mutability> {
+    ) -> Option<&[Adjustment]> {
         let expr_id = self.expr_id(db, expr)?;
         let infer = self.infer.as_ref()?;
-        let adjustments = infer.expr_adjustments.get(&expr_id)?;
-        adjustments.windows(2).find_map(|slice| match slice {
-            &[Adjustment {kind: Adjust::Deref(None), ..}, Adjustment {kind: Adjust::Borrow(AutoBorrow::Ref(m)), ..}] => Some(match m {
-                hir_ty::Mutability::Mut => Mutability::Mut,
-                hir_ty::Mutability::Not => Mutability::Shared,
-            }),
-            _ => None,
-        })
+        infer.expr_adjustments.get(&expr_id).map(|v| &**v)
     }
 
     pub(crate) fn type_of_expr(
diff --git a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
index 57a41f3d9a9..e781c0a016d 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-assists/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
index 62cf5ab4f37..2b3793659cf 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/add_missing_impl_members.rs
@@ -196,6 +196,7 @@ trait Foo {
     type Output;
 
     const CONST: usize = 42;
+    const CONST_2: i32;
 
     fn foo(&self);
     fn bar(&self);
@@ -213,6 +214,7 @@ trait Foo {
     type Output;
 
     const CONST: usize = 42;
+    const CONST_2: i32;
 
     fn foo(&self);
     fn bar(&self);
@@ -226,7 +228,7 @@ impl Foo for S {
 
     $0type Output;
 
-    const CONST: usize = 42;
+    const CONST_2: i32;
 
     fn foo(&self) {
         todo!()
@@ -379,14 +381,14 @@ impl Foo for S {
             r#"
 mod foo {
     pub struct Bar;
-    trait Foo { fn foo(&self, bar: Bar); }
+    pub trait Foo { fn foo(&self, bar: Bar); }
 }
 struct S;
 impl foo::Foo for S { $0 }"#,
             r#"
 mod foo {
     pub struct Bar;
-    trait Foo { fn foo(&self, bar: Bar); }
+    pub trait Foo { fn foo(&self, bar: Bar); }
 }
 struct S;
 impl foo::Foo for S {
@@ -439,14 +441,14 @@ impl bar::Foo for S {
             r#"
 mod foo {
     pub struct Bar<T>;
-    trait Foo { fn foo(&self, bar: Bar<u32>); }
+    pub trait Foo { fn foo(&self, bar: Bar<u32>); }
 }
 struct S;
 impl foo::Foo for S { $0 }"#,
             r#"
 mod foo {
     pub struct Bar<T>;
-    trait Foo { fn foo(&self, bar: Bar<u32>); }
+    pub trait Foo { fn foo(&self, bar: Bar<u32>); }
 }
 struct S;
 impl foo::Foo for S {
@@ -464,14 +466,14 @@ impl foo::Foo for S {
             r#"
 mod foo {
     pub struct Bar<T>;
-    trait Foo<T> { fn foo(&self, bar: Bar<T>); }
+    pub trait Foo<T> { fn foo(&self, bar: Bar<T>); }
 }
 struct S;
 impl foo::Foo<u32> for S { $0 }"#,
             r#"
 mod foo {
     pub struct Bar<T>;
-    trait Foo<T> { fn foo(&self, bar: Bar<T>); }
+    pub trait Foo<T> { fn foo(&self, bar: Bar<T>); }
 }
 struct S;
 impl foo::Foo<u32> for S {
@@ -489,7 +491,7 @@ impl foo::Foo<u32> for S {
             add_missing_impl_members,
             r#"
 mod foo {
-    trait Foo<T> { fn foo(&self, bar: T); }
+    pub trait Foo<T> { fn foo(&self, bar: T); }
     pub struct Param;
 }
 struct Param;
@@ -497,7 +499,7 @@ struct S;
 impl foo::Foo<Param> for S { $0 }"#,
             r#"
 mod foo {
-    trait Foo<T> { fn foo(&self, bar: T); }
+    pub trait Foo<T> { fn foo(&self, bar: T); }
     pub struct Param;
 }
 struct Param;
@@ -518,7 +520,7 @@ impl foo::Foo<Param> for S {
 mod foo {
     pub struct Bar<T>;
     impl Bar<T> { type Assoc = u32; }
-    trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
+    pub trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
 }
 struct S;
 impl foo::Foo for S { $0 }"#,
@@ -526,7 +528,7 @@ impl foo::Foo for S { $0 }"#,
 mod foo {
     pub struct Bar<T>;
     impl Bar<T> { type Assoc = u32; }
-    trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
+    pub trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); }
 }
 struct S;
 impl foo::Foo for S {
@@ -545,7 +547,7 @@ impl foo::Foo for S {
 mod foo {
     pub struct Bar<T>;
     pub struct Baz;
-    trait Foo { fn foo(&self, bar: Bar<Baz>); }
+    pub trait Foo { fn foo(&self, bar: Bar<Baz>); }
 }
 struct S;
 impl foo::Foo for S { $0 }"#,
@@ -553,7 +555,7 @@ impl foo::Foo for S { $0 }"#,
 mod foo {
     pub struct Bar<T>;
     pub struct Baz;
-    trait Foo { fn foo(&self, bar: Bar<Baz>); }
+    pub trait Foo { fn foo(&self, bar: Bar<Baz>); }
 }
 struct S;
 impl foo::Foo for S {
@@ -571,14 +573,14 @@ impl foo::Foo for S {
             r#"
 mod foo {
     pub trait Fn<Args> { type Output; }
-    trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
+    pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
 }
 struct S;
 impl foo::Foo for S { $0 }"#,
             r#"
 mod foo {
     pub trait Fn<Args> { type Output; }
-    trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
+    pub trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); }
 }
 struct S;
 impl foo::Foo for S {
@@ -658,6 +660,7 @@ trait Foo {
     type Output;
 
     const CONST: usize = 42;
+    const CONST_2: i32;
 
     fn valid(some: u32) -> bool { false }
     fn foo(some: u32) -> bool;
@@ -669,13 +672,16 @@ trait Foo {
     type Output;
 
     const CONST: usize = 42;
+    const CONST_2: i32;
 
     fn valid(some: u32) -> bool { false }
     fn foo(some: u32) -> bool;
 }
 struct S;
 impl Foo for S {
-    $0fn valid(some: u32) -> bool { false }
+    $0const CONST: usize = 42;
+
+    fn valid(some: u32) -> bool { false }
 }"#,
         )
     }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
index 06058835849..c1e2f19ab18 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/extract_function.rs
@@ -109,8 +109,6 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
             let params =
                 body.extracted_function_params(ctx, &container_info, locals_used.iter().copied());
 
-            let extracted_from_trait_impl = body.extracted_from_trait_impl();
-
             let name = make_function_name(&semantics_scope);
 
             let fun = Function {
@@ -129,8 +127,11 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
 
             builder.replace(target_range, make_call(ctx, &fun, old_indent));
 
+            let has_impl_wrapper =
+                insert_after.ancestors().any(|a| a.kind() == SyntaxKind::IMPL && a != insert_after);
+
             let fn_def = match fun.self_param_adt(ctx) {
-                Some(adt) if extracted_from_trait_impl => {
+                Some(adt) if anchor == Anchor::Method && !has_impl_wrapper => {
                     let fn_def = format_function(ctx, module, &fun, old_indent, new_indent + 1);
                     generate_impl_text(&adt, &fn_def).replace("{\n\n", "{")
                 }
@@ -272,7 +273,7 @@ enum FunType {
 }
 
 /// Where to put extracted function definition
-#[derive(Debug)]
+#[derive(Debug, Eq, PartialEq, Clone, Copy)]
 enum Anchor {
     /// Extract free function and put right after current top-level function
     Freestanding,
@@ -1245,6 +1246,14 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNod
     while let Some(next_ancestor) = ancestors.next() {
         match next_ancestor.kind() {
             SyntaxKind::SOURCE_FILE => break,
+            SyntaxKind::IMPL => {
+                if body.extracted_from_trait_impl() && matches!(anchor, Anchor::Method) {
+                    let impl_node = find_non_trait_impl(&next_ancestor);
+                    if let target_node @ Some(_) = impl_node.as_ref().and_then(last_impl_member) {
+                        return target_node;
+                    }
+                }
+            }
             SyntaxKind::ITEM_LIST if !matches!(anchor, Anchor::Freestanding) => continue,
             SyntaxKind::ITEM_LIST => {
                 if ancestors.peek().map(SyntaxNode::kind) == Some(SyntaxKind::MODULE) {
@@ -1265,6 +1274,29 @@ fn node_to_insert_after(body: &FunctionBody, anchor: Anchor) -> Option<SyntaxNod
     last_ancestor
 }
 
+fn find_non_trait_impl(trait_impl: &SyntaxNode) -> Option<ast::Impl> {
+    let as_impl = ast::Impl::cast(trait_impl.clone())?;
+    let impl_type = Some(impl_type_name(&as_impl)?);
+
+    let sibblings = trait_impl.parent()?.children();
+    sibblings
+        .filter_map(ast::Impl::cast)
+        .find(|s| impl_type_name(s) == impl_type && !is_trait_impl(s))
+}
+
+fn last_impl_member(impl_node: &ast::Impl) -> Option<SyntaxNode> {
+    let last_child = impl_node.assoc_item_list()?.assoc_items().last()?;
+    Some(last_child.syntax().clone())
+}
+
+fn is_trait_impl(node: &ast::Impl) -> bool {
+    node.trait_().is_some()
+}
+
+fn impl_type_name(impl_node: &ast::Impl) -> Option<String> {
+    Some(impl_node.self_ty()?.to_string())
+}
+
 fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> String {
     let ret_ty = fun.return_type(ctx);
 
@@ -5052,6 +5084,236 @@ impl Struct {
     }
 
     #[test]
+    fn extract_method_from_trait_with_existing_non_empty_impl_block() {
+        check_assist(
+            extract_function,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl Struct {
+    fn foo() {}
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        $0self.0 + 2$0
+    }
+}
+"#,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl Struct {
+    fn foo() {}
+
+    fn $0fun_name(&self) -> i32 {
+        self.0 + 2
+    }
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        self.fun_name()
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn extract_function_from_trait_with_existing_non_empty_impl_block() {
+        check_assist(
+            extract_function,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl Struct {
+    fn foo() {}
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        let three_squared = $03 * 3$0;
+        self.0 + three_squared
+    }
+}
+"#,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl Struct {
+    fn foo() {}
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        let three_squared = fun_name();
+        self.0 + three_squared
+    }
+}
+
+fn $0fun_name() -> i32 {
+    3 * 3
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn extract_method_from_trait_with_multiple_existing_impl_blocks() {
+        check_assist(
+            extract_function,
+            r#"
+struct Struct(i32);
+struct StructBefore(i32);
+struct StructAfter(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl StructBefore {
+    fn foo(){}
+}
+
+impl Struct {
+    fn foo(){}
+}
+
+impl StructAfter {
+    fn foo(){}
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        $0self.0 + 2$0
+    }
+}
+"#,
+            r#"
+struct Struct(i32);
+struct StructBefore(i32);
+struct StructAfter(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+
+impl StructBefore {
+    fn foo(){}
+}
+
+impl Struct {
+    fn foo(){}
+
+    fn $0fun_name(&self) -> i32 {
+        self.0 + 2
+    }
+}
+
+impl StructAfter {
+    fn foo(){}
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        self.fun_name()
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
+    fn extract_method_from_trait_with_multiple_existing_trait_impl_blocks() {
+        check_assist(
+            extract_function,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+trait TraitBefore {
+    fn before(&self) -> i32;
+}
+trait TraitAfter {
+    fn after(&self) -> i32;
+}
+
+impl TraitBefore for Struct {
+    fn before(&self) -> i32 {
+        42
+    }
+}
+
+impl Struct {
+    fn foo(){}
+}
+
+impl TraitAfter for Struct {
+    fn after(&self) -> i32 {
+        42
+    }
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        $0self.0 + 2$0
+    }
+}
+"#,
+            r#"
+struct Struct(i32);
+trait Trait {
+    fn bar(&self) -> i32;
+}
+trait TraitBefore {
+    fn before(&self) -> i32;
+}
+trait TraitAfter {
+    fn after(&self) -> i32;
+}
+
+impl TraitBefore for Struct {
+    fn before(&self) -> i32 {
+        42
+    }
+}
+
+impl Struct {
+    fn foo(){}
+
+    fn $0fun_name(&self) -> i32 {
+        self.0 + 2
+    }
+}
+
+impl TraitAfter for Struct {
+    fn after(&self) -> i32 {
+        42
+    }
+}
+
+impl Trait for Struct {
+    fn bar(&self) -> i32 {
+        self.fun_name()
+    }
+}
+"#,
+        )
+    }
+
+    #[test]
     fn closure_arguments() {
         check_assist(
             extract_function,
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 87645430287..d9e00435ecf 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
@@ -1,4 +1,4 @@
-use hir::{db::HirDatabase, HasSource, HasVisibility, PathResolution};
+use hir::{db::HirDatabase, HasSource, HasVisibility, ModuleDef, PathResolution, ScopeDef};
 use ide_db::base_db::FileId;
 use syntax::{
     ast::{self, HasVisibility as _},
@@ -18,7 +18,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
 //     fn frobnicate() {}
 // }
 // fn main() {
-//     m::frobnicate$0() {}
+//     m::frobnicate$0();
 // }
 // ```
 // ->
@@ -27,7 +27,7 @@ use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
 //     $0pub(crate) fn frobnicate() {}
 // }
 // fn main() {
-//     m::frobnicate() {}
+//     m::frobnicate();
 // }
 // ```
 pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
@@ -37,11 +37,15 @@ pub(crate) fn fix_visibility(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
 
 fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let path: ast::Path = ctx.find_node_at_offset()?;
-    let path_res = ctx.sema.resolve_path(&path)?;
-    let def = match path_res {
-        PathResolution::Def(def) => def,
-        _ => return None,
-    };
+    let qualifier = path.qualifier()?;
+    let name_ref = path.segment()?.name_ref()?;
+    let qualifier_res = ctx.sema.resolve_path(&qualifier)?;
+    let PathResolution::Def(ModuleDef::Module(module)) = qualifier_res else { return None; };
+    let (_, def) = module
+        .scope(ctx.db(), None)
+        .into_iter()
+        .find(|(name, _)| name.to_smol_str() == name_ref.text().as_str())?;
+    let ScopeDef::ModuleDef(def) = def else { return None; };
 
     let current_module = ctx.sema.scope(path.syntax())?.module();
     let target_module = def.module(ctx.db())?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
index 35cd42908af..0bcb5728311 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_enum_variant.rs
@@ -261,12 +261,12 @@ fn main() {
 }
 
 //- /foo.rs
-enum Foo {
+pub enum Foo {
     Bar,
 }
 ",
             r"
-enum Foo {
+pub enum Foo {
     Bar,
     Baz,
 }
@@ -310,7 +310,7 @@ fn main() {
             generate_enum_variant,
             r"
 mod m {
-    enum Foo {
+    pub enum Foo {
         Bar,
     }
 }
@@ -320,7 +320,7 @@ fn main() {
 ",
             r"
 mod m {
-    enum Foo {
+    pub enum Foo {
         Bar,
         Baz,
     }
@@ -516,10 +516,10 @@ mod foo;
 use foo::Foo::Bar$0;
 
 //- /foo.rs
-enum Foo {}
+pub enum Foo {}
 ",
             r"
-enum Foo {
+pub enum Foo {
     Bar,
 }
 ",
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
index c229127e48f..57f198748cb 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_function.rs
@@ -1324,7 +1324,7 @@ fn foo() {
             generate_function,
             r"
 mod bar {
-    mod baz {}
+    pub mod baz {}
 }
 
 fn foo() {
@@ -1333,7 +1333,7 @@ fn foo() {
 ",
             r"
 mod bar {
-    mod baz {
+    pub mod baz {
         pub(crate) fn my_fn() {
             ${0:todo!()}
         }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs
index aa710d2ce65..11db6ae7f7b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/move_format_string_arg.rs
@@ -92,7 +92,7 @@ pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>)
                         NodeOrToken::Node(n) => {
                             format_to!(current_arg, "{n}");
                         },
-                        NodeOrToken::Token(t) if t.kind() == COMMA=> {
+                        NodeOrToken::Token(t) if t.kind() == COMMA => {
                             existing_args.push(current_arg.trim().into());
                             current_arg.clear();
                         },
@@ -238,14 +238,14 @@ fn main() {
             &add_macro_decl(
                 r#"
 fn main() {
-    print!("{} {x + 1:b} {Struct(1, 2)}$0", 1);
+    print!("{:b} {x + 1:b} {Struct(1, 2)}$0", 1);
 }
 "#,
             ),
             &add_macro_decl(
                 r#"
 fn main() {
-    print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
+    print!("{:b} {:b} {}"$0, 1, x + 1, Struct(1, 2));
 }
 "#,
             ),
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
index 3d9cbff177b..99ae60e07bc 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_dbg.rs
@@ -1,7 +1,7 @@
 use itertools::Itertools;
 use syntax::{
     ast::{self, AstNode, AstToken},
-    match_ast, NodeOrToken, SyntaxElement, TextSize, T,
+    match_ast, NodeOrToken, SyntaxElement, TextRange, TextSize, T,
 };
 
 use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -22,7 +22,36 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 // }
 // ```
 pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
+    let macro_calls = if ctx.has_empty_selection() {
+        vec![ctx.find_node_at_offset::<ast::MacroCall>()?]
+    } else {
+        ctx.covering_element()
+            .as_node()?
+            .descendants()
+            .filter(|node| ctx.selection_trimmed().contains_range(node.text_range()))
+            .filter_map(ast::MacroCall::cast)
+            .collect()
+    };
+
+    let replacements =
+        macro_calls.into_iter().filter_map(compute_dbg_replacement).collect::<Vec<_>>();
+    if replacements.is_empty() {
+        return None;
+    }
+
+    acc.add(
+        AssistId("remove_dbg", AssistKind::Refactor),
+        "Remove dbg!()",
+        ctx.selection_trimmed(),
+        |builder| {
+            for (range, text) in replacements {
+                builder.replace(range, text);
+            }
+        },
+    )
+}
+
+fn compute_dbg_replacement(macro_call: ast::MacroCall) -> Option<(TextRange, String)> {
     let tt = macro_call.token_tree()?;
     let r_delim = NodeOrToken::Token(tt.right_delimiter_token()?);
     if macro_call.path()?.segment()?.name_ref()?.text() != "dbg"
@@ -41,7 +70,7 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
 
     let macro_expr = ast::MacroExpr::cast(macro_call.syntax().parent()?)?;
     let parent = macro_expr.syntax().parent()?;
-    let (range, text) = match &*input_expressions {
+    Some(match &*input_expressions {
         // dbg!()
         [] => {
             match_ast! {
@@ -107,10 +136,6 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
         }
         // dbg!(expr0, expr1, ...)
         exprs => (macro_call.syntax().text_range(), format!("({})", exprs.iter().format(", "))),
-    };
-
-    acc.add(AssistId("remove_dbg", AssistKind::Refactor), "Remove dbg!()", range, |builder| {
-        builder.replace(range, text);
     })
 }
 
@@ -238,4 +263,28 @@ fn foo() {
         check(r#"$0dbg!(0, 1)"#, r#"(0, 1)"#);
         check(r#"$0dbg!(0, (1, 2))"#, r#"(0, (1, 2))"#);
     }
+
+    #[test]
+    fn test_range() {
+        check(
+            r#"
+fn f() {
+    dbg!(0) + $0dbg!(1);
+    dbg!(())$0
+}
+"#,
+            r#"
+fn f() {
+    dbg!(0) + 1;
+    ()
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_range_partial() {
+        check_assist_not_applicable(remove_dbg, r#"$0dbg$0!(0)"#);
+        check_assist_not_applicable(remove_dbg, r#"$0dbg!(0$0)"#);
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index f9ba289ee17..6fa15b28e4e 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -1019,8 +1019,6 @@ struct Foo {
 impl foo::Bar for Foo {
     $0type Qux;
 
-    const Baz: usize = 42;
-
     const Fez: usize;
 
     fn foo() {
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 029d169899b..c09317572ac 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -741,7 +741,7 @@ mod m {
     fn frobnicate() {}
 }
 fn main() {
-    m::frobnicate$0() {}
+    m::frobnicate$0();
 }
 "#####,
         r#####"
@@ -749,7 +749,7 @@ mod m {
     $0pub(crate) fn frobnicate() {}
 }
 fn main() {
-    m::frobnicate() {}
+    m::frobnicate();
 }
 "#####,
     )
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 307e6792705..68c31b4f8e9 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -119,6 +119,10 @@ pub fn filter_assoc_items(
                 (default_methods, def.body()),
                 (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
             ),
+            ast::AssocItem::Const(def) => matches!(
+                (default_methods, def.body()),
+                (DefaultMethods::Only, Some(_)) | (DefaultMethods::No, None)
+            ),
             _ => default_methods == DefaultMethods::No,
         })
         .collect::<Vec<_>>()
diff --git a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
index 75835bce95d..11310e2f129 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-completion/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
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 e82cbfdcb84..7384a3f2d80 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
@@ -157,7 +157,7 @@ fn complete_trait_impl(
                     add_function_impl(acc, ctx, replacement_range, func, hir_impl)
                 }
                 (hir::AssocItem::TypeAlias(type_alias), All | TypeAlias) => {
-                    add_type_alias_impl(acc, ctx, replacement_range, type_alias)
+                    add_type_alias_impl(acc, ctx, replacement_range, type_alias, hir_impl)
                 }
                 (hir::AssocItem::Const(const_), All | Const) => {
                     add_const_impl(acc, ctx, replacement_range, const_, hir_impl)
@@ -236,9 +236,7 @@ fn get_transformed_assoc_item(
     );
 
     transform.apply(assoc_item.syntax());
-    if let ast::AssocItem::Fn(func) = &assoc_item {
-        func.remove_attrs_and_docs();
-    }
+    assoc_item.remove_attrs_and_docs();
     Some(assoc_item)
 }
 
@@ -247,24 +245,50 @@ fn add_type_alias_impl(
     ctx: &CompletionContext<'_>,
     replacement_range: TextRange,
     type_alias: hir::TypeAlias,
+    impl_def: hir::Impl,
 ) {
-    let alias_name = type_alias.name(ctx.db);
-    let (alias_name, escaped_name) =
-        (alias_name.unescaped().to_smol_str(), alias_name.to_smol_str());
+    let alias_name = type_alias.name(ctx.db).unescaped().to_smol_str();
 
     let label = format!("type {} =", alias_name);
-    let replacement = format!("type {} = ", escaped_name);
 
     let mut item = CompletionItem::new(SymbolKind::TypeAlias, replacement_range, label);
     item.lookup_by(format!("type {}", alias_name))
         .set_documentation(type_alias.docs(ctx.db))
         .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
-    match ctx.config.snippet_cap {
-        Some(cap) => item
-            .snippet_edit(cap, TextEdit::replace(replacement_range, format!("{}$0;", replacement))),
-        None => item.text_edit(TextEdit::replace(replacement_range, replacement)),
-    };
-    item.add_to(acc);
+
+    if let Some(source) = ctx.sema.source(type_alias) {
+        let assoc_item = ast::AssocItem::TypeAlias(source.value);
+        if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
+            let transformed_ty = match transformed_item {
+                ast::AssocItem::TypeAlias(ty) => ty,
+                _ => unreachable!(),
+            };
+
+            let start = transformed_ty.syntax().text_range().start();
+            let Some(end) = transformed_ty
+                .eq_token()
+                .map(|tok| tok.text_range().start())
+                .or(transformed_ty.semicolon_token().map(|tok| tok.text_range().start())) else { return };
+
+            let len = end - start;
+            let mut decl = transformed_ty.syntax().text().slice(..len).to_string();
+            if !decl.ends_with(' ') {
+                decl.push(' ');
+            }
+            decl.push_str("= ");
+
+            match ctx.config.snippet_cap {
+                Some(cap) => {
+                    let snippet = format!("{}$0;", decl);
+                    item.snippet_edit(cap, TextEdit::replace(replacement_range, snippet));
+                }
+                None => {
+                    item.text_edit(TextEdit::replace(replacement_range, decl));
+                }
+            };
+            item.add_to(acc);
+        }
+    }
 }
 
 fn add_const_impl(
@@ -309,7 +333,6 @@ fn add_const_impl(
 }
 
 fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> String {
-    const_.remove_attrs_and_docs();
     let const_ = if needs_whitespace {
         insert_whitespace_into_node::insert_ws_into(const_.syntax().clone())
     } else {
@@ -333,8 +356,6 @@ fn make_const_compl_syntax(const_: &ast::Const, needs_whitespace: bool) -> Strin
 }
 
 fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
-    node.remove_attrs_and_docs();
-
     let node = if needs_whitespace {
         insert_whitespace_into_node::insert_ws_into(node.syntax().clone())
     } else {
@@ -350,9 +371,7 @@ fn function_declaration(node: &ast::Fn, needs_whitespace: bool) -> String {
         .map_or(end, |f| f.text_range().start());
 
     let len = end - start;
-    let range = TextRange::new(0.into(), len);
-
-    let syntax = node.text().slice(range).to_string();
+    let syntax = node.text().slice(..len).to_string();
 
     syntax.trim_end().to_owned()
 }
@@ -1163,4 +1182,104 @@ impl Foo for Test {
 "#,
         );
     }
+
+    #[test]
+    fn includes_gat_generics() {
+        check_edit(
+            "type Ty",
+            r#"
+trait Tr<'b> {
+    type Ty<'a: 'b, T: Copy, const C: usize>;
+}
+
+impl<'b> Tr<'b> for () {
+    $0
+}
+"#,
+            r#"
+trait Tr<'b> {
+    type Ty<'a: 'b, T: Copy, const C: usize>;
+}
+
+impl<'b> Tr<'b> for () {
+    type Ty<'a: 'b, T: Copy, const C: usize> = $0;
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn strips_comments() {
+        check_edit(
+            "fn func",
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    fn func();
+}
+impl Tr for () {
+    $0
+}
+"#,
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    fn func();
+}
+impl Tr for () {
+    fn func() {
+    $0
+}
+}
+"#,
+        );
+        check_edit(
+            "const C",
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    const C: usize;
+}
+impl Tr for () {
+    $0
+}
+"#,
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    const C: usize;
+}
+impl Tr for () {
+    const C: usize = $0;
+}
+"#,
+        );
+        check_edit(
+            "type Item",
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    type Item;
+}
+impl Tr for () {
+    $0
+}
+"#,
+            r#"
+trait Tr {
+    /// docs
+    #[attr]
+    type Item;
+}
+impl Tr for () {
+    type Item = $0;
+}
+"#,
+        );
+    }
 }
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 04111ec7efa..c142a7305f9 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
@@ -681,9 +681,13 @@ fn classify_name_ref(
                     ast::Item::ExternBlock(it) => it.extern_item_list().is_none(),
                     ast::Item::Fn(it) => it.body().is_none(),
                     ast::Item::Impl(it) => it.assoc_item_list().is_none(),
-                    ast::Item::Module(it) => it.item_list().is_none(),
+                    ast::Item::Module(it) => {
+                        it.item_list().is_none() && it.semicolon_token().is_none()
+                    }
                     ast::Item::Static(it) => it.body().is_none(),
-                    ast::Item::Struct(it) => it.field_list().is_none(),
+                    ast::Item::Struct(it) => {
+                        it.field_list().is_none() && it.semicolon_token().is_none()
+                    }
                     ast::Item::Trait(it) => it.assoc_item_list().is_none(),
                     ast::Item::TypeAlias(it) => it.ty().is_none(),
                     ast::Item::Union(it) => it.record_field_list().is_none(),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
index 5076c6e86ca..8ed6cb3cf86 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item_list.rs
@@ -245,3 +245,35 @@ impl Test for () {
         "#]],
     );
 }
+
+#[test]
+fn after_unit_struct() {
+    check(
+        r#"struct S; f$0"#,
+        expect![[r#"
+            ma makro!(…)           macro_rules! makro
+            md module
+            kw const
+            kw crate::
+            kw enum
+            kw extern
+            kw fn
+            kw impl
+            kw mod
+            kw pub
+            kw pub(crate)
+            kw pub(super)
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            sn macro_rules
+            sn tfn (Test function)
+            sn tmod (Test module)
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
index cf0bcd5c96b..f48cce58c6e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-db/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
index 75d49ff2fd7..1b8f56187a0 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/line_index.rs
@@ -58,8 +58,11 @@ impl LineIndex {
         let mut utf16_lines = NoHashHashMap::default();
         let mut utf16_chars = Vec::new();
 
-        let mut newlines = vec![0.into()];
-        let mut curr_row @ mut curr_col = 0.into();
+        let mut newlines = Vec::with_capacity(16);
+        newlines.push(TextSize::from(0));
+
+        let mut curr_row = 0.into();
+        let mut curr_col = 0.into();
         let mut line = 0;
         for c in text.chars() {
             let c_len = TextSize::of(c);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
index ac6c6e8feee..313346ee131 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
@@ -104,6 +104,11 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
                 extracted_expressions.push(Arg::Placeholder);
                 state = State::NotArg;
             }
+            (State::MaybeArg, ':') => {
+                output.push(chr);
+                extracted_expressions.push(Arg::Placeholder);
+                state = State::FormatOpts;
+            }
             (State::MaybeArg, _) => {
                 if matches!(chr, '\\' | '$') {
                     current_expr.push('\\');
@@ -118,44 +123,41 @@ pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
                     state = State::Expr;
                 }
             }
-            (State::Ident | State::Expr, '}') => {
-                if inexpr_open_count == 0 {
-                    output.push(chr);
-
-                    if matches!(state, State::Expr) {
-                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
-                    } else {
-                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
-                    }
-
-                    current_expr = String::new();
-                    state = State::NotArg;
-                } else {
-                    // We're closing one brace met before inside of the expression.
-                    current_expr.push(chr);
-                    inexpr_open_count -= 1;
-                }
-            }
             (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => {
                 // path separator
                 state = State::Expr;
                 current_expr.push_str("::");
                 chars.next();
             }
-            (State::Ident | State::Expr, ':') => {
+            (State::Ident | State::Expr, ':' | '}') => {
                 if inexpr_open_count == 0 {
-                    // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
-                    output.push(chr);
+                    let trimmed = current_expr.trim();
 
-                    if matches!(state, State::Expr) {
-                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
+                    // if the expression consists of a single number, like "0" or "12", it can refer to
+                    // format args in the order they are specified.
+                    // see: https://doc.rust-lang.org/std/fmt/#positional-parameters
+                    if trimmed.chars().fold(true, |only_num, c| c.is_ascii_digit() && only_num) {
+                        output.push_str(trimmed);
+                    } else if matches!(state, State::Expr) {
+                        extracted_expressions.push(Arg::Expr(trimmed.into()));
                     } else {
-                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
+                        extracted_expressions.push(Arg::Ident(trimmed.into()));
                     }
 
-                    current_expr = String::new();
-                    state = State::FormatOpts;
-                } else {
+                    output.push(chr);
+                    current_expr.clear();
+                    state = if chr == ':' {
+                        State::FormatOpts
+                    } else if chr == '}' {
+                        State::NotArg
+                    } else {
+                        unreachable!()
+                    };
+                } else if chr == '}' {
+                    // We're closing one brace met before inside of the expression.
+                    current_expr.push(chr);
+                    inexpr_open_count -= 1;
+                } else if chr == ':' {
                     // We're inside of braced expression, assume that it's a struct field name/value delimiter.
                     current_expr.push(chr);
                 }
@@ -219,6 +221,10 @@ mod tests {
             ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
             ("{expr:?}", expect![["{:?}; expr"]]),
             ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
+            ("{:1$}", expect![[r"{:1\$}; $1"]]),
+            ("{:>padding$}", expect![[r"{:>padding\$}; $1"]]),
+            ("{}, {}, {0}", expect![[r"{}, {}, {0}; $1, $2"]]),
+            ("{}, {}, {0:b}", expect![[r"{}, {}, {0:b}; $1, $2"]]),
             ("{$0}", expect![[r"{}; \$0"]]),
             ("{malformed", expect![["-"]]),
             ("malformed}", expect![["-"]]),
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
index e1d146f4ee5..7e9a1125d75 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
index 43ff4ed5a6c..870c78d1f1e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -5,10 +5,7 @@ use crate::{Diagnostic, DiagnosticsContext};
 // This diagnostic is shown for macro expansion errors.
 pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) -> Diagnostic {
     // Use more accurate position if available.
-    let display_range = d
-        .precise_location
-        .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()).range);
-
+    let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
     Diagnostic::new("macro-error", d.message.clone(), display_range).experimental()
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
index a80299106bd..d8f2a9de981 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/no_such_field.rs
@@ -268,12 +268,12 @@ fn main() {
     foo::Foo { bar: 3, $0baz: false};
 }
 //- /foo.rs
-struct Foo {
+pub struct Foo {
     bar: i32
 }
 "#,
             r#"
-struct Foo {
+pub struct Foo {
     bar: i32,
     pub(crate) baz: bool
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
index 4b43124757f..87531f4acfb 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_macro_call.rs
@@ -9,10 +9,7 @@ pub(crate) fn unresolved_macro_call(
     d: &hir::UnresolvedMacroCall,
 ) -> Diagnostic {
     // Use more accurate position if available.
-    let display_range = d
-        .precise_location
-        .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.macro_call.clone()).range);
-
+    let display_range = ctx.resolve_precise_location(&d.macro_call, d.precise_location);
     let bang = if d.is_bang { "!" } else { "" };
     Diagnostic::new(
         "unresolved-macro-call",
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
index 760f51f9049..23818d883f7 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/unresolved_proc_macro.rs
@@ -1,5 +1,4 @@
 use hir::db::DefDatabase;
-use syntax::NodeOrToken;
 
 use crate::{Diagnostic, DiagnosticsContext, Severity};
 
@@ -19,16 +18,7 @@ pub(crate) fn unresolved_proc_macro(
     proc_attr_macros_enabled: bool,
 ) -> Diagnostic {
     // Use more accurate position if available.
-    let display_range = (|| {
-        let precise_location = d.precise_location?;
-        let root = ctx.sema.parse_or_expand(d.node.file_id)?;
-        match root.covering_element(precise_location) {
-            NodeOrToken::Node(it) => Some(ctx.sema.original_range(&it)),
-            NodeOrToken::Token(it) => d.node.with_value(it).original_file_range_opt(ctx.sema.db),
-        }
-    })()
-    .unwrap_or_else(|| ctx.sema.diagnostics_display_range(d.node.clone()))
-    .range;
+    let display_range = ctx.resolve_precise_location(&d.node, d.precise_location);
 
     let config_enabled = match d.kind {
         hir::MacroKind::Attr => proc_macros_enabled && proc_attr_macros_enabled,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
index 8b9330e0401..289ed0458c6 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/useless_braces.rs
@@ -71,9 +71,9 @@ use a;
 use a::{c, d::e};
 
 mod a {
-    mod c {}
-    mod d {
-        mod e {}
+    pub mod c {}
+    pub mod d {
+        pub mod e {}
     }
 }
 "#,
@@ -87,9 +87,9 @@ use a::{
 };
 
 mod a {
-    mod c {}
-    mod d {
-        mod e {}
+    pub mod c {}
+    pub mod d {
+        pub mod e {}
     }
 }
 "#,
@@ -116,11 +116,11 @@ use b;
         );
         check_fix(
             r#"
-mod a { mod c {} }
+mod a { pub mod c {} }
 use a::{c$0};
 "#,
             r#"
-mod a { mod c {} }
+mod a { pub mod c {} }
 use a::c;
 "#,
         );
@@ -136,11 +136,11 @@ use a;
         );
         check_fix(
             r#"
-mod a { mod c {} mod d { mod e {} } }
+mod a { pub mod c {} pub mod d { pub mod e {} } }
 use a::{c, d::{e$0}};
 "#,
             r#"
-mod a { mod c {} mod d { mod e {} } }
+mod a { pub mod c {} pub mod d { pub mod e {} } }
 use a::{c, d::e};
 "#,
         );
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 ae299f05841..d81e36a1f86 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -182,6 +182,28 @@ struct DiagnosticsContext<'a> {
     resolve: &'a AssistResolveStrategy,
 }
 
+impl<'a> DiagnosticsContext<'a> {
+    fn resolve_precise_location(
+        &self,
+        node: &InFile<SyntaxNodePtr>,
+        precise_location: Option<TextRange>,
+    ) -> TextRange {
+        let sema = &self.sema;
+        (|| {
+            let precise_location = precise_location?;
+            let root = sema.parse_or_expand(node.file_id)?;
+            match root.covering_element(precise_location) {
+                syntax::NodeOrToken::Node(it) => Some(sema.original_range(&it)),
+                syntax::NodeOrToken::Token(it) => {
+                    node.with_value(it).original_file_range_opt(sema.db)
+                }
+            }
+        })()
+        .unwrap_or_else(|| sema.diagnostics_display_range(node.clone()))
+        .range
+    }
+}
+
 pub fn diagnostics(
     db: &RootDatabase,
     config: &DiagnosticsConfig,
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
index 4baf786c455..7be62a8d9ff 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide-ssr/Cargo.toml
@@ -5,7 +5,7 @@ description = "Structural search and replace of Rust code"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-analyzer"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/ide/Cargo.toml b/src/tools/rust-analyzer/crates/ide/Cargo.toml
index 712459a7ee9..73f202630f1 100644
--- a/src/tools/rust-analyzer/crates/ide/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/ide/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
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 f97c67b144a..43f7a529bc2 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -289,10 +289,10 @@ mod b;
 enum E { X(Foo$0) }
 
 //- /a.rs
-struct Foo;
-     //^^^
+pub struct Foo;
+         //^^^
 //- /b.rs
-struct Foo;
+pub struct Foo;
 "#,
         );
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 3687b597fc6..838fb18c3d5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -119,7 +119,14 @@ pub(crate) fn hover(
         });
     }
 
-    let in_attr = matches!(original_token.parent().and_then(ast::TokenTree::cast), Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind())));
+    let in_attr = original_token
+        .parent_ancestors()
+        .filter_map(ast::Item::cast)
+        .any(|item| sema.is_attr_macro_call(&item))
+        && !matches!(
+            original_token.parent().and_then(ast::TokenTree::cast),
+            Some(tt) if tt.syntax().ancestors().any(|it| ast::Meta::can_cast(it.kind()))
+        );
     // prefer descending the same token kind in attribute expansions, in normal macros text
     // equivalency is more important
     let descended = if in_attr {
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 34d8bf67a30..37384c4e7e0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -1,7 +1,10 @@
 use std::fmt;
 
 use either::Either;
-use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
+use hir::{
+    known, Adjust, AutoBorrow, Callable, HasVisibility, HirDisplay, Mutability, OverloadedDeref,
+    PointerCast, Safety, Semantics, TypeInfo,
+};
 use ide_db::{
     base_db::FileRange, famous_defs::FamousDefs, syntax_helpers::node_ext::walk_ty, FxHashMap,
     RootDatabase,
@@ -22,7 +25,7 @@ pub struct InlayHintsConfig {
     pub type_hints: bool,
     pub parameter_hints: bool,
     pub chaining_hints: bool,
-    pub reborrow_hints: ReborrowHints,
+    pub adjustment_hints: AdjustmentHints,
     pub closure_return_type_hints: ClosureReturnTypeHints,
     pub binding_mode_hints: bool,
     pub lifetime_elision_hints: LifetimeElisionHints,
@@ -48,9 +51,9 @@ pub enum LifetimeElisionHints {
 }
 
 #[derive(Clone, Debug, PartialEq, Eq)]
-pub enum ReborrowHints {
+pub enum AdjustmentHints {
     Always,
-    MutableOnly,
+    ReborrowOnly,
     Never,
 }
 
@@ -61,7 +64,8 @@ pub enum InlayKind {
     ClosingBraceHint,
     ClosureReturnTypeHint,
     GenericParamListHint,
-    ImplicitReborrowHint,
+    AdjustmentHint,
+    AdjustmentHintClosingParenthesis,
     LifetimeHint,
     ParameterHint,
     TypeHint,
@@ -115,6 +119,12 @@ impl From<String> for InlayHintLabel {
     }
 }
 
+impl From<&str> for InlayHintLabel {
+    fn from(s: &str) -> Self {
+        Self { parts: vec![InlayHintLabelPart { text: s.into(), linked_location: None }] }
+    }
+}
+
 impl fmt::Display for InlayHintLabel {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
@@ -180,7 +190,7 @@ impl fmt::Debug for InlayHintLabelPart {
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
     file_id: FileId,
-    range_limit: Option<FileRange>,
+    range_limit: Option<TextRange>,
     config: &InlayHintsConfig,
 ) -> Vec<InlayHint> {
     let _p = profile::span("inlay_hints");
@@ -195,7 +205,7 @@ pub(crate) fn inlay_hints(
 
         let hints = |node| hints(&mut acc, &famous_defs, config, file_id, node);
         match range_limit {
-            Some(FileRange { range, .. }) => match file.covering_element(range) {
+            Some(range) => match file.covering_element(range) {
                 NodeOrToken::Token(_) => return acc,
                 NodeOrToken::Node(n) => n
                     .descendants()
@@ -221,6 +231,7 @@ fn hints(
         match node {
             ast::Expr(expr) => {
                 chaining_hints(hints, sema, &famous_defs, config, file_id, &expr);
+                adjustment_hints(hints, sema, config, &expr);
                 match expr {
                     ast::Expr::CallExpr(it) => param_name_hints(hints, sema, config, ast::Expr::from(it)),
                     ast::Expr::MethodCallExpr(it) => {
@@ -229,7 +240,7 @@ fn hints(
                     ast::Expr::ClosureExpr(it) => closure_ret_hints(hints, sema, &famous_defs, config, file_id, it),
                     // We could show reborrows for all expressions, but usually that is just noise to the user
                     // and the main point here is to show why "moving" a mutable reference doesn't necessarily move it
-                    ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
+                    // ast::Expr::PathExpr(_) => reborrow_hints(hints, sema, config, &expr),
                     _ => None,
                 }
             },
@@ -617,30 +628,95 @@ fn closure_ret_hints(
     Some(())
 }
 
-fn reborrow_hints(
+fn adjustment_hints(
     acc: &mut Vec<InlayHint>,
     sema: &Semantics<'_, RootDatabase>,
     config: &InlayHintsConfig,
     expr: &ast::Expr,
 ) -> Option<()> {
-    if config.reborrow_hints == ReborrowHints::Never {
+    if config.adjustment_hints == AdjustmentHints::Never {
+        return None;
+    }
+
+    if let ast::Expr::ParenExpr(_) = expr {
+        // These inherit from the inner expression which would result in duplicate hints
         return None;
     }
 
+    let parent = expr.syntax().parent().and_then(ast::Expr::cast);
     let descended = sema.descend_node_into_attributes(expr.clone()).pop();
     let desc_expr = descended.as_ref().unwrap_or(expr);
-    let mutability = sema.is_implicit_reborrow(desc_expr)?;
-    let label = match mutability {
-        hir::Mutability::Shared if config.reborrow_hints != ReborrowHints::MutableOnly => "&*",
-        hir::Mutability::Mut => "&mut *",
-        _ => return None,
+    let adjustments = sema.expr_adjustments(desc_expr).filter(|it| !it.is_empty())?;
+    let needs_parens = match parent {
+        Some(parent) => {
+            match parent {
+                ast::Expr::AwaitExpr(_)
+                | ast::Expr::CallExpr(_)
+                | ast::Expr::CastExpr(_)
+                | ast::Expr::FieldExpr(_)
+                | ast::Expr::MethodCallExpr(_)
+                | ast::Expr::TryExpr(_) => true,
+                // FIXME: shorthands need special casing, though not sure if adjustments are even valid there
+                ast::Expr::RecordExpr(_) => false,
+                ast::Expr::IndexExpr(index) => index.base().as_ref() == Some(expr),
+                _ => false,
+            }
+        }
+        None => false,
     };
-    acc.push(InlayHint {
-        range: expr.syntax().text_range(),
-        kind: InlayKind::ImplicitReborrowHint,
-        label: label.to_string().into(),
-        tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
-    });
+    if needs_parens {
+        acc.push(InlayHint {
+            range: expr.syntax().text_range(),
+            kind: InlayKind::AdjustmentHint,
+            label: "(".into(),
+            tooltip: None,
+        });
+    }
+    for adjustment in adjustments.into_iter().rev() {
+        // FIXME: Add some nicer tooltips to each of these
+        let text = match adjustment {
+            Adjust::NeverToAny if config.adjustment_hints == AdjustmentHints::Always => {
+                "<never-to-any>"
+            }
+            Adjust::Deref(None) => "*",
+            Adjust::Deref(Some(OverloadedDeref(Mutability::Mut))) => "*",
+            Adjust::Deref(Some(OverloadedDeref(Mutability::Shared))) => "*",
+            Adjust::Borrow(AutoBorrow::Ref(Mutability::Shared)) => "&",
+            Adjust::Borrow(AutoBorrow::Ref(Mutability::Mut)) => "&mut ",
+            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Shared)) => "&raw const ",
+            Adjust::Borrow(AutoBorrow::RawPtr(Mutability::Mut)) => "&raw mut ",
+            // some of these could be represented via `as` casts, but that's not too nice and
+            // handling everything as a prefix expr makes the `(` and `)` insertion easier
+            Adjust::Pointer(cast) if config.adjustment_hints == AdjustmentHints::Always => {
+                match cast {
+                    PointerCast::ReifyFnPointer => "<fn-item-to-fn-pointer>",
+                    PointerCast::UnsafeFnPointer => "<safe-fn-pointer-to-unsafe-fn-pointer>",
+                    PointerCast::ClosureFnPointer(Safety::Unsafe) => {
+                        "<closure-to-unsafe-fn-pointer>"
+                    }
+                    PointerCast::ClosureFnPointer(Safety::Safe) => "<closure-to-fn-pointer>",
+                    PointerCast::MutToConstPointer => "<mut-ptr-to-const-ptr>",
+                    PointerCast::ArrayToPointer => "<array-ptr-to-element-ptr>",
+                    PointerCast::Unsize => "<unsize>",
+                }
+            }
+            _ => continue,
+        };
+        acc.push(InlayHint {
+            range: expr.syntax().text_range(),
+            kind: InlayKind::AdjustmentHint,
+            label: text.into(),
+            tooltip: None,
+        });
+    }
+    if needs_parens {
+        acc.push(InlayHint {
+            range: expr.syntax().text_range(),
+            kind: InlayKind::AdjustmentHintClosingParenthesis,
+            label: ")".into(),
+            tooltip: None,
+        });
+    }
     Some(())
 }
 
@@ -1213,12 +1289,11 @@ fn get_callable(
 #[cfg(test)]
 mod tests {
     use expect_test::{expect, Expect};
-    use ide_db::base_db::FileRange;
     use itertools::Itertools;
     use syntax::{TextRange, TextSize};
     use test_utils::extract_annotations;
 
-    use crate::inlay_hints::ReborrowHints;
+    use crate::inlay_hints::AdjustmentHints;
     use crate::{fixture, inlay_hints::InlayHintsConfig, LifetimeElisionHints};
 
     use super::ClosureReturnTypeHints;
@@ -1230,7 +1305,7 @@ mod tests {
         chaining_hints: false,
         lifetime_elision_hints: LifetimeElisionHints::Never,
         closure_return_type_hints: ClosureReturnTypeHints::Never,
-        reborrow_hints: ReborrowHints::Always,
+        adjustment_hints: AdjustmentHints::Never,
         binding_mode_hints: false,
         hide_named_constructor_hints: false,
         hide_closure_initialization_hints: false,
@@ -1242,7 +1317,6 @@ mod tests {
         type_hints: true,
         parameter_hints: true,
         chaining_hints: true,
-        reborrow_hints: ReborrowHints::Always,
         closure_return_type_hints: ClosureReturnTypeHints::WithBlock,
         binding_mode_hints: true,
         lifetime_elision_hints: LifetimeElisionHints::Always,
@@ -1838,10 +1912,7 @@ fn main() {
             .inlay_hints(
                 &InlayHintsConfig { type_hints: true, ..DISABLED_CONFIG },
                 file_id,
-                Some(FileRange {
-                    file_id,
-                    range: TextRange::new(TextSize::from(500), TextSize::from(600)),
-                }),
+                Some(TextRange::new(TextSize::from(500), TextSize::from(600))),
             )
             .unwrap();
         let actual =
@@ -2846,48 +2917,6 @@ impl () {
     }
 
     #[test]
-    fn hints_implicit_reborrow() {
-        check_with_config(
-            InlayHintsConfig {
-                reborrow_hints: ReborrowHints::Always,
-                parameter_hints: true,
-                ..DISABLED_CONFIG
-            },
-            r#"
-fn __() {
-    let unique = &mut ();
-    let r_mov = unique;
-    let foo: &mut _ = unique;
-                    //^^^^^^ &mut *
-    ref_mut_id(unique);
-             //^^^^^^ mut_ref
-             //^^^^^^ &mut *
-    let shared = ref_id(unique);
-                      //^^^^^^ shared_ref
-                      //^^^^^^ &*
-    let mov = shared;
-    let r_mov: &_ = shared;
-    ref_id(shared);
-         //^^^^^^ shared_ref
-
-    identity(unique);
-    identity(shared);
-}
-fn identity<T>(t: T) -> T {
-    t
-}
-fn ref_mut_id(mut_ref: &mut ()) -> &mut () {
-    mut_ref
-  //^^^^^^^ &mut *
-}
-fn ref_id(shared_ref: &()) -> &() {
-    shared_ref
-}
-"#,
-        );
-    }
-
-    #[test]
     fn hints_binding_modes() {
         check_with_config(
             InlayHintsConfig { binding_mode_hints: true, ..DISABLED_CONFIG },
@@ -2994,4 +3023,76 @@ fn f() {
 "#,
         );
     }
+
+    #[test]
+    fn adjustment_hints() {
+        check_with_config(
+            InlayHintsConfig { adjustment_hints: AdjustmentHints::Always, ..DISABLED_CONFIG },
+            r#"
+//- minicore: coerce_unsized
+fn main() {
+    let _: u32         = loop {};
+                       //^^^^^^^<never-to-any>
+    let _: &u32        = &mut 0;
+                       //^^^^^^&
+                       //^^^^^^*
+    let _: &mut u32    = &mut 0;
+                       //^^^^^^&mut $
+                       //^^^^^^*
+    let _: *const u32  = &mut 0;
+                       //^^^^^^&raw const $
+                       //^^^^^^*
+    let _: *mut u32    = &mut 0;
+                       //^^^^^^&raw mut $
+                       //^^^^^^*
+    let _: fn()        = main;
+                       //^^^^<fn-item-to-fn-pointer>
+    let _: unsafe fn() = main;
+                       //^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
+                       //^^^^<fn-item-to-fn-pointer>
+    let _: unsafe fn() = main as fn();
+                       //^^^^^^^^^^^^<safe-fn-pointer-to-unsafe-fn-pointer>
+    let _: fn()        = || {};
+                       //^^^^^<closure-to-fn-pointer>
+    let _: unsafe fn() = || {};
+                       //^^^^^<closure-to-unsafe-fn-pointer>
+    let _: *const u32  = &mut 0u32 as *mut u32;
+                       //^^^^^^^^^^^^^^^^^^^^^<mut-ptr-to-const-ptr>
+    let _: &mut [_]    = &mut [0; 0];
+                       //^^^^^^^^^^^<unsize>
+                       //^^^^^^^^^^^&mut $
+                       //^^^^^^^^^^^*
+
+    Struct.consume();
+    Struct.by_ref();
+  //^^^^^^(
+  //^^^^^^&
+  //^^^^^^)
+    Struct.by_ref_mut();
+  //^^^^^^(
+  //^^^^^^&mut $
+  //^^^^^^)
+
+    (&Struct).consume();
+   //^^^^^^^*
+    (&Struct).by_ref();
+
+    (&mut Struct).consume();
+   //^^^^^^^^^^^*
+    (&mut Struct).by_ref();
+   //^^^^^^^^^^^&
+   //^^^^^^^^^^^*
+    (&mut Struct).by_ref_mut();
+}
+
+#[derive(Copy, Clone)]
+struct Struct;
+impl Struct {
+    fn consume(self) {}
+    fn by_ref(&self) {}
+    fn by_ref_mut(&mut self) {}
+}
+"#,
+        )
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/lib.rs b/src/tools/rust-analyzer/crates/ide/src/lib.rs
index 416817ca0b4..7402e86f36f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/lib.rs
@@ -81,8 +81,8 @@ pub use crate::{
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
-        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
-        InlayTooltip, LifetimeElisionHints, ReborrowHints,
+        AdjustmentHints, ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig,
+        InlayKind, InlayTooltip, LifetimeElisionHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
@@ -367,7 +367,7 @@ impl Analysis {
         &self,
         config: &InlayHintsConfig,
         file_id: FileId,
-        range: Option<FileRange>,
+        range: Option<TextRange>,
     ) -> Cancellable<Vec<InlayHint>> {
         self.with_db(|db| inlay_hints::inlay_hints(db, file_id, range, config))
     }
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index 07d117aff10..fcbf6d8e58c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -1,9 +1,9 @@
 //! This module generates [moniker](https://microsoft.github.io/language-server-protocol/specifications/lsif/0.6.0/specification/#exportsImports)
 //! for LSIF and LSP.
 
-use hir::{db::DefDatabase, AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
+use hir::{AsAssocItem, AssocItemContainer, Crate, Name, Semantics};
 use ide_db::{
-    base_db::{CrateOrigin, FileId, FileLoader, FilePosition, LangCrateOrigin},
+    base_db::{CrateOrigin, FilePosition, LangCrateOrigin},
     defs::{Definition, IdentClass},
     helpers::pick_best_token,
     RootDatabase,
@@ -11,7 +11,7 @@ use ide_db::{
 use itertools::Itertools;
 use syntax::{AstNode, SyntaxKind::*, T};
 
-use crate::{doc_links::token_as_doc_comment, RangeInfo};
+use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo};
 
 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
 pub enum MonikerDescriptorKind {
@@ -77,25 +77,13 @@ pub struct PackageInformation {
     pub version: Option<String>,
 }
 
-pub(crate) fn crate_for_file(db: &RootDatabase, file_id: FileId) -> Option<Crate> {
-    for &krate in db.relevant_crates(file_id).iter() {
-        let crate_def_map = db.crate_def_map(krate);
-        for (_, data) in crate_def_map.modules() {
-            if data.origin.file_id() == Some(file_id) {
-                return Some(krate.into());
-            }
-        }
-    }
-    None
-}
-
 pub(crate) fn moniker(
     db: &RootDatabase,
     FilePosition { file_id, offset }: FilePosition,
 ) -> Option<RangeInfo<Vec<MonikerResult>>> {
     let sema = &Semantics::new(db);
     let file = sema.parse(file_id).syntax().clone();
-    let current_crate = crate_for_file(db, file_id)?;
+    let current_crate: hir::Crate = crates_for(db, file_id).pop()?.into();
     let original_token = pick_best_token(file.token_at_offset(offset), |kind| match kind {
         IDENT
         | INT_NUMBER
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index e942413c110..0f758cfa2d3 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -16,6 +16,7 @@ use ide_db::{
     search::{ReferenceCategory, SearchScope, UsageSearchResult},
     RootDatabase,
 };
+use itertools::Itertools;
 use stdx::hash::NoHashHashMap;
 use syntax::{
     algo::find_node_at_offset,
@@ -86,6 +87,7 @@ pub(crate) fn find_all_refs(
                         file_id,
                         refs.into_iter()
                             .map(|file_ref| (file_ref.range, file_ref.category))
+                            .unique()
                             .collect(),
                     )
                 })
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index 7486b20293a..e7412d27faf 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -1345,5 +1345,36 @@ fn f<F: FnOnce(u8, u16) -> i32>(f: F) {
                  ^^  ---
             "#]],
         );
+        check(
+            r#"
+fn f<T, F: FnOnce(&T, u16) -> &T>(f: F) {
+    f($0)
+}
+"#,
+            expect![[r#"
+                (&T, u16) -> &T
+                 ^^  ---
+            "#]],
+        );
+    }
+
+    #[test]
+    fn regression_13579() {
+        check(
+            r#"
+fn f() {
+    take(2)($0);
+}
+
+fn take<C, Error>(
+    count: C
+) -> impl Fn() -> C  {
+    move || count
+}
+"#,
+            expect![[r#"
+                () -> i32
+            "#]],
+        );
     }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 27ad1a948d1..2380cf7381c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -13,7 +13,8 @@ use syntax::{AstNode, SyntaxKind::*, SyntaxToken, TextRange, T};
 
 use crate::{
     hover::hover_for_definition,
-    moniker::{crate_for_file, def_to_moniker, MonikerResult},
+    moniker::{def_to_moniker, MonikerResult},
+    parent_module::crates_for,
     Analysis, Fold, HoverConfig, HoverDocFormat, HoverResult, InlayHint, InlayHintsConfig,
     TryToNav,
 };
@@ -99,7 +100,7 @@ fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
 
 impl StaticIndex<'_> {
     fn add_file(&mut self, file_id: FileId) {
-        let current_crate = crate_for_file(self.db, file_id);
+        let current_crate = crates_for(self.db, file_id).pop().map(Into::into);
         let folds = self.analysis.folding_ranges(file_id).unwrap();
         let inlay_hints = self
             .analysis
@@ -111,7 +112,7 @@ impl StaticIndex<'_> {
                     chaining_hints: true,
                     closure_return_type_hints: crate::ClosureReturnTypeHints::WithBlock,
                     lifetime_elision_hints: crate::LifetimeElisionHints::Never,
-                    reborrow_hints: crate::ReborrowHints::Never,
+                    adjustment_hints: crate::AdjustmentHints::Never,
                     hide_named_constructor_hints: false,
                     hide_closure_initialization_hints: false,
                     param_names_for_lifetime_elision_hints: false,
diff --git a/src/tools/rust-analyzer/crates/limit/Cargo.toml b/src/tools/rust-analyzer/crates/limit/Cargo.toml
index 893db436d8b..3536f73da73 100644
--- a/src/tools/rust-analyzer/crates/limit/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/limit/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [features]
 tracking = []
diff --git a/src/tools/rust-analyzer/crates/mbe/Cargo.toml b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
index 13cd8901031..bce2fc9a70e 100644
--- a/src/tools/rust-analyzer/crates/mbe/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/mbe/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
index e4c56565b92..cf53c16726b 100644
--- a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge.rs
@@ -12,6 +12,9 @@ use tt::buffer::{Cursor, TokenBuffer};
 
 use crate::{to_parser_input::to_parser_input, tt_iter::TtIter, TokenMap};
 
+#[cfg(test)]
+mod tests;
+
 /// Convert the syntax node to a `TokenTree` (what macro
 /// will consume).
 pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) {
@@ -35,7 +38,7 @@ pub fn syntax_node_to_token_tree_with_modifications(
     append: FxHashMap<SyntaxElement, Vec<SyntheticToken>>,
 ) -> (tt::Subtree, TokenMap, u32) {
     let global_offset = node.text_range().start();
-    let mut c = Convertor::new(node, global_offset, existing_token_map, next_id, replace, append);
+    let mut c = Converter::new(node, global_offset, existing_token_map, next_id, replace, append);
     let subtree = convert_tokens(&mut c);
     c.id_alloc.map.shrink_to_fit();
     always!(c.replace.is_empty(), "replace: {:?}", c.replace);
@@ -100,7 +103,7 @@ pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> {
         return None;
     }
 
-    let mut conv = RawConvertor {
+    let mut conv = RawConverter {
         lexed,
         pos: 0,
         id_alloc: TokenIdAlloc {
@@ -148,7 +151,7 @@ pub fn parse_exprs_with_sep(tt: &tt::Subtree, sep: char) -> Vec<tt::Subtree> {
     res
 }
 
-fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
+fn convert_tokens<C: TokenConverter>(conv: &mut C) -> tt::Subtree {
     struct StackEntry {
         subtree: tt::Subtree,
         idx: usize,
@@ -228,7 +231,7 @@ fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
             }
 
             let spacing = match conv.peek().map(|next| next.kind(conv)) {
-                Some(kind) if !kind.is_trivia() => tt::Spacing::Joint,
+                Some(kind) if is_single_token_op(kind) => tt::Spacing::Joint,
                 _ => tt::Spacing::Alone,
             };
             let char = match token.to_char(conv) {
@@ -307,6 +310,35 @@ fn convert_tokens<C: TokenConvertor>(conv: &mut C) -> tt::Subtree {
     }
 }
 
+fn is_single_token_op(kind: SyntaxKind) -> bool {
+    matches!(
+        kind,
+        EQ | L_ANGLE
+            | R_ANGLE
+            | BANG
+            | AMP
+            | PIPE
+            | TILDE
+            | AT
+            | DOT
+            | COMMA
+            | SEMICOLON
+            | COLON
+            | POUND
+            | DOLLAR
+            | QUESTION
+            | PLUS
+            | MINUS
+            | STAR
+            | SLASH
+            | PERCENT
+            | CARET
+            // LIFETIME_IDENT will be split into a sequence of `'` (a single quote) and an
+            // identifier.
+            | LIFETIME_IDENT
+    )
+}
+
 /// Returns the textual content of a doc comment block as a quoted string
 /// That is, strips leading `///` (or `/**`, etc)
 /// and strips the ending `*/`
@@ -425,8 +457,8 @@ impl TokenIdAlloc {
     }
 }
 
-/// A raw token (straight from lexer) convertor
-struct RawConvertor<'a> {
+/// A raw token (straight from lexer) converter
+struct RawConverter<'a> {
     lexed: parser::LexedStr<'a>,
     pos: usize,
     id_alloc: TokenIdAlloc,
@@ -442,7 +474,7 @@ trait SrcToken<Ctx>: std::fmt::Debug {
     fn synthetic_id(&self, ctx: &Ctx) -> Option<SyntheticTokenId>;
 }
 
-trait TokenConvertor: Sized {
+trait TokenConverter: Sized {
     type Token: SrcToken<Self>;
 
     fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>>;
@@ -454,25 +486,25 @@ trait TokenConvertor: Sized {
     fn id_alloc(&mut self) -> &mut TokenIdAlloc;
 }
 
-impl<'a> SrcToken<RawConvertor<'a>> for usize {
-    fn kind(&self, ctx: &RawConvertor<'a>) -> SyntaxKind {
+impl<'a> SrcToken<RawConverter<'a>> for usize {
+    fn kind(&self, ctx: &RawConverter<'a>) -> SyntaxKind {
         ctx.lexed.kind(*self)
     }
 
-    fn to_char(&self, ctx: &RawConvertor<'a>) -> Option<char> {
+    fn to_char(&self, ctx: &RawConverter<'a>) -> Option<char> {
         ctx.lexed.text(*self).chars().next()
     }
 
-    fn to_text(&self, ctx: &RawConvertor<'_>) -> SmolStr {
+    fn to_text(&self, ctx: &RawConverter<'_>) -> SmolStr {
         ctx.lexed.text(*self).into()
     }
 
-    fn synthetic_id(&self, _ctx: &RawConvertor<'a>) -> Option<SyntheticTokenId> {
+    fn synthetic_id(&self, _ctx: &RawConverter<'a>) -> Option<SyntheticTokenId> {
         None
     }
 }
 
-impl<'a> TokenConvertor for RawConvertor<'a> {
+impl<'a> TokenConverter for RawConverter<'a> {
     type Token = usize;
 
     fn convert_doc_comment(&self, &token: &usize) -> Option<Vec<tt::TokenTree>> {
@@ -504,7 +536,7 @@ impl<'a> TokenConvertor for RawConvertor<'a> {
     }
 }
 
-struct Convertor {
+struct Converter {
     id_alloc: TokenIdAlloc,
     current: Option<SyntaxToken>,
     current_synthetic: Vec<SyntheticToken>,
@@ -515,7 +547,7 @@ struct Convertor {
     punct_offset: Option<(SyntaxToken, TextSize)>,
 }
 
-impl Convertor {
+impl Converter {
     fn new(
         node: &SyntaxNode,
         global_offset: TextSize,
@@ -523,11 +555,11 @@ impl Convertor {
         next_id: u32,
         mut replace: FxHashMap<SyntaxElement, Vec<SyntheticToken>>,
         mut append: FxHashMap<SyntaxElement, Vec<SyntheticToken>>,
-    ) -> Convertor {
+    ) -> Converter {
         let range = node.text_range();
         let mut preorder = node.preorder_with_tokens();
         let (first, synthetic) = Self::next_token(&mut preorder, &mut replace, &mut append);
-        Convertor {
+        Converter {
             id_alloc: { TokenIdAlloc { map: existing_token_map, global_offset, next_id } },
             current: first,
             current_synthetic: synthetic,
@@ -590,15 +622,15 @@ impl SynToken {
     }
 }
 
-impl SrcToken<Convertor> for SynToken {
-    fn kind(&self, _ctx: &Convertor) -> SyntaxKind {
+impl SrcToken<Converter> for SynToken {
+    fn kind(&self, ctx: &Converter) -> SyntaxKind {
         match self {
             SynToken::Ordinary(token) => token.kind(),
-            SynToken::Punch(token, _) => token.kind(),
+            SynToken::Punch(..) => SyntaxKind::from_char(self.to_char(ctx).unwrap()).unwrap(),
             SynToken::Synthetic(token) => token.kind,
         }
     }
-    fn to_char(&self, _ctx: &Convertor) -> Option<char> {
+    fn to_char(&self, _ctx: &Converter) -> Option<char> {
         match self {
             SynToken::Ordinary(_) => None,
             SynToken::Punch(it, i) => it.text().chars().nth((*i).into()),
@@ -606,7 +638,7 @@ impl SrcToken<Convertor> for SynToken {
             SynToken::Synthetic(_) => None,
         }
     }
-    fn to_text(&self, _ctx: &Convertor) -> SmolStr {
+    fn to_text(&self, _ctx: &Converter) -> SmolStr {
         match self {
             SynToken::Ordinary(token) => token.text().into(),
             SynToken::Punch(token, _) => token.text().into(),
@@ -614,7 +646,7 @@ impl SrcToken<Convertor> for SynToken {
         }
     }
 
-    fn synthetic_id(&self, _ctx: &Convertor) -> Option<SyntheticTokenId> {
+    fn synthetic_id(&self, _ctx: &Converter) -> Option<SyntheticTokenId> {
         match self {
             SynToken::Synthetic(token) => Some(token.id),
             _ => None,
@@ -622,7 +654,7 @@ impl SrcToken<Convertor> for SynToken {
     }
 }
 
-impl TokenConvertor for Convertor {
+impl TokenConverter for Converter {
     type Token = SynToken;
     fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> {
         convert_doc_comment(token.token()?)
@@ -651,7 +683,7 @@ impl TokenConvertor for Convertor {
         }
 
         let curr = self.current.clone()?;
-        if !&self.range.contains_range(curr.text_range()) {
+        if !self.range.contains_range(curr.text_range()) {
             return None;
         }
         let (new_current, new_synth) =
@@ -809,12 +841,15 @@ impl<'a> TtTreeSink<'a> {
         let next = last.bump();
         if let (
             Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)),
-            Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)),
+            Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(next), _)),
         ) = (last.token_tree(), next.token_tree())
         {
             // Note: We always assume the semi-colon would be the last token in
             // other parts of RA such that we don't add whitespace here.
-            if curr.spacing == tt::Spacing::Alone && curr.char != ';' {
+            //
+            // When `next` is a `Punct` of `'`, that's a part of a lifetime identifier so we don't
+            // need to add whitespace either.
+            if curr.spacing == tt::Spacing::Alone && curr.char != ';' && next.char != '\'' {
                 self.inner.token(WHITESPACE, " ");
                 self.text_pos += TextSize::of(' ');
             }
diff --git a/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
new file mode 100644
index 00000000000..4e04d2bc1c7
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/mbe/src/syntax_bridge/tests.rs
@@ -0,0 +1,93 @@
+use std::collections::HashMap;
+
+use syntax::{ast, AstNode};
+use test_utils::extract_annotations;
+use tt::{
+    buffer::{TokenBuffer, TokenTreeRef},
+    Leaf, Punct, Spacing,
+};
+
+use super::syntax_node_to_token_tree;
+
+fn check_punct_spacing(fixture: &str) {
+    let source_file = ast::SourceFile::parse(fixture).ok().unwrap();
+    let (subtree, token_map) = syntax_node_to_token_tree(source_file.syntax());
+    let mut annotations: HashMap<_, _> = extract_annotations(fixture)
+        .into_iter()
+        .map(|(range, annotation)| {
+            let token = token_map.token_by_range(range).expect("no token found");
+            let spacing = match annotation.as_str() {
+                "Alone" => Spacing::Alone,
+                "Joint" => Spacing::Joint,
+                a => panic!("unknown annotation: {}", a),
+            };
+            (token, spacing)
+        })
+        .collect();
+
+    let buf = TokenBuffer::from_subtree(&subtree);
+    let mut cursor = buf.begin();
+    while !cursor.eof() {
+        while let Some(token_tree) = cursor.token_tree() {
+            if let TokenTreeRef::Leaf(Leaf::Punct(Punct { spacing, id, .. }), _) = token_tree {
+                if let Some(expected) = annotations.remove(&id) {
+                    assert_eq!(expected, *spacing);
+                }
+            }
+            cursor = cursor.bump_subtree();
+        }
+        cursor = cursor.bump();
+    }
+
+    assert!(annotations.is_empty(), "unchecked annotations: {:?}", annotations);
+}
+
+#[test]
+fn punct_spacing() {
+    check_punct_spacing(
+        r#"
+fn main() {
+    0+0;
+   //^ Alone
+    0+(0);
+   //^ Alone
+    0<=0;
+   //^ Joint
+   // ^ Alone
+    0<=(0);
+   // ^ Alone
+    a=0;
+   //^ Alone
+    a=(0);
+   //^ Alone
+    a+=0;
+   //^ Joint
+   // ^ Alone
+    a+=(0);
+   // ^ Alone
+    a&&b;
+   //^ Joint
+   // ^ Alone
+    a&&(b);
+   // ^ Alone
+    foo::bar;
+   //  ^ Joint
+   //   ^ Alone
+    use foo::{bar,baz,};
+   //       ^ Alone
+   //            ^ Alone
+   //                ^ Alone
+    struct Struct<'a> {};
+   //            ^ Joint
+   //             ^ Joint
+    Struct::<0>;
+   //       ^ Alone
+    Struct::<{0}>;
+   //       ^ Alone
+    ;;
+  //^ Joint
+  // ^ Alone
+}
+        "#,
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/parser/Cargo.toml b/src/tools/rust-analyzer/crates/parser/Cargo.toml
index a286a6bcddd..d1420de8937 100644
--- a/src/tools/rust-analyzer/crates/parser/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/parser/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/paths/Cargo.toml b/src/tools/rust-analyzer/crates/paths/Cargo.toml
index 5e83de7d994..d23a63d2a97 100644
--- a/src/tools/rust-analyzer/crates/paths/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/paths/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
index 54879c1870c..f261f3def45 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-api/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
index 9d0da5dee9c..7991e125ab8 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [dependencies]
 proc-macro-srv = { version = "0.0.0", path = "../proc-macro-srv" }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
index e39026ac70b..a136abc12b7 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs
index 2f854bc1595..0ce099ae0ba 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/mod.rs
@@ -117,7 +117,7 @@ impl Abi {
                 let inner = unsafe { Abi_1_63::from_lib(lib, symbol_name) }?;
                 Ok(Abi::Abi1_63(inner))
             }
-            _ => Err(LoadProcMacroDylibError::UnsupportedABI),
+            _ => Err(LoadProcMacroDylibError::UnsupportedABI(info.version_string.clone())),
         }
     }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
index 7aba74e5396..0722cd89d72 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs
@@ -80,14 +80,14 @@ fn load_library(file: &Path) -> Result<Library, libloading::Error> {
 pub enum LoadProcMacroDylibError {
     Io(io::Error),
     LibLoading(libloading::Error),
-    UnsupportedABI,
+    UnsupportedABI(String),
 }
 
 impl fmt::Display for LoadProcMacroDylibError {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         match self {
             Self::Io(e) => e.fmt(f),
-            Self::UnsupportedABI => write!(f, "unsupported ABI version"),
+            Self::UnsupportedABI(v) => write!(f, "unsupported ABI `{v}`"),
             Self::LibLoading(e) => e.fmt(f),
         }
     }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 72a2dfe72d3..b4f5ebd157f 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -113,12 +113,12 @@ impl ProcMacroSrv {
 
     fn expander(&mut self, path: &Path) -> Result<&dylib::Expander, String> {
         let time = fs::metadata(path).and_then(|it| it.modified()).map_err(|err| {
-            format!("Failed to get file metadata for {}: {:?}", path.display(), err)
+            format!("Failed to get file metadata for {}: {}", path.display(), err)
         })?;
 
         Ok(match self.expanders.entry((path.to_path_buf(), time)) {
             Entry::Vacant(v) => v.insert(dylib::Expander::new(path).map_err(|err| {
-                format!("Cannot create expander for {}: {:?}", path.display(), err)
+                format!("Cannot create expander for {}: {}", path.display(), err)
             })?),
             Entry::Occupied(e) => e.into_mut(),
         })
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index b46cdddcf6b..cc0fc91fe98 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -19,7 +19,7 @@ fn test_derive_error() {
         expect![[r##"
             SUBTREE $
               IDENT   compile_error 4294967295
-              PUNCH   ! [joint] 4294967295
+              PUNCH   ! [alone] 4294967295
               SUBTREE () 4294967295
                 LITERAL "#[derive(DeriveError)] struct S ;" 4294967295
               PUNCH   ; [alone] 4294967295"##]],
@@ -109,7 +109,7 @@ fn test_fn_like_macro_clone_literals() {
               PUNCH   , [alone] 4294967295
               LITERAL 2_u32 4294967295
               PUNCH   , [alone] 4294967295
-              PUNCH   - [joint] 4294967295
+              PUNCH   - [alone] 4294967295
               LITERAL 4i64 4294967295
               PUNCH   , [alone] 4294967295
               LITERAL 3.14f32 4294967295
@@ -130,7 +130,7 @@ fn test_attr_macro() {
         expect![[r##"
             SUBTREE $
               IDENT   compile_error 4294967295
-              PUNCH   ! [joint] 4294967295
+              PUNCH   ! [alone] 4294967295
               SUBTREE () 4294967295
                 LITERAL "#[attr_error(some arguments)] mod m {}" 4294967295
               PUNCH   ; [alone] 4294967295"##]],
diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml
index 684477191b2..d2a79f91074 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-test/Cargo.toml
@@ -3,7 +3,7 @@ name = "proc-macro-test"
 version = "0.0.0"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 publish = false
 
 [lib]
diff --git a/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml b/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml
index 2d1fc3c5c7a..1bd14070e90 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/proc-macro-test/imp/Cargo.toml
@@ -3,7 +3,7 @@ name = "proc-macro-test-impl"
 version = "0.0.0"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 publish = false
 
 [lib]
diff --git a/src/tools/rust-analyzer/crates/profile/Cargo.toml b/src/tools/rust-analyzer/crates/profile/Cargo.toml
index 5697aea964f..01d1735bf78 100644
--- a/src/tools/rust-analyzer/crates/profile/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/profile/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/project-model/Cargo.toml b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
index cf9868740cb..39902a53214 100644
--- a/src/tools/rust-analyzer/crates/project-model/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/project-model/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
index a26a7c57acf..ae2b41f27d5 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/build_scripts.rs
@@ -69,7 +69,7 @@ impl WorkspaceBuildScripts {
                 cmd.args(&["check", "--quiet", "--workspace", "--message-format=json"]);
 
                 // --all-targets includes tests, benches and examples in addition to the
-                // default lib and bins. This is an independent concept from the --targets
+                // default lib and bins. This is an independent concept from the --target
                 // flag below.
                 cmd.arg("--all-targets");
 
diff --git a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
index b4c2ba43677..02ec7a4f6f9 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/cargo_workspace.rs
@@ -270,11 +270,7 @@ impl CargoWorkspace {
         config: &CargoConfig,
         progress: &dyn Fn(String),
     ) -> Result<cargo_metadata::Metadata> {
-        let target = config
-            .target
-            .clone()
-            .or_else(|| cargo_config_build_target(cargo_toml, &config.extra_env))
-            .or_else(|| rustc_discover_host_triple(cargo_toml, &config.extra_env));
+        let targets = find_list_of_build_targets(config, cargo_toml);
 
         let mut meta = MetadataCommand::new();
         meta.cargo_path(toolchain::cargo());
@@ -294,8 +290,12 @@ impl CargoWorkspace {
         }
         meta.current_dir(current_dir.as_os_str());
 
-        if let Some(target) = target {
-            meta.other_options(vec![String::from("--filter-platform"), target]);
+        if !targets.is_empty() {
+            let other_options: Vec<_> = targets
+                .into_iter()
+                .flat_map(|target| ["--filter-platform".to_string(), target])
+                .collect();
+            meta.other_options(other_options);
         }
 
         // FIXME: Fetching metadata is a slow process, as it might require
@@ -469,6 +469,19 @@ impl CargoWorkspace {
     }
 }
 
+fn find_list_of_build_targets(config: &CargoConfig, cargo_toml: &ManifestPath) -> Vec<String> {
+    if let Some(target) = &config.target {
+        return [target.into()].to_vec();
+    }
+
+    let build_targets = cargo_config_build_target(cargo_toml, &config.extra_env);
+    if !build_targets.is_empty() {
+        return build_targets;
+    }
+
+    rustc_discover_host_triple(cargo_toml, &config.extra_env).into_iter().collect()
+}
+
 fn rustc_discover_host_triple(
     cargo_toml: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
@@ -499,7 +512,7 @@ fn rustc_discover_host_triple(
 fn cargo_config_build_target(
     cargo_toml: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
-) -> Option<String> {
+) -> Vec<String> {
     let mut cargo_config = Command::new(toolchain::cargo());
     cargo_config.envs(extra_env);
     cargo_config
@@ -507,12 +520,21 @@ fn cargo_config_build_target(
         .args(&["-Z", "unstable-options", "config", "get", "build.target"])
         .env("RUSTC_BOOTSTRAP", "1");
     // if successful we receive `build.target = "target-triple"`
+    // or `build.target = ["<target 1>", ..]`
     tracing::debug!("Discovering cargo config target by {:?}", cargo_config);
-    match utf8_stdout(cargo_config) {
-        Ok(stdout) => stdout
-            .strip_prefix("build.target = \"")
-            .and_then(|stdout| stdout.strip_suffix('"'))
-            .map(ToOwned::to_owned),
-        Err(_) => None,
+    utf8_stdout(cargo_config).map(parse_output_cargo_config_build_target).unwrap_or_default()
+}
+
+fn parse_output_cargo_config_build_target(stdout: String) -> Vec<String> {
+    let trimmed = stdout.trim_start_matches("build.target = ").trim_matches('"');
+
+    if !trimmed.starts_with('[') {
+        return [trimmed.to_string()].to_vec();
+    }
+
+    let res = serde_json::from_str(trimmed);
+    if let Err(e) = &res {
+        tracing::warn!("Failed to parse `build.target` as an array of target: {}`", e);
     }
+    res.unwrap_or_default()
 }
diff --git a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
index fa8d76f3f45..f6c09a27c9d 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/sysroot.rs
@@ -128,14 +128,18 @@ impl Sysroot {
         }
 
         if let Some(alloc) = sysroot.by_name("alloc") {
-            if let Some(core) = sysroot.by_name("core") {
-                sysroot.crates[alloc].deps.push(core);
+            for dep in ALLOC_DEPS.trim().lines() {
+                if let Some(dep) = sysroot.by_name(dep) {
+                    sysroot.crates[alloc].deps.push(dep)
+                }
             }
         }
 
         if let Some(proc_macro) = sysroot.by_name("proc_macro") {
-            if let Some(std) = sysroot.by_name("std") {
-                sysroot.crates[proc_macro].deps.push(std);
+            for dep in PROC_MACRO_DEPS.trim().lines() {
+                if let Some(dep) = sysroot.by_name(dep) {
+                    sysroot.crates[proc_macro].deps.push(dep)
+                }
             }
         }
 
@@ -239,6 +243,7 @@ fn get_rust_src(sysroot_path: &AbsPath) -> Option<AbsPathBuf> {
 
 const SYSROOT_CRATES: &str = "
 alloc
+backtrace
 core
 panic_abort
 panic_unwind
@@ -246,17 +251,19 @@ proc_macro
 profiler_builtins
 std
 stdarch/crates/std_detect
-term
 test
 unwind";
 
+const ALLOC_DEPS: &str = "core";
+
 const STD_DEPS: &str = "
 alloc
-core
-panic_abort
 panic_unwind
+panic_abort
+core
 profiler_builtins
+unwind
 std_detect
-term
-test
-unwind";
+test";
+
+const PROC_MACRO_DEPS: &str = "std";
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index e2444e24974..a1cb438bddc 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -1566,10 +1566,10 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    1,
+                                    3,
                                 ),
                                 name: CrateName(
-                                    "core",
+                                    "panic_unwind",
                                 ),
                                 prelude: true,
                             },
@@ -1584,10 +1584,10 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    3,
+                                    1,
                                 ),
                                 name: CrateName(
-                                    "panic_unwind",
+                                    "core",
                                 ),
                                 prelude: true,
                             },
@@ -1602,40 +1602,31 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    7,
+                                    9,
                                 ),
                                 name: CrateName(
-                                    "std_detect",
+                                    "unwind",
                                 ),
                                 prelude: true,
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    8,
+                                    7,
                                 ),
                                 name: CrateName(
-                                    "term",
+                                    "std_detect",
                                 ),
                                 prelude: true,
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    9,
+                                    8,
                                 ),
                                 name: CrateName(
                                     "test",
                                 ),
                                 prelude: true,
                             },
-                            Dependency {
-                                crate_id: CrateId(
-                                    10,
-                                ),
-                                name: CrateName(
-                                    "unwind",
-                                ),
-                                prelude: true,
-                            },
                         ],
                         proc_macro: Err(
                             "no proc macro loaded for sysroot crate",
@@ -1690,40 +1681,6 @@ fn rust_project_hello_world_project_model() {
                         display_name: Some(
                             CrateDisplayName {
                                 crate_name: CrateName(
-                                    "term",
-                                ),
-                                canonical_name: "term",
-                            },
-                        ),
-                        cfg_options: CfgOptions(
-                            [],
-                        ),
-                        potential_cfg_options: CfgOptions(
-                            [],
-                        ),
-                        env: Env {
-                            entries: {},
-                        },
-                        dependencies: [],
-                        proc_macro: Err(
-                            "no proc macro loaded for sysroot crate",
-                        ),
-                        origin: Lang(
-                            Other,
-                        ),
-                        is_proc_macro: false,
-                    },
-                    CrateId(
-                        9,
-                    ): CrateData {
-                        root_file_id: FileId(
-                            10,
-                        ),
-                        edition: Edition2018,
-                        version: None,
-                        display_name: Some(
-                            CrateDisplayName {
-                                crate_name: CrateName(
                                     "test",
                                 ),
                                 canonical_name: "test",
@@ -1748,10 +1705,10 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        10,
+                        9,
                     ): CrateData {
                         root_file_id: FileId(
-                            11,
+                            10,
                         ),
                         edition: Edition2018,
                         version: None,
@@ -1782,10 +1739,10 @@ fn rust_project_hello_world_project_model() {
                         is_proc_macro: false,
                     },
                     CrateId(
-                        11,
+                        10,
                     ): CrateData {
                         root_file_id: FileId(
-                            12,
+                            11,
                         ),
                         edition: Edition2018,
                         version: None,
@@ -1836,7 +1793,7 @@ fn rust_project_hello_world_project_model() {
                             },
                             Dependency {
                                 crate_id: CrateId(
-                                    9,
+                                    8,
                                 ),
                                 name: CrateName(
                                     "test",
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 2780c62ed11..3d199ed24af 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/workspace.rs
@@ -377,6 +377,21 @@ impl ProjectWorkspace {
         }
     }
 
+    pub fn find_sysroot_proc_macro_srv(&self) -> Option<AbsPathBuf> {
+        match self {
+            ProjectWorkspace::Cargo { sysroot: Some(sysroot), .. }
+            | ProjectWorkspace::Json { sysroot: Some(sysroot), .. } => {
+                let standalone_server_name =
+                    format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
+                ["libexec", "lib"]
+                    .into_iter()
+                    .map(|segment| sysroot.root().join(segment).join(&standalone_server_name))
+                    .find(|server_path| std::fs::metadata(&server_path).is_ok())
+            }
+            _ => None,
+        }
+    }
+
     /// Returns the roots for the current `ProjectWorkspace`
     /// The return type contains the path and whether or not
     /// the root is a member of the current workspace
@@ -509,14 +524,14 @@ impl ProjectWorkspace {
                 build_scripts,
                 toolchain: _,
             } => cargo_to_crate_graph(
-                rustc_cfg.clone(),
-                cfg_overrides,
                 load_proc_macro,
                 load,
+                rustc,
                 cargo,
-                build_scripts,
                 sysroot.as_ref(),
-                rustc,
+                rustc_cfg.clone(),
+                cfg_overrides,
+                build_scripts,
             ),
             ProjectWorkspace::DetachedFiles { files, sysroot, rustc_cfg } => {
                 detached_files_to_crate_graph(rustc_cfg.clone(), load, files, sysroot)
@@ -602,7 +617,7 @@ fn project_json_to_crate_graph(
     for (from, krate) in project.crates() {
         if let Some(&from) = crates.get(&from) {
             if let Some((public_deps, libproc_macro)) = &sysroot_deps {
-                public_deps.add(from, &mut crate_graph);
+                public_deps.add_to_crate_graph(&mut crate_graph, from);
                 if krate.is_proc_macro {
                     if let Some(proc_macro) = libproc_macro {
                         add_dep(
@@ -626,14 +641,14 @@ fn project_json_to_crate_graph(
 }
 
 fn cargo_to_crate_graph(
-    rustc_cfg: Vec<CfgFlag>,
-    override_cfg: &CfgOverrides,
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
+    rustc: &Option<CargoWorkspace>,
     cargo: &CargoWorkspace,
-    build_scripts: &WorkspaceBuildScripts,
     sysroot: Option<&Sysroot>,
-    rustc: &Option<CargoWorkspace>,
+    rustc_cfg: Vec<CfgFlag>,
+    override_cfg: &CfgOverrides,
+    build_scripts: &WorkspaceBuildScripts,
 ) -> CrateGraph {
     let _p = profile::span("cargo_to_crate_graph");
     let mut crate_graph = CrateGraph::default();
@@ -642,13 +657,15 @@ fn cargo_to_crate_graph(
         None => (SysrootPublicDeps::default(), None),
     };
 
-    let mut cfg_options = CfgOptions::default();
-    cfg_options.extend(rustc_cfg);
+    let cfg_options = {
+        let mut cfg_options = CfgOptions::default();
+        cfg_options.extend(rustc_cfg);
+        cfg_options.insert_atom("debug_assertions".into());
+        cfg_options
+    };
 
     let mut pkg_to_lib_crate = FxHashMap::default();
 
-    cfg_options.insert_atom("debug_assertions".into());
-
     let mut pkg_crates = FxHashMap::default();
     // Does any crate signal to rust-analyzer that they need the rustc_private crates?
     let mut has_private = false;
@@ -723,7 +740,7 @@ fn cargo_to_crate_graph(
         // Set deps to the core, std and to the lib target of the current package
         for &(from, kind) in pkg_crates.get(&pkg).into_iter().flatten() {
             // Add sysroot deps first so that a lib target named `core` etc. can overwrite them.
-            public_deps.add(from, &mut crate_graph);
+            public_deps.add_to_crate_graph(&mut crate_graph, from);
 
             if let Some((to, name)) = lib_tgt.clone() {
                 if to != from && kind != TargetKind::BuildScript {
@@ -767,15 +784,16 @@ fn cargo_to_crate_graph(
         if let Some(rustc_workspace) = rustc {
             handle_rustc_crates(
                 &mut crate_graph,
-                rustc_workspace,
+                &mut pkg_to_lib_crate,
                 load,
-                &cfg_options,
-                override_cfg,
                 load_proc_macro,
-                &mut pkg_to_lib_crate,
-                &public_deps,
+                rustc_workspace,
                 cargo,
+                &public_deps,
+                libproc_macro,
                 &pkg_crates,
+                &cfg_options,
+                override_cfg,
                 build_scripts,
             );
         }
@@ -825,28 +843,29 @@ fn detached_files_to_crate_graph(
             },
         );
 
-        public_deps.add(detached_file_crate, &mut crate_graph);
+        public_deps.add_to_crate_graph(&mut crate_graph, detached_file_crate);
     }
     crate_graph
 }
 
 fn handle_rustc_crates(
     crate_graph: &mut CrateGraph,
-    rustc_workspace: &CargoWorkspace,
+    pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
     load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
-    cfg_options: &CfgOptions,
-    override_cfg: &CfgOverrides,
     load_proc_macro: &mut dyn FnMut(&str, &AbsPath) -> ProcMacroLoadResult,
-    pkg_to_lib_crate: &mut FxHashMap<Package, CrateId>,
-    public_deps: &SysrootPublicDeps,
+    rustc_workspace: &CargoWorkspace,
     cargo: &CargoWorkspace,
+    public_deps: &SysrootPublicDeps,
+    libproc_macro: Option<CrateId>,
     pkg_crates: &FxHashMap<Package, Vec<(CrateId, TargetKind)>>,
+    cfg_options: &CfgOptions,
+    override_cfg: &CfgOverrides,
     build_scripts: &WorkspaceBuildScripts,
 ) {
     let mut rustc_pkg_crates = FxHashMap::default();
     // The root package of the rustc-dev component is rustc_driver, so we match that
     let root_pkg =
-        rustc_workspace.packages().find(|package| rustc_workspace[*package].name == "rustc_driver");
+        rustc_workspace.packages().find(|&package| rustc_workspace[package].name == "rustc_driver");
     // The rustc workspace might be incomplete (such as if rustc-dev is not
     // installed for the current toolchain) and `rustc_source` is set to discover.
     if let Some(root_pkg) = root_pkg {
@@ -901,7 +920,16 @@ fn handle_rustc_crates(
                     );
                     pkg_to_lib_crate.insert(pkg, crate_id);
                     // Add dependencies on core / std / alloc for this crate
-                    public_deps.add(crate_id, crate_graph);
+                    public_deps.add_to_crate_graph(crate_graph, crate_id);
+                    if let Some(proc_macro) = libproc_macro {
+                        add_dep_with_prelude(
+                            crate_graph,
+                            crate_id,
+                            CrateName::new("proc_macro").unwrap(),
+                            proc_macro,
+                            rustc_workspace[tgt].is_proc_macro,
+                        );
+                    }
                     rustc_pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id);
                 }
             }
@@ -1009,7 +1037,7 @@ struct SysrootPublicDeps {
 
 impl SysrootPublicDeps {
     /// Makes `from` depend on the public sysroot crates.
-    fn add(&self, from: CrateId, crate_graph: &mut CrateGraph) {
+    fn add_to_crate_graph(&self, crate_graph: &mut CrateGraph, from: CrateId) {
         for (name, krate, prelude) in &self.deps {
             add_dep_with_prelude(crate_graph, from, name.clone(), *krate, *prelude);
         }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index 7ae5324ab05..56f14fe1874 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -8,7 +8,7 @@ documentation = "https://rust-analyzer.github.io/manual.html"
 license = "MIT OR Apache-2.0"
 autobins = false
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
index 6ede194babc..cf51cf15a0e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -3,11 +3,11 @@
 use std::mem;
 
 use cfg::{CfgAtom, CfgExpr};
-use ide::{FileId, RunnableKind, TestId};
+use ide::{Cancellable, FileId, RunnableKind, TestId};
 use project_model::{self, CargoFeatures, ManifestPath, TargetKind};
 use vfs::AbsPathBuf;
 
-use crate::{global_state::GlobalStateSnapshot, Result};
+use crate::global_state::GlobalStateSnapshot;
 
 /// Abstract representation of Cargo target.
 ///
@@ -29,7 +29,7 @@ impl CargoTargetSpec {
         spec: Option<CargoTargetSpec>,
         kind: &RunnableKind,
         cfg: &Option<CfgExpr>,
-    ) -> Result<(Vec<String>, Vec<String>)> {
+    ) -> (Vec<String>, Vec<String>) {
         let mut args = Vec::new();
         let mut extra_args = Vec::new();
 
@@ -111,13 +111,13 @@ impl CargoTargetSpec {
                 }
             }
         }
-        Ok((args, extra_args))
+        (args, extra_args)
     }
 
     pub(crate) fn for_file(
         global_state_snapshot: &GlobalStateSnapshot,
         file_id: FileId,
-    ) -> Result<Option<CargoTargetSpec>> {
+    ) -> Cancellable<Option<CargoTargetSpec>> {
         let crate_id = match &*global_state_snapshot.analysis.crates_for(file_id)? {
             &[crate_id, ..] => crate_id,
             _ => return Ok(None),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
index 5dba545b871..762d7d3a18e 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -60,24 +60,12 @@ pub fn load_workspace(
     };
 
     let proc_macro_client = if load_config.with_proc_macro {
-        let mut path = AbsPathBuf::assert(std::env::current_exe()?);
-        let mut args = vec!["proc-macro"];
-
-        if let ProjectWorkspace::Cargo { sysroot, .. } | ProjectWorkspace::Json { sysroot, .. } =
-            &ws
-        {
-            if let Some(sysroot) = sysroot.as_ref() {
-                let standalone_server_name =
-                    format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
-                let server_path = sysroot.root().join("libexec").join(&standalone_server_name);
-                if std::fs::metadata(&server_path).is_ok() {
-                    path = server_path;
-                    args = vec![];
-                }
-            }
-        }
+        let (server_path, args): (_, &[_]) = match ws.find_sysroot_proc_macro_srv() {
+            Some(server_path) => (server_path, &[]),
+            None => (AbsPathBuf::assert(std::env::current_exe()?), &["proc-macro"]),
+        };
 
-        ProcMacroServer::spawn(path.clone(), args.clone()).map_err(|e| e.to_string())
+        ProcMacroServer::spawn(server_path, args).map_err(|e| e.to_string())
     } else {
         Err("proc macro server disabled".to_owned())
     };
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index ca7ba896b67..9edd045ab07 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -47,30 +47,27 @@ impl flags::Scip {
 
         let si = StaticIndex::compute(&analysis);
 
-        let mut index = scip_types::Index {
-            metadata: Some(scip_types::Metadata {
-                version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
-                tool_info: Some(scip_types::ToolInfo {
-                    name: "rust-analyzer".to_owned(),
-                    version: "0.1".to_owned(),
-                    arguments: vec![],
-                    ..Default::default()
-                })
-                .into(),
-                project_root: format!(
-                    "file://{}",
-                    path.normalize()
-                        .as_os_str()
-                        .to_str()
-                        .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
-                        .to_string()
-                ),
-                text_document_encoding: scip_types::TextEncoding::UTF8.into(),
-                ..Default::default()
+        let metadata = scip_types::Metadata {
+            version: scip_types::ProtocolVersion::UnspecifiedProtocolVersion.into(),
+            tool_info: Some(scip_types::ToolInfo {
+                name: "rust-analyzer".to_owned(),
+                version: "0.1".to_owned(),
+                arguments: vec![],
+                special_fields: Default::default(),
             })
             .into(),
-            ..Default::default()
+            project_root: format!(
+                "file://{}",
+                path.normalize()
+                    .as_os_str()
+                    .to_str()
+                    .ok_or(anyhow::anyhow!("Unable to normalize project_root path"))?
+                    .to_string()
+            ),
+            text_document_encoding: scip_types::TextEncoding::UTF8.into(),
+            special_fields: Default::default(),
         };
+        let mut documents = Vec::new();
 
         let mut symbols_emitted: HashSet<TokenId> = HashSet::default();
         let mut tokens_to_symbol: HashMap<TokenId, String> = HashMap::new();
@@ -95,18 +92,14 @@ impl flags::Scip {
                 endings: LineEndings::Unix,
             };
 
-            let mut doc = scip_types::Document {
-                relative_path,
-                language: "rust".to_string(),
-                ..Default::default()
-            };
+            let mut occurrences = Vec::new();
+            let mut symbols = Vec::new();
 
-            tokens.into_iter().for_each(|(range, id)| {
+            tokens.into_iter().for_each(|(text_range, id)| {
                 let token = si.tokens.get(id).unwrap();
 
-                let mut occurrence = scip_types::Occurrence::default();
-                occurrence.range = text_range_to_scip_range(&line_index, range);
-                occurrence.symbol = tokens_to_symbol
+                let range = text_range_to_scip_range(&line_index, text_range);
+                let symbol = tokens_to_symbol
                     .entry(id)
                     .or_insert_with(|| {
                         let symbol = token_to_symbol(&token).unwrap_or_else(&mut new_local_symbol);
@@ -114,34 +107,62 @@ impl flags::Scip {
                     })
                     .clone();
 
+                let mut symbol_roles = Default::default();
+
                 if let Some(def) = token.definition {
-                    if def.range == range {
-                        occurrence.symbol_roles |= scip_types::SymbolRole::Definition as i32;
+                    if def.range == text_range {
+                        symbol_roles |= scip_types::SymbolRole::Definition as i32;
                     }
 
                     if symbols_emitted.insert(id) {
-                        let mut symbol_info = scip_types::SymbolInformation::default();
-                        symbol_info.symbol = occurrence.symbol.clone();
-                        if let Some(hover) = &token.hover {
-                            if !hover.markup.as_str().is_empty() {
-                                symbol_info.documentation = vec![hover.markup.as_str().to_string()];
-                            }
-                        }
-
-                        doc.symbols.push(symbol_info)
+                        let documentation = token
+                            .hover
+                            .as_ref()
+                            .map(|hover| hover.markup.as_str())
+                            .filter(|it| !it.is_empty())
+                            .map(|it| vec![it.to_owned()]);
+                        let symbol_info = scip_types::SymbolInformation {
+                            symbol: symbol.clone(),
+                            documentation: documentation.unwrap_or_default(),
+                            relationships: Vec::new(),
+                            special_fields: Default::default(),
+                        };
+
+                        symbols.push(symbol_info)
                     }
                 }
 
-                doc.occurrences.push(occurrence);
+                occurrences.push(scip_types::Occurrence {
+                    range,
+                    symbol,
+                    symbol_roles,
+                    override_documentation: Vec::new(),
+                    syntax_kind: Default::default(),
+                    diagnostics: Vec::new(),
+                    special_fields: Default::default(),
+                });
             });
 
-            if doc.occurrences.is_empty() {
+            if occurrences.is_empty() {
                 continue;
             }
 
-            index.documents.push(doc);
+            documents.push(scip_types::Document {
+                relative_path,
+                language: "rust".to_string(),
+                occurrences,
+                symbols,
+                special_fields: Default::default(),
+            });
         }
 
+        let index = scip_types::Index {
+            metadata: Some(metadata).into(),
+            documents,
+            external_symbols: Vec::new(),
+            special_fields: Default::default(),
+        };
+
         scip::write_message_to_file("index.scip", index)
             .map_err(|err| anyhow::anyhow!("Failed to write scip to file: {}", err))?;
 
@@ -181,7 +202,7 @@ fn new_descriptor_str(
         name: name.to_string(),
         disambiguator: "".to_string(),
         suffix: suffix.into(),
-        ..Default::default()
+        special_fields: Default::default(),
     }
 }
 
@@ -232,11 +253,11 @@ fn token_to_symbol(token: &TokenStaticData) -> Option<scip_types::Symbol> {
             manager: "cargo".to_string(),
             name: package_name,
             version: version.unwrap_or_else(|| ".".to_string()),
-            ..Default::default()
+            special_fields: Default::default(),
         })
         .into(),
         descriptors,
-        ..Default::default()
+        special_fields: Default::default(),
     })
 }
 
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 4072ae585db..6b2f22faa71 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -118,9 +118,11 @@ config_data! {
         /// This option does not take effect until rust-analyzer is restarted.
         cargo_sysroot: Option<String>    = "\"discover\"",
         /// Compilation target override (target triple).
+        // FIXME(@poliorcetics): move to multiple targets here too, but this will need more work
+        // than `checkOnSave_target`
         cargo_target: Option<String>     = "null",
         /// Unsets `#[cfg(test)]` for the specified crates.
-        cargo_unsetTest: Vec<String>   = "[\"core\"]",
+        cargo_unsetTest: Vec<String>     = "[\"core\"]",
 
         /// Check all targets and tests (`--all-targets`).
         checkOnSave_allTargets: bool                     = "true",
@@ -157,7 +159,7 @@ config_data! {
         checkOnSave_noDefaultFeatures: Option<bool>      = "null",
         /// Override the command rust-analyzer uses instead of `cargo check` for
         /// diagnostics on save. The command is required to output json and
-        /// should therefor include `--message-format=json` or a similar option.
+        /// should therefore include `--message-format=json` or a similar option.
         ///
         /// If you're changing this because you're using some tool wrapping
         /// Cargo, you might also want to change
@@ -174,9 +176,13 @@ config_data! {
         /// ```
         /// .
         checkOnSave_overrideCommand: Option<Vec<String>> = "null",
-        /// Check for a specific target. Defaults to
-        /// `#rust-analyzer.cargo.target#`.
-        checkOnSave_target: Option<String>               = "null",
+        /// Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
+        ///
+        /// Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
+        /// `["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
+        ///
+        /// Aliased as `"checkOnSave.targets"`.
+        checkOnSave_target | checkOnSave_targets: CheckOnSaveTargets           = "[]",
 
         /// 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.
@@ -261,6 +267,7 @@ config_data! {
         files_excludeDirs: Vec<PathBuf> = "[]",
         /// Controls file watching implementation.
         files_watcher: FilesWatcherDef = "\"client\"",
+
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = "true",
         /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
@@ -320,6 +327,8 @@ config_data! {
         inlayHints_closingBraceHints_minLines: usize               = "25",
         /// Whether to show inlay type hints for return types of closures.
         inlayHints_closureReturnTypeHints_enable: ClosureReturnTypeHintsDef  = "\"never\"",
+        /// Whether to show inlay hints for type adjustments.
+        inlayHints_expressionAdjustmentHints_enable: AdjustmentHintsDef = "\"never\"",
         /// Whether to show inlay type hints for elided lifetimes in function signatures.
         inlayHints_lifetimeElisionHints_enable: LifetimeElisionDef = "\"never\"",
         /// Whether to prefer using parameter names as the name for elided lifetime hints if possible.
@@ -329,7 +338,8 @@ config_data! {
         /// Whether to show function parameter name inlay hints at the call
         /// site.
         inlayHints_parameterHints_enable: bool                     = "true",
-        /// Whether to show inlay type hints for compiler inserted reborrows.
+        /// Whether to show inlay hints for compiler inserted reborrows.
+        /// This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
         inlayHints_reborrowHints_enable: ReborrowHintsDef          = "\"never\"",
         /// Whether to render leading colons for type hints, and trailing colons for parameter hints.
         inlayHints_renderColons: bool                              = "true",
@@ -1143,11 +1153,10 @@ impl Config {
             }
             Some(_) | None => FlycheckConfig::CargoCommand {
                 command: self.data.checkOnSave_command.clone(),
-                target_triple: self
-                    .data
-                    .checkOnSave_target
-                    .clone()
-                    .or_else(|| self.data.cargo_target.clone()),
+                target_triples: match &self.data.checkOnSave_target.0[..] {
+                    [] => self.data.cargo_target.clone().into_iter().collect(),
+                    targets => targets.into(),
+                },
                 all_targets: self.data.checkOnSave_allTargets,
                 no_default_features: self
                     .data
@@ -1200,10 +1209,15 @@ impl Config {
             hide_closure_initialization_hints: self
                 .data
                 .inlayHints_typeHints_hideClosureInitialization,
-            reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
-                ReborrowHintsDef::Always => ide::ReborrowHints::Always,
-                ReborrowHintsDef::Never => ide::ReborrowHints::Never,
-                ReborrowHintsDef::Mutable => ide::ReborrowHints::MutableOnly,
+            adjustment_hints: match self.data.inlayHints_expressionAdjustmentHints_enable {
+                AdjustmentHintsDef::Always => ide::AdjustmentHints::Always,
+                AdjustmentHintsDef::Never => match self.data.inlayHints_reborrowHints_enable {
+                    ReborrowHintsDef::Always | ReborrowHintsDef::Mutable => {
+                        ide::AdjustmentHints::ReborrowOnly
+                    }
+                    ReborrowHintsDef::Never => ide::AdjustmentHints::Never,
+                },
+                AdjustmentHintsDef::Reborrow => ide::AdjustmentHints::ReborrowOnly,
             },
             binding_mode_hints: self.data.inlayHints_bindingModeHints_enable,
             param_names_for_lifetime_elision_hints: self
@@ -1538,6 +1552,7 @@ mod de_unit_v {
     named_unit_variant!(all);
     named_unit_variant!(skip_trivial);
     named_unit_variant!(mutable);
+    named_unit_variant!(reborrow);
     named_unit_variant!(with_block);
 }
 
@@ -1648,6 +1663,9 @@ enum InvocationStrategy {
 }
 
 #[derive(Deserialize, Debug, Clone)]
+struct CheckOnSaveTargets(#[serde(deserialize_with = "single_or_array")] Vec<String>);
+
+#[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
 enum InvocationLocation {
     Root,
@@ -1688,6 +1706,17 @@ enum ReborrowHintsDef {
 }
 
 #[derive(Deserialize, Debug, Clone)]
+#[serde(untagged)]
+enum AdjustmentHintsDef {
+    #[serde(deserialize_with = "true_or_always")]
+    Always,
+    #[serde(deserialize_with = "false_or_never")]
+    Never,
+    #[serde(deserialize_with = "de_unit_v::reborrow")]
+    Reborrow,
+}
+
+#[derive(Deserialize, Debug, Clone)]
 #[serde(rename_all = "snake_case")]
 enum FilesWatcherDef {
     Client,
@@ -1996,6 +2025,19 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "Only show mutable reborrow hints."
             ]
         },
+        "AdjustmentHintsDef" => set! {
+            "type": "string",
+            "enum": [
+                "always",
+                "never",
+                "reborrow"
+            ],
+            "enumDescriptions": [
+                "Always show all adjustment hints.",
+                "Never show adjustment hints.",
+                "Only show auto borrow and dereference adjustment hints."
+            ]
+        },
         "CargoFeaturesDef" => set! {
             "anyOf": [
                 {
@@ -2084,6 +2126,17 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
                 "The command will be executed in the project root."
             ],
         },
+        "CheckOnSaveTargets" => set! {
+            "anyOf": [
+                {
+                    "type": "string",
+                },
+                {
+                    "type": "array",
+                    "items": { "type": "string" }
+                },
+            ],
+        },
         _ => panic!("missing entry for {}: {}", ty, default),
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 189ac2fbf53..beb23c54c9f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -359,14 +359,15 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
         .iter()
         .flat_map(|primary_span| {
             let primary_location = primary_location(config, workspace_root, primary_span, snap);
-
-            let mut message = message.clone();
-            if needs_primary_span_label {
-                if let Some(primary_span_label) = &primary_span.label {
-                    format_to!(message, "\n{}", primary_span_label);
+            let message = {
+                let mut message = message.clone();
+                if needs_primary_span_label {
+                    if let Some(primary_span_label) = &primary_span.label {
+                        format_to!(message, "\n{}", primary_span_label);
+                    }
                 }
-            }
-
+                message
+            };
             // Each primary diagnostic span may result in multiple LSP diagnostics.
             let mut diagnostics = Vec::new();
 
@@ -417,7 +418,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
                     message: message.clone(),
                     related_information: Some(information_for_additional_diagnostic),
                     tags: if tags.is_empty() { None } else { Some(tags.clone()) },
-                    data: None,
+                    data: Some(serde_json::json!({ "rendered": rd.rendered })),
                 };
                 diagnostics.push(MappedRustDiagnostic {
                     url: secondary_location.uri,
@@ -449,7 +450,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
                         }
                     },
                     tags: if tags.is_empty() { None } else { Some(tags.clone()) },
-                    data: None,
+                    data: Some(serde_json::json!({ "rendered": rd.rendered })),
                 },
                 fix: None,
             });
@@ -534,7 +535,8 @@ mod tests {
             Config::new(workspace_root.to_path_buf(), ClientCapabilities::default()),
         );
         let snap = state.snapshot();
-        let actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap);
+        let mut actual = map_rust_diagnostic_to_lsp(&config, &diagnostic, workspace_root, &snap);
+        actual.iter_mut().for_each(|diag| diag.diagnostic.data = None);
         expect.assert_debug_eq(&actual)
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs
index 936957bab48..dd433b0f4d3 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/from_proto.rs
@@ -42,8 +42,10 @@ pub(crate) fn offset(line_index: &LineIndex, position: lsp_types::Position) -> R
 pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Result<TextRange> {
     let start = offset(line_index, range.start)?;
     let end = offset(line_index, range.end)?;
-    let text_range = TextRange::new(start, end);
-    Ok(text_range)
+    match end < start {
+        true => Err(format_err!("Invalid Range").into()),
+        false => Ok(TextRange::new(start, end)),
+    }
 }
 
 pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 74277ff2e57..4e8bc8d6462 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -100,7 +100,7 @@ pub(crate) struct GlobalState {
     /// the user just adds comments or whitespace to Cargo.toml, we do not want
     /// to invalidate any salsa caches.
     pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
-    pub(crate) fetch_workspaces_queue: OpQueue<Vec<anyhow::Result<ProjectWorkspace>>>,
+    pub(crate) fetch_workspaces_queue: OpQueue<Option<Vec<anyhow::Result<ProjectWorkspace>>>>,
     pub(crate) fetch_build_data_queue:
         OpQueue<(Arc<Vec<ProjectWorkspace>>, Vec<anyhow::Result<WorkspaceBuildScripts>>)>,
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
index 34795a8eb40..d190a9f4e2c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers.rs
@@ -9,9 +9,9 @@ use std::{
 
 use anyhow::Context;
 use ide::{
-    AnnotationConfig, AssistKind, AssistResolveStrategy, FileId, FilePosition, FileRange,
-    HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable, RunnableKind,
-    SingleResolve, SourceChange, TextEdit,
+    AnnotationConfig, AssistKind, AssistResolveStrategy, Cancellable, FileId, FilePosition,
+    FileRange, HoverAction, HoverGotoTypeData, Query, RangeInfo, ReferenceCategory, Runnable,
+    RunnableKind, SingleResolve, SourceChange, TextEdit,
 };
 use ide_db::SymbolKind;
 use lsp_server::ErrorCode;
@@ -556,7 +556,7 @@ pub(crate) fn handle_will_rename_files(
     if source_change.source_file_edits.is_empty() {
         Ok(None)
     } else {
-        to_proto::workspace_edit(&snap, source_change).map(Some)
+        Ok(Some(to_proto::workspace_edit(&snap, source_change)?))
     }
 }
 
@@ -1313,7 +1313,7 @@ pub(crate) fn handle_ssr(
         position,
         selections,
     )??;
-    to_proto::workspace_edit(&snap, source_change)
+    to_proto::workspace_edit(&snap, source_change).map_err(Into::into)
 }
 
 pub(crate) fn publish_diagnostics(
@@ -1354,13 +1354,12 @@ pub(crate) fn handle_inlay_hints(
 ) -> Result<Option<Vec<InlayHint>>> {
     let _p = profile::span("handle_inlay_hints");
     let document_uri = &params.text_document.uri;
-    let file_id = from_proto::file_id(&snap, document_uri)?;
-    let line_index = snap.file_line_index(file_id)?;
-    let range = from_proto::file_range(
+    let FileRange { file_id, range } = from_proto::file_range(
         &snap,
         TextDocumentIdentifier::new(document_uri.to_owned()),
         params.range,
     )?;
+    let line_index = snap.file_line_index(file_id)?;
     let inlay_hints_config = snap.config.inlay_hints();
     Ok(Some(
         snap.analysis
@@ -1369,7 +1368,7 @@ pub(crate) fn handle_inlay_hints(
             .map(|it| {
                 to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
             })
-            .collect::<Result<Vec<_>>>()?,
+            .collect::<Cancellable<Vec<_>>>()?,
     ))
 }
 
@@ -1426,7 +1425,7 @@ pub(crate) fn handle_call_hierarchy_prepare(
         .into_iter()
         .filter(|it| it.kind == Some(SymbolKind::Function))
         .map(|it| to_proto::call_hierarchy_item(&snap, it))
-        .collect::<Result<Vec<_>>>()?;
+        .collect::<Cancellable<Vec<_>>>()?;
 
     Ok(Some(res))
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs
index 0d424b91570..2945dba12f2 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/line_index.rs
@@ -27,10 +27,6 @@ pub(crate) enum LineEndings {
 impl LineEndings {
     /// Replaces `\r\n` with `\n` in-place in `src`.
     pub(crate) fn normalize(src: String) -> (String, LineEndings) {
-        if !src.as_bytes().contains(&b'\r') {
-            return (src, LineEndings::Unix);
-        }
-
         // We replace `\r\n` with `\n` in-place, which doesn't break utf-8 encoding.
         // While we *can* call `as_mut_vec` and do surgery on the live string
         // directly, let's rather steal the contents of `src`. This makes the code
@@ -39,10 +35,19 @@ impl LineEndings {
         let mut buf = src.into_bytes();
         let mut gap_len = 0;
         let mut tail = buf.as_mut_slice();
+        let mut crlf_seen = false;
+
+        let find_crlf = |src: &[u8]| src.windows(2).position(|it| it == b"\r\n");
+
         loop {
             let idx = match find_crlf(&tail[gap_len..]) {
-                None => tail.len(),
-                Some(idx) => idx + gap_len,
+                None if crlf_seen => tail.len(),
+                // SAFETY: buf is unchanged and therefore still contains utf8 data
+                None => return (unsafe { String::from_utf8_unchecked(buf) }, LineEndings::Unix),
+                Some(idx) => {
+                    crlf_seen = true;
+                    idx + gap_len
+                }
             };
             tail.copy_within(gap_len..idx, 0);
             tail = &mut tail[idx - gap_len..];
@@ -54,15 +59,48 @@ impl LineEndings {
 
         // Account for removed `\r`.
         // After `set_len`, `buf` is guaranteed to contain utf-8 again.
-        let new_len = buf.len() - gap_len;
         let src = unsafe {
+            let new_len = buf.len() - gap_len;
             buf.set_len(new_len);
             String::from_utf8_unchecked(buf)
         };
-        return (src, LineEndings::Dos);
+        (src, LineEndings::Dos)
+    }
+}
 
-        fn find_crlf(src: &[u8]) -> Option<usize> {
-            src.windows(2).position(|it| it == b"\r\n")
-        }
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn unix() {
+        let src = "a\nb\nc\n\n\n\n";
+        let (res, endings) = LineEndings::normalize(src.into());
+        assert_eq!(endings, LineEndings::Unix);
+        assert_eq!(res, src);
+    }
+
+    #[test]
+    fn dos() {
+        let src = "\r\na\r\n\r\nb\r\nc\r\n\r\n\r\n\r\n";
+        let (res, endings) = LineEndings::normalize(src.into());
+        assert_eq!(endings, LineEndings::Dos);
+        assert_eq!(res, "\na\n\nb\nc\n\n\n\n");
+    }
+
+    #[test]
+    fn mixed() {
+        let src = "a\r\nb\r\nc\r\n\n\r\n\n";
+        let (res, endings) = LineEndings::normalize(src.into());
+        assert_eq!(endings, LineEndings::Dos);
+        assert_eq!(res, "a\nb\nc\n\n\n\n");
+    }
+
+    #[test]
+    fn none() {
+        let src = "abc";
+        let (res, endings) = LineEndings::normalize(src.into());
+        assert_eq!(endings, LineEndings::Unix);
+        assert_eq!(res, src);
     }
 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
index c6a4db9a453..0971dc36f3a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp_utils.rs
@@ -1,5 +1,5 @@
 //! Utilities for LSP-related boilerplate code.
-use std::{ops::Range, sync::Arc};
+use std::{mem, ops::Range, sync::Arc};
 
 use lsp_server::Notification;
 
@@ -133,11 +133,37 @@ impl GlobalState {
 }
 
 pub(crate) fn apply_document_changes(
-    old_text: &mut String,
-    content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
-) {
+    file_contents: impl FnOnce() -> String,
+    mut content_changes: Vec<lsp_types::TextDocumentContentChangeEvent>,
+) -> String {
+    // Skip to the last full document change, as it invalidates all previous changes anyways.
+    let mut start = content_changes
+        .iter()
+        .rev()
+        .position(|change| change.range.is_none())
+        .map(|idx| content_changes.len() - idx - 1)
+        .unwrap_or(0);
+
+    let mut text: String = match content_changes.get_mut(start) {
+        // peek at the first content change as an optimization
+        Some(lsp_types::TextDocumentContentChangeEvent { range: None, text, .. }) => {
+            let text = mem::take(text);
+            start += 1;
+
+            // The only change is a full document update
+            if start == content_changes.len() {
+                return text;
+            }
+            text
+        }
+        Some(_) => file_contents(),
+        // we received no content changes
+        None => return file_contents(),
+    };
+
     let mut line_index = LineIndex {
-        index: Arc::new(ide::LineIndex::new(old_text)),
+        // the index will be overwritten in the bottom loop's first iteration
+        index: Arc::new(ide::LineIndex::new(&text)),
         // We don't care about line endings or offset encoding here.
         endings: LineEndings::Unix,
         encoding: PositionEncoding::Utf16,
@@ -148,38 +174,20 @@ pub(crate) fn apply_document_changes(
     // Some clients (e.g. Code) sort the ranges in reverse. As an optimization, we
     // remember the last valid line in the index and only rebuild it if needed.
     // The VFS will normalize the end of lines to `\n`.
-    enum IndexValid {
-        All,
-        UpToLineExclusive(u32),
-    }
-
-    impl IndexValid {
-        fn covers(&self, line: u32) -> bool {
-            match *self {
-                IndexValid::UpToLineExclusive(to) => to > line,
-                _ => true,
-            }
-        }
-    }
-
-    let mut index_valid = IndexValid::All;
+    let mut index_valid = !0u32;
     for change in content_changes {
-        match change.range {
-            Some(range) => {
-                if !index_valid.covers(range.end.line) {
-                    line_index.index = Arc::new(ide::LineIndex::new(old_text));
-                }
-                index_valid = IndexValid::UpToLineExclusive(range.start.line);
-                if let Ok(range) = from_proto::text_range(&line_index, range) {
-                    old_text.replace_range(Range::<usize>::from(range), &change.text);
-                }
+        // The None case can't happen as we have handled it above already
+        if let Some(range) = change.range {
+            if index_valid <= range.end.line {
+                *Arc::make_mut(&mut line_index.index) = ide::LineIndex::new(&text);
             }
-            None => {
-                *old_text = change.text;
-                index_valid = IndexValid::UpToLineExclusive(0);
+            index_valid = range.start.line;
+            if let Ok(range) = from_proto::text_range(&line_index, range) {
+                text.replace_range(Range::<usize>::from(range), &change.text);
             }
         }
     }
+    text
 }
 
 /// Checks that the edits inside the completion and the additional edits do not overlap.
@@ -242,11 +250,10 @@ mod tests {
             };
         }
 
-        let mut text = String::new();
-        apply_document_changes(&mut text, vec![]);
+        let text = apply_document_changes(|| String::new(), vec![]);
         assert_eq!(text, "");
-        apply_document_changes(
-            &mut text,
+        let text = apply_document_changes(
+            || text,
             vec![TextDocumentContentChangeEvent {
                 range: None,
                 range_length: None,
@@ -254,39 +261,39 @@ mod tests {
             }],
         );
         assert_eq!(text, "the");
-        apply_document_changes(&mut text, c![0, 3; 0, 3 => " quick"]);
+        let text = apply_document_changes(|| text, c![0, 3; 0, 3 => " quick"]);
         assert_eq!(text, "the quick");
-        apply_document_changes(&mut text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
+        let text = apply_document_changes(|| text, c![0, 0; 0, 4 => "", 0, 5; 0, 5 => " foxes"]);
         assert_eq!(text, "quick foxes");
-        apply_document_changes(&mut text, c![0, 11; 0, 11 => "\ndream"]);
+        let text = apply_document_changes(|| text, c![0, 11; 0, 11 => "\ndream"]);
         assert_eq!(text, "quick foxes\ndream");
-        apply_document_changes(&mut text, c![1, 0; 1, 0 => "have "]);
+        let text = apply_document_changes(|| text, c![1, 0; 1, 0 => "have "]);
         assert_eq!(text, "quick foxes\nhave dream");
-        apply_document_changes(
-            &mut text,
+        let text = apply_document_changes(
+            || text,
             c![0, 0; 0, 0 => "the ", 1, 4; 1, 4 => " quiet", 1, 16; 1, 16 => "s\n"],
         );
         assert_eq!(text, "the quick foxes\nhave quiet dreams\n");
-        apply_document_changes(&mut text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
+        let text = apply_document_changes(|| text, c![0, 15; 0, 15 => "\n", 2, 17; 2, 17 => "\n"]);
         assert_eq!(text, "the quick foxes\n\nhave quiet dreams\n\n");
-        apply_document_changes(
-            &mut text,
+        let text = apply_document_changes(
+            || text,
             c![1, 0; 1, 0 => "DREAM", 2, 0; 2, 0 => "they ", 3, 0; 3, 0 => "DON'T THEY?"],
         );
         assert_eq!(text, "the quick foxes\nDREAM\nthey have quiet dreams\nDON'T THEY?\n");
-        apply_document_changes(&mut text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
+        let text = apply_document_changes(|| text, c![0, 10; 1, 5 => "", 2, 0; 2, 12 => ""]);
         assert_eq!(text, "the quick \nthey have quiet dreams\n");
 
-        text = String::from("❤️");
-        apply_document_changes(&mut text, c![0, 0; 0, 0 => "a"]);
+        let text = String::from("❤️");
+        let text = apply_document_changes(|| text, c![0, 0; 0, 0 => "a"]);
         assert_eq!(text, "a❤️");
 
-        text = String::from("a\nb");
-        apply_document_changes(&mut text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
+        let text = String::from("a\nb");
+        let text = apply_document_changes(|| text, c![0, 1; 1, 0 => "\nțc", 0, 1; 1, 1 => "d"]);
         assert_eq!(text, "adcb");
 
-        text = String::from("a\nb");
-        apply_document_changes(&mut text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
+        let text = String::from("a\nb");
+        let text = apply_document_changes(|| text, c![0, 1; 1, 0 => "ț\nc", 0, 2; 0, 2 => "c"]);
         assert_eq!(text, "ațc\ncb");
     }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index 7d10dc5d15b..274588ce0e0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -451,7 +451,7 @@ impl GlobalState {
                     ProjectWorkspaceProgress::Begin => (Progress::Begin, None),
                     ProjectWorkspaceProgress::Report(msg) => (Progress::Report, Some(msg)),
                     ProjectWorkspaceProgress::End(workspaces) => {
-                        self.fetch_workspaces_queue.op_completed(workspaces);
+                        self.fetch_workspaces_queue.op_completed(Some(workspaces));
 
                         let old = Arc::clone(&self.workspaces);
                         self.switch_workspaces("fetched workspace".to_string());
@@ -759,8 +759,10 @@ impl GlobalState {
 
                     let vfs = &mut this.vfs.write().0;
                     let file_id = vfs.file_id(&path).unwrap();
-                    let mut text = String::from_utf8(vfs.file_contents(file_id).to_vec()).unwrap();
-                    apply_document_changes(&mut text, params.content_changes);
+                    let text = apply_document_changes(
+                        || std::str::from_utf8(vfs.file_contents(file_id)).unwrap().into(),
+                        params.content_changes,
+                    );
 
                     vfs.set_file_contents(path, Some(text.into_bytes()));
                 }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs
index f86a0f66ad8..45a1dab9772 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/mem_docs.rs
@@ -7,7 +7,7 @@ use vfs::VfsPath;
 
 /// Holds the set of in-memory documents.
 ///
-/// For these document, there true contents is maintained by the client. It
+/// For these document, their true contents is maintained by the client. It
 /// might be different from what's on disk.
 #[derive(Default, Clone)]
 pub(crate) struct MemDocs {
@@ -19,6 +19,7 @@ impl MemDocs {
     pub(crate) fn contains(&self, path: &VfsPath) -> bool {
         self.mem_docs.contains_key(path)
     }
+
     pub(crate) fn insert(&mut self, path: VfsPath, data: DocumentData) -> Result<(), ()> {
         self.added_or_removed = true;
         match self.mem_docs.insert(path, data) {
@@ -26,6 +27,7 @@ impl MemDocs {
             None => Ok(()),
         }
     }
+
     pub(crate) fn remove(&mut self, path: &VfsPath) -> Result<(), ()> {
         self.added_or_removed = true;
         match self.mem_docs.remove(path) {
@@ -33,17 +35,21 @@ impl MemDocs {
             None => Err(()),
         }
     }
+
     pub(crate) fn get(&self, path: &VfsPath) -> Option<&DocumentData> {
         self.mem_docs.get(path)
     }
+
     pub(crate) fn get_mut(&mut self, path: &VfsPath) -> Option<&mut DocumentData> {
         // NB: don't set `self.added_or_removed` here, as that purposefully only
         // tracks changes to the key set.
         self.mem_docs.get_mut(path)
     }
+
     pub(crate) fn iter(&self) -> impl Iterator<Item = &VfsPath> {
         self.mem_docs.keys()
     }
+
     pub(crate) fn take_changes(&mut self) -> bool {
         mem::replace(&mut self.added_or_removed, false)
     }
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index e1f651786de..fcfe4be0b8c 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -106,6 +106,14 @@ impl GlobalState {
             status.health = lsp_ext::Health::Error;
             status.message = Some(error)
         }
+
+        if self.config.linked_projects().is_empty()
+            && self.config.detached_files().is_empty()
+            && self.config.notifications().cargo_toml_not_found
+        {
+            status.health = lsp_ext::Health::Warning;
+            status.message = Some("Workspace reload required".to_string())
+        }
         status
     }
 
@@ -198,12 +206,9 @@ impl GlobalState {
             self.show_and_log_error("failed to run build scripts".to_string(), Some(error));
         }
 
-        let workspaces = self
-            .fetch_workspaces_queue
-            .last_op_result()
-            .iter()
-            .filter_map(|res| res.as_ref().ok().cloned())
-            .collect::<Vec<_>>();
+        let Some(workspaces) = self.fetch_workspaces_queue.last_op_result() else { return; };
+        let workspaces =
+            workspaces.iter().filter_map(|res| res.as_ref().ok().cloned()).collect::<Vec<_>>();
 
         fn eq_ignore_build_data<'a>(
             left: &'a ProjectWorkspace,
@@ -300,9 +305,6 @@ impl GlobalState {
         let files_config = self.config.files();
         let project_folders = ProjectFolders::new(&self.workspaces, &files_config.exclude);
 
-        let standalone_server_name =
-            format!("rust-analyzer-proc-macro-srv{}", std::env::consts::EXE_SUFFIX);
-
         if self.proc_macro_clients.is_empty() {
             if let Some((path, path_manually_set)) = self.config.proc_macro_srv() {
                 tracing::info!("Spawning proc-macro servers");
@@ -310,40 +312,17 @@ impl GlobalState {
                     .workspaces
                     .iter()
                     .map(|ws| {
-                        let (path, args) = if path_manually_set {
+                        let (path, args): (_, &[_]) = if path_manually_set {
                             tracing::debug!(
                                 "Pro-macro server path explicitly set: {}",
                                 path.display()
                             );
-                            (path.clone(), vec![])
+                            (path.clone(), &[])
                         } else {
-                            let mut sysroot_server = None;
-                            if let ProjectWorkspace::Cargo { sysroot, .. }
-                            | ProjectWorkspace::Json { sysroot, .. } = ws
-                            {
-                                if let Some(sysroot) = sysroot.as_ref() {
-                                    let server_path = sysroot
-                                        .root()
-                                        .join("libexec")
-                                        .join(&standalone_server_name);
-                                    if std::fs::metadata(&server_path).is_ok() {
-                                        tracing::debug!(
-                                            "Sysroot proc-macro server exists at {}",
-                                            server_path.display()
-                                        );
-                                        sysroot_server = Some(server_path);
-                                    } else {
-                                        tracing::debug!(
-                                            "Sysroot proc-macro server does not exist at {}",
-                                            server_path.display()
-                                        );
-                                    }
-                                }
+                            match ws.find_sysroot_proc_macro_srv() {
+                                Some(server_path) => (server_path, &[]),
+                                None => (path.clone(), &["proc-macro"]),
                             }
-                            sysroot_server.map_or_else(
-                                || (path.clone(), vec!["proc-macro".to_owned()]),
-                                |path| (path, vec![]),
-                            )
                         };
 
                         tracing::info!(?args, "Using proc-macro server at {}", path.display(),);
@@ -427,9 +406,14 @@ impl GlobalState {
     fn fetch_workspace_error(&self) -> Result<(), String> {
         let mut buf = String::new();
 
-        for ws in self.fetch_workspaces_queue.last_op_result() {
-            if let Err(err) = ws {
-                stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
+        let Some(last_op_result) = self.fetch_workspaces_queue.last_op_result() else { return Ok(()) };
+        if last_op_result.is_empty() {
+            stdx::format_to!(buf, "rust-analyzer failed to discover workspace");
+        } else {
+            for ws in last_op_result {
+                if let Err(err) = ws {
+                    stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
+                }
             }
         }
 
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
index 6c84a2069cd..81cc1952ba5 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/to_proto.rs
@@ -24,7 +24,7 @@ use crate::{
     line_index::{LineEndings, LineIndex, PositionEncoding},
     lsp_ext,
     lsp_utils::invalid_params_error,
-    semantic_tokens, Result,
+    semantic_tokens,
 };
 
 pub(crate) fn position(line_index: &LineIndex, offset: TextSize) -> lsp_types::Position {
@@ -429,7 +429,7 @@ pub(crate) fn inlay_hint(
     line_index: &LineIndex,
     render_colons: bool,
     mut inlay_hint: InlayHint,
-) -> Result<lsp_types::InlayHint> {
+) -> Cancellable<lsp_types::InlayHint> {
     match inlay_hint.kind {
         InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
         InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
@@ -440,32 +440,35 @@ pub(crate) fn inlay_hint(
     Ok(lsp_types::InlayHint {
         position: match inlay_hint.kind {
             // before annotated thing
-            InlayKind::ParameterHint
-            | InlayKind::ImplicitReborrowHint
-            | InlayKind::BindingModeHint => position(line_index, inlay_hint.range.start()),
+            InlayKind::ParameterHint | InlayKind::AdjustmentHint | InlayKind::BindingModeHint => {
+                position(line_index, inlay_hint.range.start())
+            }
             // after annotated thing
             InlayKind::ClosureReturnTypeHint
             | InlayKind::TypeHint
             | InlayKind::ChainingHint
             | InlayKind::GenericParamListHint
+            | InlayKind::AdjustmentHintClosingParenthesis
             | InlayKind::LifetimeHint
             | InlayKind::ClosingBraceHint => position(line_index, inlay_hint.range.end()),
         },
         padding_left: Some(match inlay_hint.kind {
             InlayKind::TypeHint => !render_colons,
             InlayKind::ChainingHint | InlayKind::ClosingBraceHint => true,
-            InlayKind::BindingModeHint
+            InlayKind::AdjustmentHintClosingParenthesis
+            | InlayKind::BindingModeHint
             | InlayKind::ClosureReturnTypeHint
             | InlayKind::GenericParamListHint
-            | InlayKind::ImplicitReborrowHint
+            | InlayKind::AdjustmentHint
             | InlayKind::LifetimeHint
             | InlayKind::ParameterHint => false,
         }),
         padding_right: Some(match inlay_hint.kind {
-            InlayKind::ChainingHint
+            InlayKind::AdjustmentHintClosingParenthesis
+            | InlayKind::ChainingHint
             | InlayKind::ClosureReturnTypeHint
             | InlayKind::GenericParamListHint
-            | InlayKind::ImplicitReborrowHint
+            | InlayKind::AdjustmentHint
             | InlayKind::TypeHint
             | InlayKind::ClosingBraceHint => false,
             InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
@@ -476,10 +479,11 @@ pub(crate) fn inlay_hint(
             InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
                 Some(lsp_types::InlayHintKind::TYPE)
             }
-            InlayKind::BindingModeHint
+            InlayKind::AdjustmentHintClosingParenthesis
+            | InlayKind::BindingModeHint
             | InlayKind::GenericParamListHint
             | InlayKind::LifetimeHint
-            | InlayKind::ImplicitReborrowHint
+            | InlayKind::AdjustmentHint
             | InlayKind::ClosingBraceHint => None,
         },
         text_edits: None,
@@ -518,7 +522,7 @@ pub(crate) fn inlay_hint(
 fn inlay_hint_label(
     snap: &GlobalStateSnapshot,
     label: InlayHintLabel,
-) -> Result<lsp_types::InlayHintLabel> {
+) -> Cancellable<lsp_types::InlayHintLabel> {
     Ok(match label.as_simple_str() {
         Some(s) => lsp_types::InlayHintLabel::String(s.into()),
         None => lsp_types::InlayHintLabel::LabelParts(
@@ -536,7 +540,7 @@ fn inlay_hint_label(
                         command: None,
                     })
                 })
-                .collect::<Result<Vec<_>>>()?,
+                .collect::<Cancellable<Vec<_>>>()?,
         ),
     })
 }
@@ -794,7 +798,7 @@ pub(crate) fn optional_versioned_text_document_identifier(
 pub(crate) fn location(
     snap: &GlobalStateSnapshot,
     frange: FileRange,
-) -> Result<lsp_types::Location> {
+) -> Cancellable<lsp_types::Location> {
     let url = url(snap, frange.file_id);
     let line_index = snap.file_line_index(frange.file_id)?;
     let range = range(&line_index, frange.range);
@@ -806,7 +810,7 @@ pub(crate) fn location(
 pub(crate) fn location_from_nav(
     snap: &GlobalStateSnapshot,
     nav: NavigationTarget,
-) -> Result<lsp_types::Location> {
+) -> Cancellable<lsp_types::Location> {
     let url = url(snap, nav.file_id);
     let line_index = snap.file_line_index(nav.file_id)?;
     let range = range(&line_index, nav.full_range);
@@ -818,7 +822,7 @@ pub(crate) fn location_link(
     snap: &GlobalStateSnapshot,
     src: Option<FileRange>,
     target: NavigationTarget,
-) -> Result<lsp_types::LocationLink> {
+) -> Cancellable<lsp_types::LocationLink> {
     let origin_selection_range = match src {
         Some(src) => {
             let line_index = snap.file_line_index(src.file_id)?;
@@ -840,7 +844,7 @@ pub(crate) fn location_link(
 fn location_info(
     snap: &GlobalStateSnapshot,
     target: NavigationTarget,
-) -> Result<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> {
+) -> Cancellable<(lsp_types::Url, lsp_types::Range, lsp_types::Range)> {
     let line_index = snap.file_line_index(target.file_id)?;
 
     let target_uri = url(snap, target.file_id);
@@ -854,12 +858,12 @@ pub(crate) fn goto_definition_response(
     snap: &GlobalStateSnapshot,
     src: Option<FileRange>,
     targets: Vec<NavigationTarget>,
-) -> Result<lsp_types::GotoDefinitionResponse> {
+) -> Cancellable<lsp_types::GotoDefinitionResponse> {
     if snap.config.location_link() {
         let links = targets
             .into_iter()
             .map(|nav| location_link(snap, src, nav))
-            .collect::<Result<Vec<_>>>()?;
+            .collect::<Cancellable<Vec<_>>>()?;
         Ok(links.into())
     } else {
         let locations = targets
@@ -867,7 +871,7 @@ pub(crate) fn goto_definition_response(
             .map(|nav| {
                 location(snap, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() })
             })
-            .collect::<Result<Vec<_>>>()?;
+            .collect::<Cancellable<Vec<_>>>()?;
         Ok(locations.into())
     }
 }
@@ -881,7 +885,7 @@ pub(crate) fn snippet_text_document_edit(
     is_snippet: bool,
     file_id: FileId,
     edit: TextEdit,
-) -> Result<lsp_ext::SnippetTextDocumentEdit> {
+) -> Cancellable<lsp_ext::SnippetTextDocumentEdit> {
     let text_document = optional_versioned_text_document_identifier(snap, file_id);
     let line_index = snap.file_line_index(file_id)?;
     let mut edits: Vec<_> =
@@ -958,7 +962,7 @@ pub(crate) fn snippet_text_document_ops(
 pub(crate) fn snippet_workspace_edit(
     snap: &GlobalStateSnapshot,
     source_change: SourceChange,
-) -> Result<lsp_ext::SnippetWorkspaceEdit> {
+) -> Cancellable<lsp_ext::SnippetWorkspaceEdit> {
     let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
 
     for op in source_change.file_system_edits {
@@ -995,7 +999,7 @@ pub(crate) fn snippet_workspace_edit(
 pub(crate) fn workspace_edit(
     snap: &GlobalStateSnapshot,
     source_change: SourceChange,
-) -> Result<lsp_types::WorkspaceEdit> {
+) -> Cancellable<lsp_types::WorkspaceEdit> {
     assert!(!source_change.is_snippet);
     snippet_workspace_edit(snap, source_change).map(|it| it.into())
 }
@@ -1048,7 +1052,7 @@ impl From<lsp_ext::SnippetTextEdit>
 pub(crate) fn call_hierarchy_item(
     snap: &GlobalStateSnapshot,
     target: NavigationTarget,
-) -> Result<lsp_types::CallHierarchyItem> {
+) -> Cancellable<lsp_types::CallHierarchyItem> {
     let name = target.name.to_string();
     let detail = target.description.clone();
     let kind = target.kind.map(symbol_kind).unwrap_or(lsp_types::SymbolKind::FUNCTION);
@@ -1080,7 +1084,7 @@ pub(crate) fn code_action(
     snap: &GlobalStateSnapshot,
     assist: Assist,
     resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
-) -> Result<lsp_ext::CodeAction> {
+) -> Cancellable<lsp_ext::CodeAction> {
     let mut res = lsp_ext::CodeAction {
         title: assist.label.to_string(),
         group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
@@ -1113,13 +1117,13 @@ pub(crate) fn code_action(
 pub(crate) fn runnable(
     snap: &GlobalStateSnapshot,
     runnable: Runnable,
-) -> Result<lsp_ext::Runnable> {
+) -> Cancellable<lsp_ext::Runnable> {
     let config = snap.config.runnables();
     let spec = CargoTargetSpec::for_file(snap, runnable.nav.file_id)?;
     let workspace_root = spec.as_ref().map(|it| it.workspace_root.clone());
     let target = spec.as_ref().map(|s| s.target.clone());
     let (cargo_args, executable_args) =
-        CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg)?;
+        CargoTargetSpec::runnable_args(snap, spec, &runnable.kind, &runnable.cfg);
     let label = runnable.label(target);
     let location = location_link(snap, None, runnable.nav)?;
 
@@ -1142,7 +1146,7 @@ pub(crate) fn code_lens(
     acc: &mut Vec<lsp_types::CodeLens>,
     snap: &GlobalStateSnapshot,
     annotation: Annotation,
-) -> Result<()> {
+) -> Cancellable<()> {
     let client_commands_config = snap.config.client_commands();
     match annotation.kind {
         AnnotationKind::Runnable(run) => {
diff --git a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml b/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml
index e75867e2d81..593dc4e55b2 100644
--- a/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/sourcegen/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/stdx/Cargo.toml b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
index e0657ab0f6d..f7b7d09640f 100644
--- a/src/tools/rust-analyzer/crates/stdx/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/stdx/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
@@ -16,7 +16,7 @@ always-assert = { version = "0.1.2", features = ["log"] }
 # Think twice before adding anything here
 
 [target.'cfg(windows)'.dependencies]
-miow = "0.4.0"
+miow = "0.5.0"
 winapi = { version = "0.3.9", features = ["winerror"] }
 
 [features]
diff --git a/src/tools/rust-analyzer/crates/syntax/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
index 1ef903371cf..00743cca559 100644
--- a/src/tools/rust-analyzer/crates/syntax/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/Cargo.toml
@@ -5,7 +5,7 @@ description = "Comment and whitespace preserving parser for the Rust language"
 license = "MIT OR Apache-2.0"
 repository = "https://github.com/rust-lang/rust-analyzer"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
index ba2f515b0bc..f295c40065d 100644
--- a/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml
@@ -4,7 +4,7 @@ name = "syntax-fuzz"
 version = "0.0.1"
 publish = false
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [package.metadata]
 cargo-fuzz = true
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 5379732ac6c..0a0cb0290d6 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -239,8 +239,11 @@ Static =
 Trait =
   Attr* Visibility?
   'unsafe'? 'auto'?
-  'trait' Name GenericParamList? (':' TypeBoundList?)? WhereClause?
-  AssocItemList
+  'trait' Name GenericParamList?
+  (
+    (':' TypeBoundList?)? WhereClause? AssocItemList
+    | '=' TypeBoundList? WhereClause? ';'
+  )
 
 AssocItemList =
   '{' Attr* AssocItem* '}'
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 6cfb98d92fc..2ea715f47fb 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -407,6 +407,8 @@ impl Trait {
     pub fn auto_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![auto]) }
     pub fn trait_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![trait]) }
     pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) }
+    pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
+    pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
index ba72e64425b..8990f7a7d4e 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/token_ext.rs
@@ -209,17 +209,19 @@ impl ast::String {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf = String::new();
-        let mut text_iter = text.chars();
+        let mut prev_end = 0;
         let mut has_error = false;
         unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c),
-            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
+            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
+                prev_end = char_range.end
+            }
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.push_str(&text[..char_range.start]);
+                buf.push_str(&text[..prev_end]);
                 buf.push(c);
             }
             (Err(_), _) => has_error = true,
@@ -252,17 +254,19 @@ impl ast::ByteString {
         let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
 
         let mut buf: Vec<u8> = Vec::new();
-        let mut text_iter = text.chars();
+        let mut prev_end = 0;
         let mut has_error = false;
         unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
             unescaped_char,
             buf.capacity() == 0,
         ) {
             (Ok(c), false) => buf.push(c as u8),
-            (Ok(c), true) if char_range.len() == 1 && Some(c) == text_iter.next() => (),
+            (Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
+                prev_end = char_range.end
+            }
             (Ok(c), true) => {
                 buf.reserve_exact(text.len());
-                buf.extend_from_slice(text[..char_range.start].as_bytes());
+                buf.extend_from_slice(text[..prev_end].as_bytes());
                 buf.push(c as u8);
             }
             (Err(_), _) => has_error = true,
@@ -445,6 +449,36 @@ mod tests {
         check_string_value(r"\foobar", None);
         check_string_value(r"\nfoobar", "\nfoobar");
         check_string_value(r"C:\\Windows\\System32\\", "C:\\Windows\\System32\\");
+        check_string_value(r"\x61bcde", "abcde");
+        check_string_value(
+            r"a\
+bcde", "abcde",
+        );
+    }
+
+    fn check_byte_string_value<'a, const N: usize>(
+        lit: &str,
+        expected: impl Into<Option<&'a [u8; N]>>,
+    ) {
+        assert_eq!(
+            ast::ByteString { syntax: make::tokens::literal(&format!("b\"{}\"", lit)) }
+                .value()
+                .as_deref(),
+            expected.into().map(|value| &value[..])
+        );
+    }
+
+    #[test]
+    fn test_byte_string_escape() {
+        check_byte_string_value(r"foobar", b"foobar");
+        check_byte_string_value(r"\foobar", None::<&[u8; 0]>);
+        check_byte_string_value(r"\nfoobar", b"\nfoobar");
+        check_byte_string_value(r"C:\\Windows\\System32\\", b"C:\\Windows\\System32\\");
+        check_byte_string_value(r"\x61bcde", b"abcde");
+        check_byte_string_value(
+            r"a\
+bcde", b"abcde",
+        );
     }
 
     #[test]
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index 70b54843dba..712ef5f63b6 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -86,7 +86,7 @@ fn generate_nodes(kinds: KindsSrc<'_>, grammar: &AstSrc) -> String {
                 .traits
                 .iter()
                 .filter(|trait_name| {
-                    // Loops have two expressions so this might collide, therefor manual impl it
+                    // Loops have two expressions so this might collide, therefore manual impl it
                     node.name != "ForExpr" && node.name != "WhileExpr"
                         || trait_name.as_str() != "HasLoopBody"
                 })
diff --git a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
index cceafe04e37..1047373b1c7 100644
--- a/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/test-utils/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
index 7a90d64a98b..8df7e1af611 100644
--- a/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/text-edit/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
index 3e0f31f19c5..a6a3ae742ae 100644
--- a/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/toolchain/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/tt/Cargo.toml b/src/tools/rust-analyzer/crates/tt/Cargo.toml
index 52dfb860804..4f2103f3a97 100644
--- a/src/tools/rust-analyzer/crates/tt/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/tt/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
index df5dc24e2cd..061f3c157a8 100644
--- a/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs-notify/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/crates/vfs/Cargo.toml b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
index d7549a28415..e55bf6f293c 100644
--- a/src/tools/rust-analyzer/crates/vfs/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/vfs/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.0.0"
 description = "TBD"
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [lib]
 doctest = false
diff --git a/src/tools/rust-analyzer/docs/dev/architecture.md b/src/tools/rust-analyzer/docs/dev/architecture.md
index e3a4fdfda90..a07cf036e06 100644
--- a/src/tools/rust-analyzer/docs/dev/architecture.md
+++ b/src/tools/rust-analyzer/docs/dev/architecture.md
@@ -481,7 +481,7 @@ It is not cheap enough to enable in prod, and this is a bug which should be fixe
 rust-analyzer strives to be as configurable as possible while offering reasonable defaults where no configuration exists yet.
 The rule of thumb is to enable most features by default unless they are buggy or degrade performance too much.
 There will always be features that some people find more annoying than helpful, so giving the users the ability to tweak or disable these is a big part of offering a good user experience.
-Enabling them by default is a matter of discoverability, as many users end up don't know about some features even though they are presented in the manual.
+Enabling them by default is a matter of discoverability, as many users don't know about some features even though they are presented in the manual.
 Mind the code--architecture gap: at the moment, we are using fewer feature flags than we really should.
 
 ### Serialization
@@ -492,8 +492,8 @@ If a type is serializable, then it is a part of some IPC boundary.
 You often don't control the other side of this boundary, so changing serializable types is hard.
 
 For this reason, the types in `ide`, `base_db` and below are not serializable by design.
-If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide custom, client-specific serialization format.
+If such types need to cross an IPC boundary, then the client of rust-analyzer needs to provide a custom, client-specific serialization format.
 This isolates backwards compatibility and migration concerns to a specific client.
 
-For example, `rust-project.json` is it's own format -- it doesn't include `CrateGraph` as is.
+For example, `rust-project.json` is its own format -- it doesn't include `CrateGraph` as is.
 Instead, it creates a `CrateGraph` by calling appropriate constructing functions.
diff --git a/src/tools/rust-analyzer/docs/user/generated_config.adoc b/src/tools/rust-analyzer/docs/user/generated_config.adoc
index 36794efe427..57f950034cb 100644
--- a/src/tools/rust-analyzer/docs/user/generated_config.adoc
+++ b/src/tools/rust-analyzer/docs/user/generated_config.adoc
@@ -173,7 +173,7 @@ Whether to pass `--no-default-features` to Cargo. Defaults to
 --
 Override the command rust-analyzer uses instead of `cargo check` for
 diagnostics on save. The command is required to output json and
-should therefor include `--message-format=json` or a similar option.
+should therefore include `--message-format=json` or a similar option.
 
 If you're changing this because you're using some tool wrapping
 Cargo, you might also want to change
@@ -190,11 +190,15 @@ cargo check --workspace --message-format=json --all-targets
 ```
 .
 --
-[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `null`)::
+[[rust-analyzer.checkOnSave.target]]rust-analyzer.checkOnSave.target (default: `[]`)::
 +
 --
-Check for a specific target. Defaults to
-`#rust-analyzer.cargo.target#`.
+Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.
+
+Can be a single target, e.g. `"x86_64-unknown-linux-gnu"` or a list of targets, e.g.
+`["aarch64-apple-darwin", "x86_64-apple-darwin"]`.
+
+Aliased as `"checkOnSave.targets"`.
 --
 [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 +
@@ -450,6 +454,11 @@ to always show them).
 --
 Whether to show inlay type hints for return types of closures.
 --
+[[rust-analyzer.inlayHints.expressionAdjustmentHints.enable]]rust-analyzer.inlayHints.expressionAdjustmentHints.enable (default: `"never"`)::
++
+--
+Whether to show inlay hints for type adjustments.
+--
 [[rust-analyzer.inlayHints.lifetimeElisionHints.enable]]rust-analyzer.inlayHints.lifetimeElisionHints.enable (default: `"never"`)::
 +
 --
@@ -474,7 +483,8 @@ site.
 [[rust-analyzer.inlayHints.reborrowHints.enable]]rust-analyzer.inlayHints.reborrowHints.enable (default: `"never"`)::
 +
 --
-Whether to show inlay type hints for compiler inserted reborrows.
+Whether to show inlay hints for compiler inserted reborrows.
+This setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.
 --
 [[rust-analyzer.inlayHints.renderColons]]rust-analyzer.inlayHints.renderColons (default: `true`)::
 +
diff --git a/src/tools/rust-analyzer/docs/user/manual.adoc b/src/tools/rust-analyzer/docs/user/manual.adoc
index 49500e390a5..1a4c70575b0 100644
--- a/src/tools/rust-analyzer/docs/user/manual.adoc
+++ b/src/tools/rust-analyzer/docs/user/manual.adoc
@@ -367,7 +367,7 @@ if executable('rust-analyzer')
 endif
 ----
 
-There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<_configuration,Configuration>> section.
+There is no dedicated UI for the server configuration, so you would need to send any options as a value of the `initialization_options` field, as described in the <<configuration,Configuration>> section.
 Here is an example of how to enable the proc-macro support:
 
 [source,vim]
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index 1a97a9c0893..c4d4e428ea0 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -396,6 +396,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.diagnostics.previewRustcOutput": {
+                    "markdownDescription": "Whether to show the main part of the rendered rustc output of a diagnostic message.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "$generated-start": {},
                 "rust-analyzer.assist.emitMustUse": {
                     "markdownDescription": "Whether to insert #[must_use] when generating `as_` methods\nfor enum variants.",
@@ -623,7 +628,7 @@
                     ]
                 },
                 "rust-analyzer.checkOnSave.overrideCommand": {
-                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefor include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
+                    "markdownDescription": "Override the command rust-analyzer uses instead of `cargo check` for\ndiagnostics on save. The command is required to output json and\nshould therefore include `--message-format=json` or a similar option.\n\nIf you're changing this because you're using some tool wrapping\nCargo, you might also want to change\n`#rust-analyzer.cargo.buildScripts.overrideCommand#`.\n\nIf there are multiple linked projects, this command is invoked for\neach of them, with the working directory being the project root\n(i.e., the folder containing the `Cargo.toml`).\n\nAn example command would be:\n\n```bash\ncargo check --workspace --message-format=json --all-targets\n```\n.",
                     "default": null,
                     "type": [
                         "null",
@@ -634,11 +639,18 @@
                     }
                 },
                 "rust-analyzer.checkOnSave.target": {
-                    "markdownDescription": "Check for a specific target. Defaults to\n`#rust-analyzer.cargo.target#`.",
-                    "default": null,
-                    "type": [
-                        "null",
-                        "string"
+                    "markdownDescription": "Check for specific targets. Defaults to `#rust-analyzer.cargo.target#` if empty.\n\nCan be a single target, e.g. `\"x86_64-unknown-linux-gnu\"` or a list of targets, e.g.\n`[\"aarch64-apple-darwin\", \"x86_64-apple-darwin\"]`.\n\nAliased as `\"checkOnSave.targets\"`.",
+                    "default": [],
+                    "anyOf": [
+                        {
+                            "type": "string"
+                        },
+                        {
+                            "type": "array",
+                            "items": {
+                                "type": "string"
+                            }
+                        }
                     ]
                 },
                 "rust-analyzer.completion.autoimport.enable": {
@@ -935,6 +947,21 @@
                         "Only show type hints for return types of closures with blocks."
                     ]
                 },
+                "rust-analyzer.inlayHints.expressionAdjustmentHints.enable": {
+                    "markdownDescription": "Whether to show inlay hints for type adjustments.",
+                    "default": "never",
+                    "type": "string",
+                    "enum": [
+                        "always",
+                        "never",
+                        "reborrow"
+                    ],
+                    "enumDescriptions": [
+                        "Always show all adjustment hints.",
+                        "Never show adjustment hints.",
+                        "Only show auto borrow and dereference adjustment hints."
+                    ]
+                },
                 "rust-analyzer.inlayHints.lifetimeElisionHints.enable": {
                     "markdownDescription": "Whether to show inlay type hints for elided lifetimes in function signatures.",
                     "default": "never",
@@ -970,7 +997,7 @@
                     "type": "boolean"
                 },
                 "rust-analyzer.inlayHints.reborrowHints.enable": {
-                    "markdownDescription": "Whether to show inlay type hints for compiler inserted reborrows.",
+                    "markdownDescription": "Whether to show inlay hints for compiler inserted reborrows.\nThis setting is deprecated in favor of #rust-analyzer.inlayHints.expressionAdjustmentHints.enable#.",
                     "default": "never",
                     "type": "string",
                     "enum": [
@@ -1276,6 +1303,11 @@
                 "$generated-end": {}
             }
         },
+        "configurationDefaults": {
+            "explorer.fileNesting.patterns": {
+                "Cargo.toml": "Cargo.lock"
+            }
+        },
         "problemPatterns": [
             {
                 "name": "rustc",
diff --git a/src/tools/rust-analyzer/editors/code/src/client.ts b/src/tools/rust-analyzer/editors/code/src/client.ts
index fb667619c86..23e039722ee 100644
--- a/src/tools/rust-analyzer/editors/code/src/client.ts
+++ b/src/tools/rust-analyzer/editors/code/src/client.ts
@@ -4,7 +4,7 @@ import * as ra from "../src/lsp_ext";
 import * as Is from "vscode-languageclient/lib/common/utils/is";
 import { assert } from "./util";
 import { WorkspaceEdit } from "vscode";
-import { substituteVSCodeVariables } from "./config";
+import { Config, substituteVSCodeVariables } from "./config";
 import { randomUUID } from "crypto";
 
 export interface Env {
@@ -66,7 +66,8 @@ export async function createClient(
     traceOutputChannel: vscode.OutputChannel,
     outputChannel: vscode.OutputChannel,
     initializationOptions: vscode.WorkspaceConfiguration,
-    serverOptions: lc.ServerOptions
+    serverOptions: lc.ServerOptions,
+    config: Config
 ): Promise<lc.LanguageClient> {
     const clientOptions: lc.LanguageClientOptions = {
         documentSelector: [{ scheme: "file", language: "rust" }],
@@ -99,6 +100,43 @@ export async function createClient(
                     }
                 },
             },
+            async handleDiagnostics(
+                uri: vscode.Uri,
+                diagnostics: vscode.Diagnostic[],
+                next: lc.HandleDiagnosticsSignature
+            ) {
+                const preview = config.previewRustcOutput;
+                diagnostics.forEach((diag, idx) => {
+                    // Abuse the fact that VSCode leaks the LSP diagnostics data field through the
+                    // Diagnostic class, if they ever break this we are out of luck and have to go
+                    // back to the worst diagnostics experience ever:)
+
+                    // We encode the rendered output of a rustc diagnostic in the rendered field of
+                    // the data payload of the lsp diagnostic. If that field exists, overwrite the
+                    // diagnostic code such that clicking it opens the diagnostic in a readonly
+                    // text editor for easy inspection
+                    const rendered = (diag as unknown as { data?: { rendered?: string } }).data
+                        ?.rendered;
+                    if (rendered) {
+                        if (preview) {
+                            const index = rendered.match(/^(note|help):/m)?.index || 0;
+                            diag.message = rendered
+                                .substring(0, index)
+                                .replace(/^ -->[^\n]+\n/m, "");
+                        }
+                        diag.code = {
+                            target: vscode.Uri.from({
+                                scheme: "rust-analyzer-diagnostics-view",
+                                path: "/diagnostic message",
+                                fragment: uri.toString(),
+                                query: idx.toString(),
+                            }),
+                            value: "Click for full compiler diagnostic",
+                        };
+                    }
+                });
+                return next(uri, diagnostics);
+            },
             async provideHover(
                 document: vscode.TextDocument,
                 position: vscode.Position,
diff --git a/src/tools/rust-analyzer/editors/code/src/config.ts b/src/tools/rust-analyzer/editors/code/src/config.ts
index 632a7d86faa..d8dbd1df16d 100644
--- a/src/tools/rust-analyzer/editors/code/src/config.ts
+++ b/src/tools/rust-analyzer/editors/code/src/config.ts
@@ -238,6 +238,9 @@ export class Config {
             gotoTypeDef: this.get<boolean>("hover.actions.gotoTypeDef.enable"),
         };
     }
+    get previewRustcOutput() {
+        return this.get<boolean>("diagnostics.previewRustcOutput");
+    }
 }
 
 const VarRegex = new RegExp(/\$\{(.+?)\}/g);
diff --git a/src/tools/rust-analyzer/editors/code/src/ctx.ts b/src/tools/rust-analyzer/editors/code/src/ctx.ts
index 3e366525ee2..d6cee5c8fc6 100644
--- a/src/tools/rust-analyzer/editors/code/src/ctx.ts
+++ b/src/tools/rust-analyzer/editors/code/src/ctx.ts
@@ -179,7 +179,8 @@ export class Ctx {
                 this.traceOutputChannel,
                 this.outputChannel,
                 initializationOptions,
-                serverOptions
+                serverOptions,
+                this.config
             );
             this.pushClientCleanup(
                 this._client.onNotification(ra.serverStatus, (params) =>
diff --git a/src/tools/rust-analyzer/editors/code/src/main.ts b/src/tools/rust-analyzer/editors/code/src/main.ts
index e76b657c1bf..25f1e83d109 100644
--- a/src/tools/rust-analyzer/editors/code/src/main.ts
+++ b/src/tools/rust-analyzer/editors/code/src/main.ts
@@ -48,6 +48,30 @@ async function activateServer(ctx: Ctx): Promise<RustAnalyzerExtensionApi> {
         ctx.pushExtCleanup(activateTaskProvider(ctx.config));
     }
 
+    ctx.pushExtCleanup(
+        vscode.workspace.registerTextDocumentContentProvider(
+            "rust-analyzer-diagnostics-view",
+            new (class implements vscode.TextDocumentContentProvider {
+                async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
+                    const diags = ctx.client?.diagnostics?.get(
+                        vscode.Uri.parse(uri.fragment, true)
+                    );
+                    if (!diags) {
+                        return "Unable to find original rustc diagnostic";
+                    }
+
+                    const diag = diags[parseInt(uri.query)];
+                    if (!diag) {
+                        return "Unable to find original rustc diagnostic";
+                    }
+                    const rendered = (diag as unknown as { data?: { rendered?: string } }).data
+                        ?.rendered;
+                    return rendered ?? "Unable to find original rustc diagnostic";
+                }
+            })()
+        )
+    );
+
     vscode.workspace.onDidChangeWorkspaceFolders(
         async (_) => ctx.onWorkspaceFolderChanges(),
         null,
diff --git a/src/tools/rust-analyzer/xtask/Cargo.toml b/src/tools/rust-analyzer/xtask/Cargo.toml
index 0be0bf920de..95e27beab5d 100644
--- a/src/tools/rust-analyzer/xtask/Cargo.toml
+++ b/src/tools/rust-analyzer/xtask/Cargo.toml
@@ -4,7 +4,7 @@ version = "0.1.0"
 publish = false
 license = "MIT OR Apache-2.0"
 edition = "2021"
-rust-version = "1.57"
+rust-version = "1.65"
 
 [dependencies]
 anyhow = "1.0.62"
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index d5611082f01..414e767690b 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -660,7 +660,7 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<
         ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
             Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
         }
-        ast::ExprKind::Loop(ref block, label) => {
+        ast::ExprKind::Loop(ref block, label, _) => {
             Some(ControlFlow::new_loop(block, label, expr.span))
         }
         ast::ExprKind::While(ref cond, ref block, label) => {