about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-12 10:46:19 +0000
committerbors <bors@rust-lang.org>2023-01-12 10:46:19 +0000
commit606c3907251397a42e23d3e60de31be9d32525d5 (patch)
treed04af6e38cfba4aac7f02930873467da917f6c31
parent2b8590ef3bd1221830ec8a4131ea9d02b1636746 (diff)
parent9ec36f56684cbd0fa90ab2da3c5084811f7a3989 (diff)
downloadrust-606c3907251397a42e23d3e60de31be9d32525d5.tar.gz
rust-606c3907251397a42e23d3e60de31be9d32525d5.zip
Auto merge of #106760 - compiler-errors:rollup-0bogyco, r=compiler-errors
Rollup of 8 pull requests

Successful merges:

 - #103236 (doc: rewrite doc for signed int::{carrying_add,borrowing_sub})
 - #103800 (Stabilize `::{core,std}::pin::pin!`)
 - #106097 (Migrate mir_build diagnostics 2 of 3)
 - #106170 (Move autoderef to `rustc_hir_analysis`)
 - #106323 (Stabilize f16c_target_feature)
 - #106360 (Tweak E0277 `&`-removal suggestions)
 - #106524 (Label `struct/enum constructor` instead of `fn item`, mention that it should be called on type mismatch)
 - #106739 (Remove `<dyn AstConv<'tcx>>::fun(c, ...)` calls in favour of `c.astconv().fun(...)`)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs3
-rw-r--r--compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl4
-rw-r--r--compiler/rustc_error_messages/locales/en-US/mir_build.ftl61
-rw-r--r--compiler/rustc_error_messages/locales/en-US/trait_selection.ftl4
-rw-r--r--compiler/rustc_feature/src/accepted.rs2
-rw-r--r--compiler/rustc_feature/src/active.rs1
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs1134
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs24
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs (renamed from compiler/rustc_trait_selection/src/autoderef.rs)4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs37
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs26
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs12
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs6
-rw-r--r--compiler/rustc_hir_typeck/src/autoderef.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs19
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs13
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs28
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs7
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs4
-rw-r--r--compiler/rustc_middle/src/thir.rs7
-rw-r--r--compiler/rustc_middle/src/ty/error.rs14
-rw-r--r--compiler/rustc_mir_build/src/errors.rs226
-rw-r--r--compiler/rustc_mir_build/src/lib.rs1
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs191
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs188
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs30
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs42
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs13
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs173
-rw-r--r--library/core/src/lib.rs2
-rw-r--r--library/core/src/num/int_macros.rs111
-rw-r--r--library/core/src/pin.rs10
-rw-r--r--library/core/tests/lib.rs1
-rw-r--r--src/tools/miri/tests/pass/issues/issue-miri-2068.rs2
-rw-r--r--src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs2
-rw-r--r--tests/ui/associated-types/substs-ppaux.normal.stderr8
-rw-r--r--tests/ui/associated-types/substs-ppaux.verbose.stderr8
-rw-r--r--tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr6
-rw-r--r--tests/ui/consts/const-match-check.eval1.stderr2
-rw-r--r--tests/ui/consts/const-match-check.eval2.stderr2
-rw-r--r--tests/ui/consts/const-match-check.matchck.stderr8
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.rs18
-rw-r--r--tests/ui/consts/const-pattern-irrefutable.stderr19
-rw-r--r--tests/ui/consts/const_let_refutable.stderr2
-rw-r--r--tests/ui/empty/empty-never-array.rs3
-rw-r--r--tests/ui/empty/empty-never-array.stderr14
-rw-r--r--tests/ui/error-codes/E0005.stderr13
-rw-r--r--tests/ui/error-codes/E0297.stderr7
-rw-r--r--tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr13
-rw-r--r--tests/ui/for/for-loop-refutable-pattern-error-message.stderr2
-rw-r--r--tests/ui/impl-trait/in-trait/issue-102140.stderr12
-rw-r--r--tests/ui/issues/issue-15381.rs3
-rw-r--r--tests/ui/issues/issue-15381.stderr2
-rw-r--r--tests/ui/issues/issue-35241.stderr8
-rw-r--r--tests/ui/kindck/kindck-copy.stderr12
-rw-r--r--tests/ui/never_type/exhaustive_patterns.stderr8
-rw-r--r--tests/ui/not-panic/not-panic-safe-4.stderr10
-rw-r--r--tests/ui/not-panic/not-panic-safe.rs4
-rw-r--r--tests/ui/not-panic/not-panic-safe.stderr18
-rw-r--r--tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr2
-rw-r--r--tests/ui/pattern/usefulness/issue-31561.rs3
-rw-r--r--tests/ui/pattern/usefulness/issue-31561.stderr16
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs38
-rw-r--r--tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr58
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.rs6
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-errors.stderr6
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs3
-rw-r--r--tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr2
-rw-r--r--tests/ui/pin-macro/cant_access_internals.rs1
-rw-r--r--tests/ui/pin-macro/cant_access_internals.stderr2
-rw-r--r--tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs1
-rw-r--r--tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr4
-rw-r--r--tests/ui/recursion/recursive-types-are-not-uninhabited.stderr13
-rw-r--r--tests/ui/resolve/privacy-enum-ctor.stderr24
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs5
-rw-r--r--tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr5
-rw-r--r--tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr44
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-1.stderr10
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-2.stderr10
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-3.stderr20
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-4.fixed5
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-4.rs5
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-4.stderr17
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-5.fixed8
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-5.rs8
-rw-r--r--tests/ui/suggestions/suggest-remove-refs-5.stderr37
-rw-r--r--tests/ui/typeck/issue-57404.stderr11
-rw-r--r--tests/ui/typeck/issue-87181/empty-tuple-method.rs2
-rw-r--r--tests/ui/typeck/issue-87181/empty-tuple-method.stderr2
-rw-r--r--tests/ui/typeck/issue-87181/enum-variant.rs2
-rw-r--r--tests/ui/typeck/issue-87181/enum-variant.stderr2
-rw-r--r--tests/ui/typeck/issue-87181/tuple-method.rs2
-rw-r--r--tests/ui/typeck/issue-87181/tuple-method.stderr2
-rw-r--r--tests/ui/typeck/issue-96738.stderr2
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.rs4
-rw-r--r--tests/ui/uninhabited/uninhabited-irrefutable.stderr14
-rw-r--r--tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr13
108 files changed, 1676 insertions, 1385 deletions
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index da69fc8ecf7..739963fffd1 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -187,7 +187,7 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
     ("bmi2", None),
     ("cmpxchg16b", Some(sym::cmpxchg16b_target_feature)),
     ("ermsb", Some(sym::ermsb_target_feature)),
-    ("f16c", Some(sym::f16c_target_feature)),
+    ("f16c", None),
     ("fma", None),
     ("fxsr", None),
     ("gfni", Some(sym::avx512_target_feature)),
@@ -396,7 +396,6 @@ pub fn from_target_feature(
                 Some(sym::cmpxchg16b_target_feature) => rust_features.cmpxchg16b_target_feature,
                 Some(sym::movbe_target_feature) => rust_features.movbe_target_feature,
                 Some(sym::rtm_target_feature) => rust_features.rtm_target_feature,
-                Some(sym::f16c_target_feature) => rust_features.f16c_target_feature,
                 Some(sym::ermsb_target_feature) => rust_features.ermsb_target_feature,
                 Some(sym::bpf_target_feature) => rust_features.bpf_target_feature,
                 Some(sym::aarch64_ver_target_feature) => rust_features.aarch64_ver_target_feature,
diff --git a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
index 26cdf8a58f3..41f458f6c17 100644
--- a/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/hir_analysis.ftl
@@ -120,3 +120,7 @@ hir_analysis_self_in_impl_self =
 
 hir_analysis_linkage_type =
     invalid type for variable with `#[linkage]` attribute
+
+hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
+    .label = deref recursion limit reached
+    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
diff --git a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
index aacaafeede6..a082c0b61fa 100644
--- a/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/mir_build.ftl
@@ -303,3 +303,64 @@ mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once a
     .mutable_borrow = another mutable borrow, by `{$name_mut}`, occurs here
     .immutable_borrow = also borrowed as immutable, by `{$name_immut}`, here
     .moved = also moved into `{$name_moved}` here
+
+mir_build_union_pattern = cannot use unions in constant patterns
+
+mir_build_type_not_structural =
+     to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+
+mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+
+mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
+
+mir_build_float_pattern = floating-point types cannot be used in patterns
+
+mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+
+mir_build_indirect_structural_match =
+    to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+
+mir_build_nontrivial_structural_match =
+    to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+
+mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
+    .range = ... with this range
+    .note = you likely meant to write mutually exclusive ranges
+
+mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
+    .help = ensure that all variants are matched explicitly by adding the suggested match arms
+    .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
+
+mir_build_uncovered = {$count ->
+        [1] pattern `{$witness_1}`
+        [2] patterns `{$witness_1}` and `{$witness_2}`
+        [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
+        *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
+    } not covered
+
+mir_build_pattern_not_covered = refutable pattern in {$origin}
+    .pattern_ty = the matched value is of type `{$pattern_ty}`
+
+mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+
+mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+
+mir_build_res_defined_here = {$res} defined here
+
+mir_build_adt_defined_here = `{$ty}` defined here
+
+mir_build_variant_defined_here = not covered
+
+mir_build_interpreted_as_const = introduce a variable instead
+
+mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as {$article} {$res} pattern, not a new variable
+
+mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
+        [one] variant that isn't
+        *[other] variants that aren't
+    } matched
+
+mir_build_suggest_let_else = you might want to use `let else` to handle the {$count ->
+        [one] variant that isn't
+        *[other] variants that aren't
+    } matched
diff --git a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl
index 004e0ab1896..14eb4a5502d 100644
--- a/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl
+++ b/compiler/rustc_error_messages/locales/en-US/trait_selection.ftl
@@ -2,10 +2,6 @@ trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entri
 
 trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
 
-trait_selection_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
-    .label = deref recursion limit reached
-    .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
-
 trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
     .label = empty on-clause here
 
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index e2f30fb89b9..fcbc5bacfcc 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -161,6 +161,8 @@ declare_features! (
     (accepted, extern_crate_self, "1.34.0", Some(56409), None),
     /// Allows access to crate names passed via `--extern` through prelude.
     (accepted, extern_prelude, "1.30.0", Some(44660), None),
+    /// Allows using F16C intrinsics from `core::arch::{x86, x86_64}`.
+    (accepted, f16c_target_feature, "CURRENT_RUSTC_VERSION", Some(44839), None),
     /// Allows field shorthands (`x` meaning `x: x`) in struct literal expressions.
     (accepted, field_init_shorthand, "1.17.0", Some(37340), None),
     /// Allows `#[must_use]` on functions, and introduces must-use operators (RFC 1940).
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 691c0955cad..f0bc35d06bf 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -254,7 +254,6 @@ declare_features! (
     (active, bpf_target_feature, "1.54.0", Some(44839), None),
     (active, cmpxchg16b_target_feature, "1.32.0", Some(44839), None),
     (active, ermsb_target_feature, "1.49.0", Some(44839), None),
-    (active, f16c_target_feature, "1.36.0", Some(44839), None),
     (active, hexagon_target_feature, "1.27.0", Some(44839), None),
     (active, mips_target_feature, "1.27.0", Some(44839), None),
     (active, movbe_target_feature, "1.34.0", Some(44839), None),
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index f64d65cc6ad..ce3682a8f2d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -1,6 +1,6 @@
 use super::IsMethodCall;
 use crate::astconv::{
-    AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
+    CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, GenericArgPosition,
 };
 use crate::errors::AssocTypeBindingNotAllowed;
@@ -18,642 +18,624 @@ use rustc_session::lint::builtin::LATE_BOUND_LIFETIME_ARGUMENTS;
 use rustc_span::{symbol::kw, Span};
 use smallvec::SmallVec;
 
-impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
-    /// Report an error that a generic argument did not match the generic parameter that was
-    /// expected.
-    fn generic_arg_mismatch_err(
-        tcx: TyCtxt<'_>,
-        arg: &GenericArg<'_>,
-        param: &GenericParamDef,
-        possible_ordering_error: bool,
-        help: Option<&str>,
-    ) {
-        let sess = tcx.sess;
-        let mut err = struct_span_err!(
-            sess,
-            arg.span(),
-            E0747,
-            "{} provided when a {} was expected",
-            arg.descr(),
-            param.kind.descr(),
-        );
-
-        if let GenericParamDefKind::Const { .. } = param.kind {
-            if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
-                err.help("const arguments cannot yet be inferred with `_`");
-                if sess.is_nightly_build() {
-                    err.help(
-                        "add `#![feature(generic_arg_infer)]` to the crate attributes to enable",
-                    );
-                }
+/// Report an error that a generic argument did not match the generic parameter that was
+/// expected.
+fn generic_arg_mismatch_err(
+    tcx: TyCtxt<'_>,
+    arg: &GenericArg<'_>,
+    param: &GenericParamDef,
+    possible_ordering_error: bool,
+    help: Option<&str>,
+) {
+    let sess = tcx.sess;
+    let mut err = struct_span_err!(
+        sess,
+        arg.span(),
+        E0747,
+        "{} provided when a {} was expected",
+        arg.descr(),
+        param.kind.descr(),
+    );
+
+    if let GenericParamDefKind::Const { .. } = param.kind {
+        if matches!(arg, GenericArg::Type(hir::Ty { kind: hir::TyKind::Infer, .. })) {
+            err.help("const arguments cannot yet be inferred with `_`");
+            if sess.is_nightly_build() {
+                err.help("add `#![feature(generic_arg_infer)]` to the crate attributes to enable");
             }
         }
+    }
 
-        let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| {
-            let suggestions = vec![
-                (arg.span().shrink_to_lo(), String::from("{ ")),
-                (arg.span().shrink_to_hi(), String::from(" }")),
-            ];
-            err.multipart_suggestion(
-                "if this generic argument was intended as a const parameter, \
+    let add_braces_suggestion = |arg: &GenericArg<'_>, err: &mut Diagnostic| {
+        let suggestions = vec![
+            (arg.span().shrink_to_lo(), String::from("{ ")),
+            (arg.span().shrink_to_hi(), String::from(" }")),
+        ];
+        err.multipart_suggestion(
+            "if this generic argument was intended as a const parameter, \
                  surround it with braces",
-                suggestions,
-                Applicability::MaybeIncorrect,
-            );
-        };
-
-        // Specific suggestion set for diagnostics
-        match (arg, &param.kind) {
-            (
-                GenericArg::Type(hir::Ty {
-                    kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
-                    ..
-                }),
-                GenericParamDefKind::Const { .. },
-            ) => match path.res {
-                Res::Err => {
-                    add_braces_suggestion(arg, &mut err);
-                    err.set_primary_message(
-                        "unresolved item provided when a constant was expected",
-                    )
+            suggestions,
+            Applicability::MaybeIncorrect,
+        );
+    };
+
+    // Specific suggestion set for diagnostics
+    match (arg, &param.kind) {
+        (
+            GenericArg::Type(hir::Ty {
+                kind: hir::TyKind::Path(rustc_hir::QPath::Resolved(_, path)),
+                ..
+            }),
+            GenericParamDefKind::Const { .. },
+        ) => match path.res {
+            Res::Err => {
+                add_braces_suggestion(arg, &mut err);
+                err.set_primary_message("unresolved item provided when a constant was expected")
                     .emit();
-                    return;
-                }
-                Res::Def(DefKind::TyParam, src_def_id) => {
-                    if let Some(param_local_id) = param.def_id.as_local() {
-                        let param_name = tcx.hir().ty_param_name(param_local_id);
-                        let param_type = tcx.type_of(param.def_id);
-                        if param_type.is_suggestable(tcx, false) {
-                            err.span_suggestion(
-                                tcx.def_span(src_def_id),
-                                "consider changing this type parameter to be a `const` generic",
-                                format!("const {}: {}", param_name, param_type),
-                                Applicability::MaybeIncorrect,
-                            );
-                        };
-                    }
-                }
-                _ => add_braces_suggestion(arg, &mut err),
-            },
-            (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
-                GenericParamDefKind::Const { .. },
-            ) => add_braces_suggestion(arg, &mut err),
-            (
-                GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
-                GenericParamDefKind::Const { .. },
-            ) if tcx.type_of(param.def_id) == tcx.types.usize => {
-                let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
-                if let Ok(snippet) = snippet {
-                    err.span_suggestion(
-                        arg.span(),
-                        "array type provided where a `usize` was expected, try",
-                        format!("{{ {} }}", snippet),
-                        Applicability::MaybeIncorrect,
-                    );
+                return;
+            }
+            Res::Def(DefKind::TyParam, src_def_id) => {
+                if let Some(param_local_id) = param.def_id.as_local() {
+                    let param_name = tcx.hir().ty_param_name(param_local_id);
+                    let param_type = tcx.type_of(param.def_id);
+                    if param_type.is_suggestable(tcx, false) {
+                        err.span_suggestion(
+                            tcx.def_span(src_def_id),
+                            "consider changing this type parameter to be a `const` generic",
+                            format!("const {}: {}", param_name, param_type),
+                            Applicability::MaybeIncorrect,
+                        );
+                    };
                 }
             }
-            (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
-                let body = tcx.hir().body(cnst.value.body);
-                if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) =
-                    body.value.kind
-                {
-                    if let Res::Def(DefKind::Fn { .. }, id) = path.res {
-                        err.help(&format!(
-                            "`{}` is a function item, not a type",
-                            tcx.item_name(id)
-                        ));
-                        err.help("function item types cannot be named directly");
-                    }
+            _ => add_braces_suggestion(arg, &mut err),
+        },
+        (
+            GenericArg::Type(hir::Ty { kind: hir::TyKind::Path(_), .. }),
+            GenericParamDefKind::Const { .. },
+        ) => add_braces_suggestion(arg, &mut err),
+        (
+            GenericArg::Type(hir::Ty { kind: hir::TyKind::Array(_, len), .. }),
+            GenericParamDefKind::Const { .. },
+        ) if tcx.type_of(param.def_id) == tcx.types.usize => {
+            let snippet = sess.source_map().span_to_snippet(tcx.hir().span(len.hir_id()));
+            if let Ok(snippet) = snippet {
+                err.span_suggestion(
+                    arg.span(),
+                    "array type provided where a `usize` was expected, try",
+                    format!("{{ {} }}", snippet),
+                    Applicability::MaybeIncorrect,
+                );
+            }
+        }
+        (GenericArg::Const(cnst), GenericParamDefKind::Type { .. }) => {
+            let body = tcx.hir().body(cnst.value.body);
+            if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind
+            {
+                if let Res::Def(DefKind::Fn { .. }, id) = path.res {
+                    err.help(&format!("`{}` is a function item, not a type", tcx.item_name(id)));
+                    err.help("function item types cannot be named directly");
                 }
             }
-            _ => {}
         }
+        _ => {}
+    }
 
-        let kind_ord = param.kind.to_ord();
-        let arg_ord = arg.to_ord();
+    let kind_ord = param.kind.to_ord();
+    let arg_ord = arg.to_ord();
 
-        // This note is only true when generic parameters are strictly ordered by their kind.
-        if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
-            let (first, last) = if kind_ord < arg_ord {
-                (param.kind.descr(), arg.descr())
-            } else {
-                (arg.descr(), param.kind.descr())
-            };
-            err.note(&format!("{} arguments must be provided before {} arguments", first, last));
-            if let Some(help) = help {
-                err.help(help);
-            }
+    // This note is only true when generic parameters are strictly ordered by their kind.
+    if possible_ordering_error && kind_ord.cmp(&arg_ord) != core::cmp::Ordering::Equal {
+        let (first, last) = if kind_ord < arg_ord {
+            (param.kind.descr(), arg.descr())
+        } else {
+            (arg.descr(), param.kind.descr())
+        };
+        err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+        if let Some(help) = help {
+            err.help(help);
         }
+    }
+
+    err.emit();
+}
 
-        err.emit();
+/// Creates the relevant generic argument substitutions
+/// corresponding to a set of generic parameters. This is a
+/// rather complex function. Let us try to explain the role
+/// of each of its parameters:
+///
+/// To start, we are given the `def_id` of the thing we are
+/// creating the substitutions for, and a partial set of
+/// substitutions `parent_substs`. In general, the substitutions
+/// for an item begin with substitutions for all the "parents" of
+/// that item -- e.g., for a method it might include the
+/// parameters from the impl.
+///
+/// Therefore, the method begins by walking down these parents,
+/// starting with the outermost parent and proceed inwards until
+/// it reaches `def_id`. For each parent `P`, it will check `parent_substs`
+/// first to see if the parent's substitutions are listed in there. If so,
+/// we can append those and move on. Otherwise, it invokes the
+/// three callback functions:
+///
+/// - `args_for_def_id`: given the `DefId` `P`, supplies back the
+///   generic arguments that were given to that parent from within
+///   the path; so e.g., if you have `<T as Foo>::Bar`, the `DefId`
+///   might refer to the trait `Foo`, and the arguments might be
+///   `[T]`. The boolean value indicates whether to infer values
+///   for arguments whose values were not explicitly provided.
+/// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
+///   instantiate a `GenericArg`.
+/// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
+///   creates a suitable inference variable.
+pub fn create_substs_for_generic_args<'tcx, 'a>(
+    tcx: TyCtxt<'tcx>,
+    def_id: DefId,
+    parent_substs: &[subst::GenericArg<'tcx>],
+    has_self: bool,
+    self_ty: Option<Ty<'tcx>>,
+    arg_count: &GenericArgCountResult,
+    ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
+) -> SubstsRef<'tcx> {
+    // Collect the segments of the path; we need to substitute arguments
+    // for parameters throughout the entire path (wherever there are
+    // generic parameters).
+    let mut parent_defs = tcx.generics_of(def_id);
+    let count = parent_defs.count();
+    let mut stack = vec![(def_id, parent_defs)];
+    while let Some(def_id) = parent_defs.parent {
+        parent_defs = tcx.generics_of(def_id);
+        stack.push((def_id, parent_defs));
     }
 
-    /// Creates the relevant generic argument substitutions
-    /// corresponding to a set of generic parameters. This is a
-    /// rather complex function. Let us try to explain the role
-    /// of each of its parameters:
-    ///
-    /// To start, we are given the `def_id` of the thing we are
-    /// creating the substitutions for, and a partial set of
-    /// substitutions `parent_substs`. In general, the substitutions
-    /// for an item begin with substitutions for all the "parents" of
-    /// that item -- e.g., for a method it might include the
-    /// parameters from the impl.
-    ///
-    /// Therefore, the method begins by walking down these parents,
-    /// starting with the outermost parent and proceed inwards until
-    /// it reaches `def_id`. For each parent `P`, it will check `parent_substs`
-    /// first to see if the parent's substitutions are listed in there. If so,
-    /// we can append those and move on. Otherwise, it invokes the
-    /// three callback functions:
-    ///
-    /// - `args_for_def_id`: given the `DefId` `P`, supplies back the
-    ///   generic arguments that were given to that parent from within
-    ///   the path; so e.g., if you have `<T as Foo>::Bar`, the `DefId`
-    ///   might refer to the trait `Foo`, and the arguments might be
-    ///   `[T]`. The boolean value indicates whether to infer values
-    ///   for arguments whose values were not explicitly provided.
-    /// - `provided_kind`: given the generic parameter and the value from `args_for_def_id`,
-    ///   instantiate a `GenericArg`.
-    /// - `inferred_kind`: if no parameter was provided, and inference is enabled, then
-    ///   creates a suitable inference variable.
-    pub fn create_substs_for_generic_args<'a>(
-        tcx: TyCtxt<'tcx>,
-        def_id: DefId,
-        parent_substs: &[subst::GenericArg<'tcx>],
-        has_self: bool,
-        self_ty: Option<Ty<'tcx>>,
-        arg_count: &GenericArgCountResult,
-        ctx: &mut impl CreateSubstsForGenericArgsCtxt<'a, 'tcx>,
-    ) -> SubstsRef<'tcx> {
-        // Collect the segments of the path; we need to substitute arguments
-        // for parameters throughout the entire path (wherever there are
-        // generic parameters).
-        let mut parent_defs = tcx.generics_of(def_id);
-        let count = parent_defs.count();
-        let mut stack = vec![(def_id, parent_defs)];
-        while let Some(def_id) = parent_defs.parent {
-            parent_defs = tcx.generics_of(def_id);
-            stack.push((def_id, parent_defs));
+    // We manually build up the substitution, rather than using convenience
+    // methods in `subst.rs`, so that we can iterate over the arguments and
+    // parameters in lock-step linearly, instead of trying to match each pair.
+    let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
+    // Iterate over each segment of the path.
+    while let Some((def_id, defs)) = stack.pop() {
+        let mut params = defs.params.iter().peekable();
+
+        // If we have already computed substitutions for parents, we can use those directly.
+        while let Some(&param) = params.peek() {
+            if let Some(&kind) = parent_substs.get(param.index as usize) {
+                substs.push(kind);
+                params.next();
+            } else {
+                break;
+            }
         }
 
-        // We manually build up the substitution, rather than using convenience
-        // methods in `subst.rs`, so that we can iterate over the arguments and
-        // parameters in lock-step linearly, instead of trying to match each pair.
-        let mut substs: SmallVec<[subst::GenericArg<'tcx>; 8]> = SmallVec::with_capacity(count);
-        // Iterate over each segment of the path.
-        while let Some((def_id, defs)) = stack.pop() {
-            let mut params = defs.params.iter().peekable();
-
-            // If we have already computed substitutions for parents, we can use those directly.
-            while let Some(&param) = params.peek() {
-                if let Some(&kind) = parent_substs.get(param.index as usize) {
-                    substs.push(kind);
-                    params.next();
-                } else {
-                    break;
+        // `Self` is handled first, unless it's been handled in `parent_substs`.
+        if has_self {
+            if let Some(&param) = params.peek() {
+                if param.index == 0 {
+                    if let GenericParamDefKind::Type { .. } = param.kind {
+                        substs.push(
+                            self_ty
+                                .map(|ty| ty.into())
+                                .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
+                        );
+                        params.next();
+                    }
                 }
             }
+        }
 
-            // `Self` is handled first, unless it's been handled in `parent_substs`.
-            if has_self {
-                if let Some(&param) = params.peek() {
-                    if param.index == 0 {
-                        if let GenericParamDefKind::Type { .. } = param.kind {
-                            substs.push(
-                                self_ty
-                                    .map(|ty| ty.into())
-                                    .unwrap_or_else(|| ctx.inferred_kind(None, param, true)),
-                            );
+        // Check whether this segment takes generic arguments and the user has provided any.
+        let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
+
+        let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
+        let mut args = args_iter.clone().peekable();
+
+        // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
+        // If we later encounter a lifetime, we know that the arguments were provided in the
+        // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
+        // inferred, so we can use it for diagnostics later.
+        let mut force_infer_lt = None;
+
+        loop {
+            // We're going to iterate through the generic arguments that the user
+            // provided, matching them with the generic parameters we expect.
+            // Mismatches can occur as a result of elided lifetimes, or for malformed
+            // input. We try to handle both sensibly.
+            match (args.peek(), params.peek()) {
+                (Some(&arg), Some(&param)) => {
+                    match (arg, &param.kind, arg_count.explicit_late_bound) {
+                        (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
+                        | (
+                            GenericArg::Type(_) | GenericArg::Infer(_),
+                            GenericParamDefKind::Type { .. },
+                            _,
+                        )
+                        | (
+                            GenericArg::Const(_) | GenericArg::Infer(_),
+                            GenericParamDefKind::Const { .. },
+                            _,
+                        ) => {
+                            substs.push(ctx.provided_kind(param, arg));
+                            args.next();
                             params.next();
                         }
-                    }
-                }
-            }
-
-            // Check whether this segment takes generic arguments and the user has provided any.
-            let (generic_args, infer_args) = ctx.args_for_def_id(def_id);
-
-            let args_iter = generic_args.iter().flat_map(|generic_args| generic_args.args.iter());
-            let mut args = args_iter.clone().peekable();
-
-            // If we encounter a type or const when we expect a lifetime, we infer the lifetimes.
-            // If we later encounter a lifetime, we know that the arguments were provided in the
-            // wrong order. `force_infer_lt` records the type or const that forced lifetimes to be
-            // inferred, so we can use it for diagnostics later.
-            let mut force_infer_lt = None;
-
-            loop {
-                // We're going to iterate through the generic arguments that the user
-                // provided, matching them with the generic parameters we expect.
-                // Mismatches can occur as a result of elided lifetimes, or for malformed
-                // input. We try to handle both sensibly.
-                match (args.peek(), params.peek()) {
-                    (Some(&arg), Some(&param)) => {
-                        match (arg, &param.kind, arg_count.explicit_late_bound) {
-                            (GenericArg::Lifetime(_), GenericParamDefKind::Lifetime, _)
-                            | (
-                                GenericArg::Type(_) | GenericArg::Infer(_),
-                                GenericParamDefKind::Type { .. },
-                                _,
-                            )
-                            | (
-                                GenericArg::Const(_) | GenericArg::Infer(_),
-                                GenericParamDefKind::Const { .. },
-                                _,
-                            ) => {
-                                substs.push(ctx.provided_kind(param, arg));
-                                args.next();
-                                params.next();
-                            }
-                            (
-                                GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
-                                GenericParamDefKind::Lifetime,
-                                _,
-                            ) => {
-                                // We expected a lifetime argument, but got a type or const
-                                // argument. That means we're inferring the lifetimes.
-                                substs.push(ctx.inferred_kind(None, param, infer_args));
-                                force_infer_lt = Some((arg, param));
-                                params.next();
-                            }
-                            (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
-                                // We've come across a lifetime when we expected something else in
-                                // the presence of explicit late bounds. This is most likely
-                                // due to the presence of the explicit bound so we're just going to
-                                // ignore it.
-                                args.next();
-                            }
-                            (_, _, _) => {
-                                // We expected one kind of parameter, but the user provided
-                                // another. This is an error. However, if we already know that
-                                // the arguments don't match up with the parameters, we won't issue
-                                // an additional error, as the user already knows what's wrong.
-                                if arg_count.correct.is_ok() {
-                                    // We're going to iterate over the parameters to sort them out, and
-                                    // show that order to the user as a possible order for the parameters
-                                    let mut param_types_present = defs
-                                        .params
-                                        .iter()
-                                        .map(|param| (param.kind.to_ord(), param.clone()))
-                                        .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
-                                    param_types_present.sort_by_key(|(ord, _)| *ord);
-                                    let (mut param_types_present, ordered_params): (
-                                        Vec<ParamKindOrd>,
-                                        Vec<GenericParamDef>,
-                                    ) = param_types_present.into_iter().unzip();
-                                    param_types_present.dedup();
-
-                                    Self::generic_arg_mismatch_err(
-                                        tcx,
-                                        arg,
-                                        param,
-                                        !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
-                                        Some(&format!(
-                                            "reorder the arguments: {}: `<{}>`",
-                                            param_types_present
-                                                .into_iter()
-                                                .map(|ord| format!("{}s", ord))
-                                                .collect::<Vec<String>>()
-                                                .join(", then "),
-                                            ordered_params
-                                                .into_iter()
-                                                .filter_map(|param| {
-                                                    if param.name == kw::SelfUpper {
-                                                        None
-                                                    } else {
-                                                        Some(param.name.to_string())
-                                                    }
-                                                })
-                                                .collect::<Vec<String>>()
-                                                .join(", ")
-                                        )),
-                                    );
-                                }
-
-                                // We've reported the error, but we want to make sure that this
-                                // problem doesn't bubble down and create additional, irrelevant
-                                // errors. In this case, we're simply going to ignore the argument
-                                // and any following arguments. The rest of the parameters will be
-                                // inferred.
-                                while args.next().is_some() {}
-                            }
+                        (
+                            GenericArg::Infer(_) | GenericArg::Type(_) | GenericArg::Const(_),
+                            GenericParamDefKind::Lifetime,
+                            _,
+                        ) => {
+                            // We expected a lifetime argument, but got a type or const
+                            // argument. That means we're inferring the lifetimes.
+                            substs.push(ctx.inferred_kind(None, param, infer_args));
+                            force_infer_lt = Some((arg, param));
+                            params.next();
                         }
-                    }
-
-                    (Some(&arg), None) => {
-                        // We should never be able to reach this point with well-formed input.
-                        // There are three situations in which we can encounter this issue.
-                        //
-                        //  1.  The number of arguments is incorrect. In this case, an error
-                        //      will already have been emitted, and we can ignore it.
-                        //  2.  There are late-bound lifetime parameters present, yet the
-                        //      lifetime arguments have also been explicitly specified by the
-                        //      user.
-                        //  3.  We've inferred some lifetimes, which have been provided later (i.e.
-                        //      after a type or const). We want to throw an error in this case.
-
-                        if arg_count.correct.is_ok()
-                            && arg_count.explicit_late_bound == ExplicitLateBound::No
-                        {
-                            let kind = arg.descr();
-                            assert_eq!(kind, "lifetime");
-                            let (provided_arg, param) =
-                                force_infer_lt.expect("lifetimes ought to have been inferred");
-                            Self::generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
+                        (GenericArg::Lifetime(_), _, ExplicitLateBound::Yes) => {
+                            // We've come across a lifetime when we expected something else in
+                            // the presence of explicit late bounds. This is most likely
+                            // due to the presence of the explicit bound so we're just going to
+                            // ignore it.
+                            args.next();
                         }
+                        (_, _, _) => {
+                            // We expected one kind of parameter, but the user provided
+                            // another. This is an error. However, if we already know that
+                            // the arguments don't match up with the parameters, we won't issue
+                            // an additional error, as the user already knows what's wrong.
+                            if arg_count.correct.is_ok() {
+                                // We're going to iterate over the parameters to sort them out, and
+                                // show that order to the user as a possible order for the parameters
+                                let mut param_types_present = defs
+                                    .params
+                                    .iter()
+                                    .map(|param| (param.kind.to_ord(), param.clone()))
+                                    .collect::<Vec<(ParamKindOrd, GenericParamDef)>>();
+                                param_types_present.sort_by_key(|(ord, _)| *ord);
+                                let (mut param_types_present, ordered_params): (
+                                    Vec<ParamKindOrd>,
+                                    Vec<GenericParamDef>,
+                                ) = param_types_present.into_iter().unzip();
+                                param_types_present.dedup();
+
+                                generic_arg_mismatch_err(
+                                    tcx,
+                                    arg,
+                                    param,
+                                    !args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
+                                    Some(&format!(
+                                        "reorder the arguments: {}: `<{}>`",
+                                        param_types_present
+                                            .into_iter()
+                                            .map(|ord| format!("{}s", ord))
+                                            .collect::<Vec<String>>()
+                                            .join(", then "),
+                                        ordered_params
+                                            .into_iter()
+                                            .filter_map(|param| {
+                                                if param.name == kw::SelfUpper {
+                                                    None
+                                                } else {
+                                                    Some(param.name.to_string())
+                                                }
+                                            })
+                                            .collect::<Vec<String>>()
+                                            .join(", ")
+                                    )),
+                                );
+                            }
 
-                        break;
+                            // We've reported the error, but we want to make sure that this
+                            // problem doesn't bubble down and create additional, irrelevant
+                            // errors. In this case, we're simply going to ignore the argument
+                            // and any following arguments. The rest of the parameters will be
+                            // inferred.
+                            while args.next().is_some() {}
+                        }
                     }
+                }
 
-                    (None, Some(&param)) => {
-                        // If there are fewer arguments than parameters, it means
-                        // we're inferring the remaining arguments.
-                        substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
-                        params.next();
+                (Some(&arg), None) => {
+                    // We should never be able to reach this point with well-formed input.
+                    // There are three situations in which we can encounter this issue.
+                    //
+                    //  1.  The number of arguments is incorrect. In this case, an error
+                    //      will already have been emitted, and we can ignore it.
+                    //  2.  There are late-bound lifetime parameters present, yet the
+                    //      lifetime arguments have also been explicitly specified by the
+                    //      user.
+                    //  3.  We've inferred some lifetimes, which have been provided later (i.e.
+                    //      after a type or const). We want to throw an error in this case.
+
+                    if arg_count.correct.is_ok()
+                        && arg_count.explicit_late_bound == ExplicitLateBound::No
+                    {
+                        let kind = arg.descr();
+                        assert_eq!(kind, "lifetime");
+                        let (provided_arg, param) =
+                            force_infer_lt.expect("lifetimes ought to have been inferred");
+                        generic_arg_mismatch_err(tcx, provided_arg, param, false, None);
                     }
 
-                    (None, None) => break,
+                    break;
+                }
+
+                (None, Some(&param)) => {
+                    // If there are fewer arguments than parameters, it means
+                    // we're inferring the remaining arguments.
+                    substs.push(ctx.inferred_kind(Some(&substs), param, infer_args));
+                    params.next();
                 }
+
+                (None, None) => break,
             }
         }
-
-        tcx.intern_substs(&substs)
     }
 
-    /// Checks that the correct number of generic arguments have been provided.
-    /// Used specifically for function calls.
-    pub fn check_generic_arg_count_for_call(
-        tcx: TyCtxt<'_>,
-        span: Span,
-        def_id: DefId,
-        generics: &ty::Generics,
-        seg: &hir::PathSegment<'_>,
-        is_method_call: IsMethodCall,
-    ) -> GenericArgCountResult {
-        let empty_args = hir::GenericArgs::none();
-        let gen_args = seg.args.unwrap_or(&empty_args);
-        let gen_pos = if is_method_call == IsMethodCall::Yes {
-            GenericArgPosition::MethodCall
+    tcx.intern_substs(&substs)
+}
+
+/// Checks that the correct number of generic arguments have been provided.
+/// Used specifically for function calls.
+pub fn check_generic_arg_count_for_call(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    def_id: DefId,
+    generics: &ty::Generics,
+    seg: &hir::PathSegment<'_>,
+    is_method_call: IsMethodCall,
+) -> GenericArgCountResult {
+    let empty_args = hir::GenericArgs::none();
+    let gen_args = seg.args.unwrap_or(&empty_args);
+    let gen_pos = if is_method_call == IsMethodCall::Yes {
+        GenericArgPosition::MethodCall
+    } else {
+        GenericArgPosition::Value
+    };
+    let has_self = generics.parent.is_none() && generics.has_self;
+
+    check_generic_arg_count(
+        tcx,
+        span,
+        def_id,
+        seg,
+        generics,
+        gen_args,
+        gen_pos,
+        has_self,
+        seg.infer_args,
+    )
+}
+
+/// Checks that the correct number of generic arguments have been provided.
+/// This is used both for datatypes and function calls.
+#[instrument(skip(tcx, gen_pos), level = "debug")]
+pub(crate) fn check_generic_arg_count(
+    tcx: TyCtxt<'_>,
+    span: Span,
+    def_id: DefId,
+    seg: &hir::PathSegment<'_>,
+    gen_params: &ty::Generics,
+    gen_args: &hir::GenericArgs<'_>,
+    gen_pos: GenericArgPosition,
+    has_self: bool,
+    infer_args: bool,
+) -> GenericArgCountResult {
+    let default_counts = gen_params.own_defaults();
+    let param_counts = gen_params.own_counts();
+
+    // Subtracting from param count to ensure type params synthesized from `impl Trait`
+    // cannot be explicitly specified.
+    let synth_type_param_count = gen_params
+        .params
+        .iter()
+        .filter(|param| matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. }))
+        .count();
+    let named_type_param_count = param_counts.types - has_self as usize - synth_type_param_count;
+    let infer_lifetimes =
+        (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
+
+    if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
+            prohibit_assoc_ty_binding(tcx, b.span);
+        }
+
+    let explicit_late_bound =
+        prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
+
+    let mut invalid_args = vec![];
+
+    let mut check_lifetime_args = |min_expected_args: usize,
+                                   max_expected_args: usize,
+                                   provided_args: usize,
+                                   late_bounds_ignore: bool| {
+        if (min_expected_args..=max_expected_args).contains(&provided_args) {
+            return Ok(());
+        }
+
+        if late_bounds_ignore {
+            return Ok(());
+        }
+
+        if provided_args > max_expected_args {
+            invalid_args.extend(
+                gen_args.args[max_expected_args..provided_args].iter().map(|arg| arg.span()),
+            );
+        };
+
+        let gen_args_info = if provided_args > min_expected_args {
+            invalid_args.extend(
+                gen_args.args[min_expected_args..provided_args].iter().map(|arg| arg.span()),
+            );
+            let num_redundant_args = provided_args - min_expected_args;
+            GenericArgsInfo::ExcessLifetimes { num_redundant_args }
         } else {
-            GenericArgPosition::Value
+            let num_missing_args = min_expected_args - provided_args;
+            GenericArgsInfo::MissingLifetimes { num_missing_args }
         };
-        let has_self = generics.parent.is_none() && generics.has_self;
 
-        Self::check_generic_arg_count(
+        let reported = WrongNumberOfGenericArgs::new(
             tcx,
-            span,
-            def_id,
+            gen_args_info,
             seg,
-            generics,
+            gen_params,
+            has_self as usize,
             gen_args,
-            gen_pos,
-            has_self,
-            seg.infer_args,
+            def_id,
         )
-    }
-
-    /// Checks that the correct number of generic arguments have been provided.
-    /// This is used both for datatypes and function calls.
-    #[instrument(skip(tcx, gen_pos), level = "debug")]
-    pub(crate) fn check_generic_arg_count(
-        tcx: TyCtxt<'_>,
-        span: Span,
-        def_id: DefId,
-        seg: &hir::PathSegment<'_>,
-        gen_params: &ty::Generics,
-        gen_args: &hir::GenericArgs<'_>,
-        gen_pos: GenericArgPosition,
-        has_self: bool,
-        infer_args: bool,
-    ) -> GenericArgCountResult {
-        let default_counts = gen_params.own_defaults();
-        let param_counts = gen_params.own_counts();
-
-        // Subtracting from param count to ensure type params synthesized from `impl Trait`
-        // cannot be explicitly specified.
-        let synth_type_param_count = gen_params
-            .params
-            .iter()
-            .filter(|param| {
-                matches!(param.kind, ty::GenericParamDefKind::Type { synthetic: true, .. })
-            })
-            .count();
-        let named_type_param_count =
-            param_counts.types - has_self as usize - synth_type_param_count;
-        let infer_lifetimes =
-            (gen_pos != GenericArgPosition::Type || infer_args) && !gen_args.has_lifetime_params();
-
-        if gen_pos != GenericArgPosition::Type && let Some(b) = gen_args.bindings.first() {
-            Self::prohibit_assoc_ty_binding(tcx, b.span);
+        .diagnostic()
+        .emit();
+
+        Err(reported)
+    };
+
+    let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
+    let max_expected_lifetime_args = param_counts.lifetimes;
+    let num_provided_lifetime_args = gen_args.num_lifetime_params();
+
+    let lifetimes_correct = check_lifetime_args(
+        min_expected_lifetime_args,
+        max_expected_lifetime_args,
+        num_provided_lifetime_args,
+        explicit_late_bound == ExplicitLateBound::Yes,
+    );
+
+    let mut check_types_and_consts = |expected_min,
+                                      expected_max,
+                                      expected_max_with_synth,
+                                      provided,
+                                      params_offset,
+                                      args_offset| {
+        debug!(
+            ?expected_min,
+            ?expected_max,
+            ?provided,
+            ?params_offset,
+            ?args_offset,
+            "check_types_and_consts"
+        );
+        if (expected_min..=expected_max).contains(&provided) {
+            return Ok(());
         }
 
-        let explicit_late_bound =
-            Self::prohibit_explicit_late_bound_lifetimes(tcx, gen_params, gen_args, gen_pos);
-
-        let mut invalid_args = vec![];
+        let num_default_params = expected_max - expected_min;
 
-        let mut check_lifetime_args =
-            |min_expected_args: usize,
-             max_expected_args: usize,
-             provided_args: usize,
-             late_bounds_ignore: bool| {
-                if (min_expected_args..=max_expected_args).contains(&provided_args) {
-                    return Ok(());
-                }
-
-                if late_bounds_ignore {
-                    return Ok(());
-                }
+        let gen_args_info = if provided > expected_max {
+            invalid_args.extend(
+                gen_args.args[args_offset + expected_max..args_offset + provided]
+                    .iter()
+                    .map(|arg| arg.span()),
+            );
+            let num_redundant_args = provided - expected_max;
 
-                if provided_args > max_expected_args {
-                    invalid_args.extend(
-                        gen_args.args[max_expected_args..provided_args]
-                            .iter()
-                            .map(|arg| arg.span()),
-                    );
-                };
-
-                let gen_args_info = if provided_args > min_expected_args {
-                    invalid_args.extend(
-                        gen_args.args[min_expected_args..provided_args]
-                            .iter()
-                            .map(|arg| arg.span()),
-                    );
-                    let num_redundant_args = provided_args - min_expected_args;
-                    GenericArgsInfo::ExcessLifetimes { num_redundant_args }
-                } else {
-                    let num_missing_args = min_expected_args - provided_args;
-                    GenericArgsInfo::MissingLifetimes { num_missing_args }
-                };
-
-                let reported = WrongNumberOfGenericArgs::new(
-                    tcx,
-                    gen_args_info,
-                    seg,
-                    gen_params,
-                    has_self as usize,
-                    gen_args,
-                    def_id,
-                )
-                .diagnostic()
-                .emit();
-
-                Err(reported)
-            };
-
-        let min_expected_lifetime_args = if infer_lifetimes { 0 } else { param_counts.lifetimes };
-        let max_expected_lifetime_args = param_counts.lifetimes;
-        let num_provided_lifetime_args = gen_args.num_lifetime_params();
-
-        let lifetimes_correct = check_lifetime_args(
-            min_expected_lifetime_args,
-            max_expected_lifetime_args,
-            num_provided_lifetime_args,
-            explicit_late_bound == ExplicitLateBound::Yes,
-        );
+            // Provide extra note if synthetic arguments like `impl Trait` are specified.
+            let synth_provided = provided <= expected_max_with_synth;
 
-        let mut check_types_and_consts = |expected_min,
-                                          expected_max,
-                                          expected_max_with_synth,
-                                          provided,
-                                          params_offset,
-                                          args_offset| {
-            debug!(
-                ?expected_min,
-                ?expected_max,
-                ?provided,
-                ?params_offset,
-                ?args_offset,
-                "check_types_and_consts"
-            );
-            if (expected_min..=expected_max).contains(&provided) {
-                return Ok(());
+            GenericArgsInfo::ExcessTypesOrConsts {
+                num_redundant_args,
+                num_default_params,
+                args_offset,
+                synth_provided,
             }
+        } else {
+            let num_missing_args = expected_max - provided;
 
-            let num_default_params = expected_max - expected_min;
-
-            let gen_args_info = if provided > expected_max {
-                invalid_args.extend(
-                    gen_args.args[args_offset + expected_max..args_offset + provided]
-                        .iter()
-                        .map(|arg| arg.span()),
-                );
-                let num_redundant_args = provided - expected_max;
+            GenericArgsInfo::MissingTypesOrConsts {
+                num_missing_args,
+                num_default_params,
+                args_offset,
+            }
+        };
 
-                // Provide extra note if synthetic arguments like `impl Trait` are specified.
-                let synth_provided = provided <= expected_max_with_synth;
+        debug!(?gen_args_info);
 
-                GenericArgsInfo::ExcessTypesOrConsts {
-                    num_redundant_args,
-                    num_default_params,
-                    args_offset,
-                    synth_provided,
-                }
-            } else {
-                let num_missing_args = expected_max - provided;
+        let reported = WrongNumberOfGenericArgs::new(
+            tcx,
+            gen_args_info,
+            seg,
+            gen_params,
+            params_offset,
+            gen_args,
+            def_id,
+        )
+        .diagnostic()
+        .emit_unless(gen_args.has_err());
 
-                GenericArgsInfo::MissingTypesOrConsts {
-                    num_missing_args,
-                    num_default_params,
-                    args_offset,
-                }
-            };
-
-            debug!(?gen_args_info);
-
-            let reported = WrongNumberOfGenericArgs::new(
-                tcx,
-                gen_args_info,
-                seg,
-                gen_params,
-                params_offset,
-                gen_args,
-                def_id,
-            )
-            .diagnostic()
-            .emit_unless(gen_args.has_err());
-
-            Err(reported)
-        };
+        Err(reported)
+    };
 
-        let args_correct = {
-            let expected_min = if infer_args {
-                0
-            } else {
-                param_counts.consts + named_type_param_count
-                    - default_counts.types
-                    - default_counts.consts
-            };
-            debug!(?expected_min);
-            debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
-
-            check_types_and_consts(
-                expected_min,
-                param_counts.consts + named_type_param_count,
-                param_counts.consts + named_type_param_count + synth_type_param_count,
-                gen_args.num_generic_params(),
-                param_counts.lifetimes + has_self as usize,
-                gen_args.num_lifetime_params(),
-            )
+    let args_correct = {
+        let expected_min = if infer_args {
+            0
+        } else {
+            param_counts.consts + named_type_param_count
+                - default_counts.types
+                - default_counts.consts
         };
+        debug!(?expected_min);
+        debug!(arg_counts.lifetimes=?gen_args.num_lifetime_params());
+
+        check_types_and_consts(
+            expected_min,
+            param_counts.consts + named_type_param_count,
+            param_counts.consts + named_type_param_count + synth_type_param_count,
+            gen_args.num_generic_params(),
+            param_counts.lifetimes + has_self as usize,
+            gen_args.num_lifetime_params(),
+        )
+    };
 
-        GenericArgCountResult {
-            explicit_late_bound,
-            correct: lifetimes_correct.and(args_correct).map_err(|reported| {
-                GenericArgCountMismatch { reported: Some(reported), invalid_args }
-            }),
-        }
+    GenericArgCountResult {
+        explicit_late_bound,
+        correct: lifetimes_correct
+            .and(args_correct)
+            .map_err(|reported| GenericArgCountMismatch { reported: Some(reported), invalid_args }),
     }
+}
 
-    /// Emits an error regarding forbidden type binding associations
-    pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
-        tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
-    }
+/// Emits an error regarding forbidden type binding associations
+pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) {
+    tcx.sess.emit_err(AssocTypeBindingNotAllowed { span });
+}
 
-    /// Prohibits explicit lifetime arguments if late-bound lifetime parameters
-    /// are present. This is used both for datatypes and function calls.
-    pub(crate) fn prohibit_explicit_late_bound_lifetimes(
-        tcx: TyCtxt<'_>,
-        def: &ty::Generics,
-        args: &hir::GenericArgs<'_>,
-        position: GenericArgPosition,
-    ) -> ExplicitLateBound {
-        let param_counts = def.own_counts();
-        let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
-
-        if infer_lifetimes {
-            return ExplicitLateBound::No;
-        }
+/// Prohibits explicit lifetime arguments if late-bound lifetime parameters
+/// are present. This is used both for datatypes and function calls.
+pub(crate) fn prohibit_explicit_late_bound_lifetimes(
+    tcx: TyCtxt<'_>,
+    def: &ty::Generics,
+    args: &hir::GenericArgs<'_>,
+    position: GenericArgPosition,
+) -> ExplicitLateBound {
+    let param_counts = def.own_counts();
+    let infer_lifetimes = position != GenericArgPosition::Type && !args.has_lifetime_params();
+
+    if infer_lifetimes {
+        return ExplicitLateBound::No;
+    }
 
-        if let Some(span_late) = def.has_late_bound_regions {
-            let msg = "cannot specify lifetime arguments explicitly \
+    if let Some(span_late) = def.has_late_bound_regions {
+        let msg = "cannot specify lifetime arguments explicitly \
                        if late bound lifetime parameters are present";
-            let note = "the late bound lifetime parameter is introduced here";
-            let span = args.args[0].span();
-
-            if position == GenericArgPosition::Value
-                && args.num_lifetime_params() != param_counts.lifetimes
-            {
-                let mut err = tcx.sess.struct_span_err(span, msg);
-                err.span_note(span_late, note);
-                err.emit();
-            } else {
-                let mut multispan = MultiSpan::from_span(span);
-                multispan.push_span_label(span_late, note);
-                tcx.struct_span_lint_hir(
-                    LATE_BOUND_LIFETIME_ARGUMENTS,
-                    args.args[0].hir_id(),
-                    multispan,
-                    msg,
-                    |lint| lint,
-                );
-            }
-
-            ExplicitLateBound::Yes
+        let note = "the late bound lifetime parameter is introduced here";
+        let span = args.args[0].span();
+
+        if position == GenericArgPosition::Value
+            && args.num_lifetime_params() != param_counts.lifetimes
+        {
+            let mut err = tcx.sess.struct_span_err(span, msg);
+            err.span_note(span_late, note);
+            err.emit();
         } else {
-            ExplicitLateBound::No
+            let mut multispan = MultiSpan::from_span(span);
+            multispan.push_span_label(span_late, note);
+            tcx.struct_span_lint_hir(
+                LATE_BOUND_LIFETIME_ARGUMENTS,
+                args.args[0].hir_id(),
+                multispan,
+                msg,
+                |lint| lint,
+            );
         }
+
+        ExplicitLateBound::Yes
+    } else {
+        ExplicitLateBound::No
     }
 }
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 5a7957be318..9fa0e6e8eaa 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -3,8 +3,11 @@
 //! instance of `AstConv`.
 
 mod errors;
-mod generics;
+pub mod generics;
 
+use crate::astconv::generics::{
+    check_generic_arg_count, create_substs_for_generic_args, prohibit_assoc_ty_binding,
+};
 use crate::bounds::Bounds;
 use crate::collect::HirPlaceholderCollector;
 use crate::errors::{
@@ -120,6 +123,13 @@ pub trait AstConv<'tcx> {
     fn set_tainted_by_errors(&self, e: ErrorGuaranteed);
 
     fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, span: Span);
+
+    fn astconv(&self) -> &dyn AstConv<'tcx>
+    where
+        Self: Sized,
+    {
+        self
+    }
 }
 
 #[derive(Debug)]
@@ -279,7 +289,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             ty::BoundConstness::NotConst,
         );
         if let Some(b) = item_segment.args().bindings.first() {
-            Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+            prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
 
         substs
@@ -349,7 +359,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             assert!(self_ty.is_none());
         }
 
-        let arg_count = Self::check_generic_arg_count(
+        let arg_count = check_generic_arg_count(
             tcx,
             span,
             def_id,
@@ -524,7 +534,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             inferred_params: vec![],
             infer_args,
         };
-        let substs = Self::create_substs_for_generic_args(
+        let substs = create_substs_for_generic_args(
             tcx,
             def_id,
             parent_substs,
@@ -610,7 +620,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         );
 
         if let Some(b) = item_segment.args().bindings.first() {
-            Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+            prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
 
         args
@@ -804,7 +814,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
             constness,
         );
         if let Some(b) = trait_segment.args().bindings.first() {
-            Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+            prohibit_assoc_ty_binding(self.tcx(), b.span);
         }
         self.tcx().mk_trait_ref(trait_def_id, substs)
     }
@@ -2301,7 +2311,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
         for segment in segments {
             // Only emit the first error to avoid overloading the user with error messages.
             if let Some(b) = segment.args().bindings.first() {
-                Self::prohibit_assoc_ty_binding(self.tcx(), b.span);
+                prohibit_assoc_ty_binding(self.tcx(), b.span);
                 return true;
             }
         }
diff --git a/compiler/rustc_trait_selection/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index e988c77a064..730560cc686 100644
--- a/compiler/rustc_trait_selection/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -178,6 +178,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
         self.state.obligations
     }
 
+    pub fn current_obligations(&self) -> Vec<traits::PredicateObligation<'tcx>> {
+        self.state.obligations.clone()
+    }
+
     pub fn steps(&self) -> &[(Ty<'tcx>, AutoderefKind)] {
         &self.state.steps
     }
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index e9baab59453..d1f4dbc8d84 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -1,4 +1,6 @@
+use crate::autoderef::Autoderef;
 use crate::constrained_generic_params::{identify_constrained_generic_params, Parameter};
+
 use hir::def::DefKind;
 use rustc_ast as ast;
 use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet};
@@ -22,7 +24,6 @@ use rustc_session::parse::feature_err;
 use rustc_span::symbol::{sym, Ident, Symbol};
 use rustc_span::{Span, DUMMY_SP};
 use rustc_target::spec::abi::Abi;
-use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
 use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index b7f259668a1..cd745ee8cab 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -351,7 +351,7 @@ impl<'tcx> ItemCtxt<'tcx> {
     }
 
     pub fn to_ty(&self, ast_ty: &hir::Ty<'_>) -> Ty<'tcx> {
-        <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_ty)
+        self.astconv().ast_ty_to_ty(ast_ty)
     }
 
     pub fn hir_id(&self) -> hir::HirId {
@@ -413,8 +413,7 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
         poly_trait_ref: ty::PolyTraitRef<'tcx>,
     ) -> Ty<'tcx> {
         if let Some(trait_ref) = poly_trait_ref.no_bound_vars() {
-            let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
-                self,
+            let item_substs = self.astconv().create_substs_for_associated_item(
                 span,
                 item_def_id,
                 item_segment,
@@ -1112,8 +1111,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
                 tcx.hir().get_parent(hir_id)
                 && i.of_trait.is_some()
             {
-                <dyn AstConv<'_>>::ty_of_fn(
-                    &icx,
+                icx.astconv().ty_of_fn(
                     hir_id,
                     sig.header.unsafety,
                     sig.header.abi,
@@ -1130,15 +1128,9 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: DefId) -> ty::PolyFnSig<'_> {
             kind: TraitItemKind::Fn(FnSig { header, decl, span: _ }, _),
             generics,
             ..
-        }) => <dyn AstConv<'_>>::ty_of_fn(
-            &icx,
-            hir_id,
-            header.unsafety,
-            header.abi,
-            decl,
-            Some(generics),
-            None,
-        ),
+        }) => {
+            icx.astconv().ty_of_fn(hir_id, header.unsafety, header.abi, decl, Some(generics), None)
+        }
 
         ForeignItem(&hir::ForeignItem { kind: ForeignItemKind::Fn(fn_decl, _, _), .. }) => {
             let abi = tcx.hir().get_foreign_abi(hir_id);
@@ -1244,8 +1236,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
 
             ty::Binder::dummy(fn_sig)
         }
-        None => <dyn AstConv<'_>>::ty_of_fn(
-            icx,
+        None => icx.astconv().ty_of_fn(
             hir_id,
             sig.header.unsafety,
             sig.header.abi,
@@ -1354,8 +1345,7 @@ fn impl_trait_ref(tcx: TyCtxt<'_>, def_id: DefId) -> Option<ty::TraitRef<'_>> {
     match item.kind {
         hir::ItemKind::Impl(ref impl_) => impl_.of_trait.as_ref().map(|ast_trait_ref| {
             let selfty = tcx.type_of(def_id);
-            <dyn AstConv<'_>>::instantiate_mono_trait_ref(
-                &icx,
+            icx.astconv().instantiate_mono_trait_ref(
                 ast_trait_ref,
                 selfty,
                 check_impl_constness(tcx, impl_.constness, ast_trait_ref),
@@ -1485,15 +1475,8 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
         hir::Unsafety::Unsafe
     };
     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
-    let fty = <dyn AstConv<'_>>::ty_of_fn(
-        &ItemCtxt::new(tcx, def_id),
-        hir_id,
-        unsafety,
-        abi,
-        decl,
-        None,
-        None,
-    );
+    let fty =
+        ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None);
 
     // Feature gate SIMD types in FFI, since I am not sure that the
     // ABIs are handled at all correctly. -huonw
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 093e9560ccd..62eef710ba4 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -26,9 +26,9 @@ fn associated_type_bounds<'tcx>(
     );
 
     let icx = ItemCtxt::new(tcx, assoc_item_def_id);
-    let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+    let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
     // Associated types are implicitly sized unless a `?Sized` bound is found
-    <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
+    icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
 
     let trait_def_id = tcx.parent(assoc_item_def_id);
     let trait_predicates = tcx.trait_explicit_predicates_and_bounds(trait_def_id.expect_local());
@@ -70,9 +70,9 @@ fn opaque_type_bounds<'tcx>(
         };
 
         let icx = ItemCtxt::new(tcx, opaque_def_id);
-        let mut bounds = <dyn AstConv<'_>>::compute_bounds(&icx, item_ty, ast_bounds);
+        let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
         // Opaque types are implicitly sized unless a `?Sized` bound is found
-        <dyn AstConv<'_>>::add_implicitly_sized(&icx, &mut bounds, item_ty, ast_bounds, None, span);
+        icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
         debug!(?bounds);
 
         tcx.arena.alloc_from_iter(bounds.predicates())
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 18fc43ce15c..23425355684 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -162,8 +162,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
 
                 let mut bounds = Bounds::default();
                 // Params are implicitly sized unless a `?Sized` bound is found
-                <dyn AstConv<'_>>::add_implicitly_sized(
-                    &icx,
+                icx.astconv().add_implicitly_sized(
                     &mut bounds,
                     param_ty,
                     &[],
@@ -211,22 +210,16 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
                 }
 
                 let mut bounds = Bounds::default();
-                <dyn AstConv<'_>>::add_bounds(
-                    &icx,
-                    ty,
-                    bound_pred.bounds.iter(),
-                    &mut bounds,
-                    bound_vars,
-                );
+                icx.astconv().add_bounds(ty, bound_pred.bounds.iter(), &mut bounds, bound_vars);
                 predicates.extend(bounds.predicates());
             }
 
             hir::WherePredicate::RegionPredicate(region_pred) => {
-                let r1 = <dyn AstConv<'_>>::ast_region_to_region(&icx, &region_pred.lifetime, None);
+                let r1 = icx.astconv().ast_region_to_region(&region_pred.lifetime, None);
                 predicates.extend(region_pred.bounds.iter().map(|bound| {
                     let (r2, span) = match bound {
                         hir::GenericBound::Outlives(lt) => {
-                            (<dyn AstConv<'_>>::ast_region_to_region(&icx, lt, None), lt.ident.span)
+                            (icx.astconv().ast_region_to_region(lt, None), lt.ident.span)
                         }
                         _ => bug!(),
                     };
@@ -279,7 +272,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericP
         debug!(?lifetimes);
         for (arg, duplicate) in std::iter::zip(lifetimes, ast_generics.params) {
             let hir::GenericArg::Lifetime(arg) = arg else { bug!() };
-            let orig_region = <dyn AstConv<'_>>::ast_region_to_region(&icx, &arg, None);
+            let orig_region = icx.astconv().ast_region_to_region(&arg, None);
             if !matches!(orig_region.kind(), ty::ReEarlyBound(..)) {
                 // Only early-bound regions can point to the original generic parameter.
                 continue;
@@ -527,14 +520,9 @@ pub(super) fn super_predicates_that_define_assoc_type(
         // Convert the bounds that follow the colon, e.g., `Bar + Zed` in `trait Foo: Bar + Zed`.
         let self_param_ty = tcx.types.self_param;
         let superbounds1 = if let Some(assoc_name) = assoc_name {
-            <dyn AstConv<'_>>::compute_bounds_that_match_assoc_type(
-                &icx,
-                self_param_ty,
-                bounds,
-                assoc_name,
-            )
+            icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name)
         } else {
-            <dyn AstConv<'_>>::compute_bounds(&icx, self_param_ty, bounds)
+            icx.astconv().compute_bounds(self_param_ty, bounds)
         };
 
         let superbounds1 = superbounds1.predicates();
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index d383fcacb3a..04f5f3f6276 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -300,3 +300,15 @@ pub(crate) struct LinkageType {
     #[primary_span]
     pub span: Span,
 }
+
+#[derive(Diagnostic)]
+#[help]
+#[diag(hir_analysis_auto_deref_reached_recursion_limit, code = "E0055")]
+pub struct AutoDerefReachedRecursionLimit<'a> {
+    #[primary_span]
+    #[label]
+    pub span: Span,
+    pub ty: Ty<'a>,
+    pub suggested_limit: rustc_session::Limit,
+    pub crate_name: Symbol,
+}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 2058832d5fd..ddc5b766881 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -84,6 +84,7 @@ extern crate rustc_middle;
 pub mod check;
 
 pub mod astconv;
+pub mod autoderef;
 mod bounds;
 mod check_unused;
 mod coherence;
@@ -544,7 +545,7 @@ pub fn hir_ty_to_ty<'tcx>(tcx: TyCtxt<'tcx>, hir_ty: &hir::Ty<'_>) -> Ty<'tcx> {
     // scope.  This is derived from the enclosing item-like thing.
     let env_def_id = tcx.hir().get_parent_item(hir_ty.hir_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
-    <dyn AstConv<'_>>::ast_ty_to_ty(&item_cx, hir_ty)
+    item_cx.astconv().ast_ty_to_ty(hir_ty)
 }
 
 pub fn hir_trait_to_predicates<'tcx>(
@@ -558,8 +559,7 @@ pub fn hir_trait_to_predicates<'tcx>(
     let env_def_id = tcx.hir().get_parent_item(hir_trait.hir_ref_id);
     let item_cx = self::collect::ItemCtxt::new(tcx, env_def_id.to_def_id());
     let mut bounds = Bounds::default();
-    let _ = <dyn AstConv<'_>>::instantiate_poly_trait_ref(
-        &item_cx,
+    let _ = &item_cx.astconv().instantiate_poly_trait_ref(
         hir_trait,
         DUMMY_SP,
         ty::BoundConstness::NotConst,
diff --git a/compiler/rustc_hir_typeck/src/autoderef.rs b/compiler/rustc_hir_typeck/src/autoderef.rs
index 41b52a4c4a9..7873257c4e3 100644
--- a/compiler/rustc_hir_typeck/src/autoderef.rs
+++ b/compiler/rustc_hir_typeck/src/autoderef.rs
@@ -2,11 +2,11 @@
 use super::method::MethodCallee;
 use super::{FnCtxt, PlaceOp};
 
+use rustc_hir_analysis::autoderef::{Autoderef, AutoderefKind};
 use rustc_infer::infer::InferOk;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
 use rustc_middle::ty::{self, Ty};
 use rustc_span::Span;
-use rustc_trait_selection::autoderef::{Autoderef, AutoderefKind};
 
 use std::iter;
 
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 3b664363d23..8d417290407 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -8,6 +8,7 @@ use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed,
 use rustc_hir as hir;
 use rustc_hir::def::{self, CtorKind, Namespace, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::{
     infer,
     traits::{self, Obligation},
@@ -25,7 +26,6 @@ use rustc_span::def_id::LocalDefId;
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
 use rustc_target::spec::abi;
-use rustc_trait_selection::autoderef::Autoderef;
 use rustc_trait_selection::infer::InferCtxtExt as _;
 use rustc_trait_selection::traits::error_reporting::DefIdOrName;
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index a0e086bc261..7e1c0faa453 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -1807,7 +1807,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
             // Get the return type.
             && let hir::TyKind::OpaqueDef(..) = ty.kind
         {
-            let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty);
+            let ty = fcx.astconv().ast_ty_to_ty( ty);
             // Get the `impl Trait`'s `DefId`.
             if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind()
                 // Get the `impl Trait`'s `Item` so that we can get its trait bounds and
@@ -1866,7 +1866,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
     fn is_return_ty_unsized<'a>(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool {
         if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id)
             && let hir::FnRetTy::Return(ty) = fn_decl.output
-            && let ty = <dyn AstConv<'_>>::ast_ty_to_ty(fcx, ty)
+            && let ty = fcx.astconv().ast_ty_to_ty( ty)
             && let ty::Dynamic(..) = ty.kind()
         {
             return true;
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index 47c4b7d7431..8570715b41e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -10,6 +10,9 @@ use rustc_hir::def::{CtorOf, DefKind, Res};
 use rustc_hir::def_id::DefId;
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{ExprKind, GenericArg, Node, QPath};
+use rustc_hir_analysis::astconv::generics::{
+    check_generic_arg_count_for_call, create_substs_for_generic_args,
+};
 use rustc_hir_analysis::astconv::{
     AstConv, CreateSubstsForGenericArgsCtxt, ExplicitLateBound, GenericArgCountMismatch,
     GenericArgCountResult, IsMethodCall, PathSeg,
@@ -374,7 +377,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
     }
 
     pub fn to_ty(&self, ast_t: &hir::Ty<'_>) -> RawTy<'tcx> {
-        let t = <dyn AstConv<'_>>::ast_ty_to_ty(self, ast_t);
+        let t = self.astconv().ast_ty_to_ty(ast_t);
         self.register_wf_obligation(t.into(), ast_t.span, traits::WellFormed(None));
         self.handle_raw_ty(ast_t.span, t)
     }
@@ -777,7 +780,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // to be object-safe.
                 // We manually call `register_wf_obligation` in the success path
                 // below.
-                let ty = <dyn AstConv<'_>>::ast_ty_to_ty_in_path(self, qself);
+                let ty = self.astconv().ast_ty_to_ty_in_path(qself);
                 (self.handle_raw_ty(span, ty), qself, segment)
             }
             QPath::LangItem(..) => {
@@ -975,8 +978,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
         let path_segs = match res {
             Res::Local(_) | Res::SelfCtor(_) => vec![],
-            Res::Def(kind, def_id) => <dyn AstConv<'_>>::def_ids_for_value_path_segments(
-                self,
+            Res::Def(kind, def_id) => self.astconv().def_ids_for_value_path_segments(
                 segments,
                 self_ty.map(|ty| ty.raw),
                 kind,
@@ -1027,8 +1029,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // errors if type parameters are provided in an inappropriate place.
 
         let generic_segs: FxHashSet<_> = path_segs.iter().map(|PathSeg(_, index)| index).collect();
-        let generics_has_err = <dyn AstConv<'_>>::prohibit_generics(
-            self,
+        let generics_has_err = self.astconv().prohibit_generics(
             segments.iter().enumerate().filter_map(|(index, seg)| {
                 if !generic_segs.contains(&index) || is_alias_variant_ctor {
                     Some(seg)
@@ -1069,7 +1070,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // parameter internally, but we don't allow users to specify the
             // parameter's value explicitly, so we have to do some error-
             // checking here.
-            let arg_count = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+            let arg_count = check_generic_arg_count_for_call(
                 tcx,
                 span,
                 def_id,
@@ -1177,7 +1178,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             ) -> ty::GenericArg<'tcx> {
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        <dyn AstConv<'_>>::ast_region_to_region(self.fcx, lt, Some(param)).into()
+                        self.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                         self.fcx.to_ty(ty).raw.into()
@@ -1235,7 +1236,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         let substs_raw = self_ctor_substs.unwrap_or_else(|| {
-            <dyn AstConv<'_>>::create_substs_for_generic_args(
+            create_substs_for_generic_args(
                 tcx,
                 def_id,
                 &[],
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 5075d9b893b..b9e13fd2009 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -1664,15 +1664,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         match *qpath {
             QPath::Resolved(ref maybe_qself, ref path) => {
                 let self_ty = maybe_qself.as_ref().map(|qself| self.to_ty(qself).raw);
-                let ty = <dyn AstConv<'_>>::res_to_ty(self, self_ty, path, true);
+                let ty = self.astconv().res_to_ty(self_ty, path, true);
                 (path.res, self.handle_raw_ty(path_span, ty))
             }
             QPath::TypeRelative(ref qself, ref segment) => {
                 let ty = self.to_ty(qself);
 
-                let result = <dyn AstConv<'_>>::associated_path_to_ty(
-                    self, hir_id, path_span, ty.raw, qself, segment, true,
-                );
+                let result = self
+                    .astconv()
+                    .associated_path_to_ty(hir_id, path_span, ty.raw, qself, segment, true);
                 let ty = result.map(|(ty, _, _)| ty).unwrap_or_else(|_| self.tcx().ty_error());
                 let ty = self.handle_raw_ty(path_span, ty);
                 let result = result.map(|(_, kind, def_id)| (kind, def_id));
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index 6347b9a69a0..428fde642bc 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -20,7 +20,7 @@ use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitable};
 use rustc_session::Session;
 use rustc_span::symbol::Ident;
-use rustc_span::{self, Span};
+use rustc_span::{self, Span, DUMMY_SP};
 use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode, ObligationCtxt};
 
 use std::cell::{Cell, RefCell};
@@ -175,6 +175,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     fn_sig
                 })
             }),
+            autoderef_steps: Box::new(|ty| {
+                let mut autoderef = self.autoderef(DUMMY_SP, ty).silence_errors();
+                let mut steps = vec![];
+                while let Some((ty, _)) = autoderef.next() {
+                    steps.push((ty, autoderef.current_obligations()));
+                }
+                steps
+            }),
         }
     }
 
@@ -286,8 +294,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
             poly_trait_ref,
         );
 
-        let item_substs = <dyn AstConv<'tcx>>::create_substs_for_associated_item(
-            self,
+        let item_substs = self.astconv().create_substs_for_associated_item(
             span,
             item_def_id,
             item_segment,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 91498265259..005bd164065 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -5,7 +5,7 @@ use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
 use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
 use rustc_errors::{Applicability, Diagnostic, MultiSpan};
 use rustc_hir as hir;
-use rustc_hir::def::{CtorOf, DefKind};
+use rustc_hir::def::{CtorKind, CtorOf, DefKind};
 use rustc_hir::lang_items::LangItem;
 use rustc_hir::{
     Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
@@ -417,10 +417,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         } else if self.suggest_else_fn_with_closure(err, expr, found, expected) {
             return true;
         } else if self.suggest_fn_call(err, expr, found, |output| self.can_coerce(output, expected))
-            && let ty::FnDef(def_id, ..) = &found.kind()
-            && let Some(sp) = self.tcx.hir().span_if_local(*def_id)
+            && let ty::FnDef(def_id, ..) = *found.kind()
+            && let Some(sp) = self.tcx.hir().span_if_local(def_id)
         {
-            err.span_label(sp, format!("{found} defined here"));
+            let name = self.tcx.item_name(def_id);
+            let kind = self.tcx.def_kind(def_id);
+            if let DefKind::Ctor(of, CtorKind::Fn) = kind {
+                err.span_label(sp, format!("`{name}` defines {} constructor here, which should be called", match of {
+                    CtorOf::Struct => "a struct",
+                    CtorOf::Variant => "an enum variant",
+                }));
+            } else {
+                let descr = kind.descr(def_id);
+                err.span_label(sp, format!("{descr} `{name}` defined here"));
+            }
             return true;
         } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
             return true;
@@ -783,7 +793,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // are not, the expectation must have been caused by something else.
                 debug!("suggest_missing_return_type: return type {:?} node {:?}", ty, ty.kind);
                 let span = ty.span;
-                let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
+                let ty = self.astconv().ast_ty_to_ty(ty);
                 debug!("suggest_missing_return_type: return type {:?}", ty);
                 debug!("suggest_missing_return_type: expected type {:?}", ty);
                 let bound_vars = self.tcx.late_bound_vars(fn_id);
@@ -854,7 +864,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     ..
                 }) => {
                     // FIXME: Maybe these calls to `ast_ty_to_ty` can be removed (and the ones below)
-                    let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, bounded_ty);
+                    let ty = self.astconv().ast_ty_to_ty(bounded_ty);
                     Some((ty, bounds))
                 }
                 _ => None,
@@ -892,7 +902,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         let all_bounds_str = all_matching_bounds_strs.join(" + ");
 
         let ty_param_used_in_fn_params = fn_parameters.iter().any(|param| {
-                let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, param);
+                let ty = self.astconv().ast_ty_to_ty( param);
                 matches!(ty.kind(), ty::Param(fn_param_ty_param) if expected_ty_as_param == fn_param_ty_param)
             });
 
@@ -946,7 +956,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         }
 
         if let hir::FnRetTy::Return(ty) = fn_decl.output {
-            let ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
+            let ty = self.astconv().ast_ty_to_ty(ty);
             let bound_vars = self.tcx.late_bound_vars(fn_id);
             let ty = self.tcx.erase_late_bound_regions(Binder::bind_with_vars(ty, bound_vars));
             let ty = match self.tcx.asyncness(fn_id.owner) {
@@ -1339,7 +1349,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 hir::Path { segments: [segment], .. },
             ))
             | hir::ExprKind::Path(QPath::TypeRelative(ty, segment)) => {
-                let self_ty = <dyn AstConv<'_>>::ast_ty_to_ty(self, ty);
+                let self_ty = self.astconv().ast_ty_to_ty(ty);
                 if let Ok(pick) = self.probe_for_name(
                     Mode::Path,
                     Ident::new(capitalized_name, segment.ident.span),
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 69929589541..7ddf9eaa4d8 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -205,7 +205,7 @@ fn typeck_with_fallback<'tcx>(
 
         if let Some(hir::FnSig { header, decl, .. }) = fn_sig {
             let fn_sig = if rustc_hir_analysis::collect::get_infer_ret_ty(&decl.output).is_some() {
-                <dyn AstConv<'_>>::ty_of_fn(&fcx, id, header.unsafety, header.abi, decl, None, None)
+                fcx.astconv().ty_of_fn(id, header.unsafety, header.abi, decl, None, None)
             } else {
                 tcx.fn_sig(def_id)
             };
@@ -220,7 +220,7 @@ fn typeck_with_fallback<'tcx>(
         } else {
             let expected_type = body_ty
                 .and_then(|ty| match ty.kind {
-                    hir::TyKind::Infer => Some(<dyn AstConv<'_>>::ast_ty_to_ty(&fcx, ty)),
+                    hir::TyKind::Infer => Some(fcx.astconv().ast_ty_to_ty(ty)),
                     _ => None,
                 })
                 .unwrap_or_else(|| match tcx.hir().get(id) {
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 7d2ba1fd09d..4a33a791e1b 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -4,6 +4,9 @@ use crate::{callee, FnCtxt};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::GenericArg;
+use rustc_hir_analysis::astconv::generics::{
+    check_generic_arg_count_for_call, create_substs_for_generic_args,
+};
 use rustc_hir_analysis::astconv::{AstConv, CreateSubstsForGenericArgsCtxt, IsMethodCall};
 use rustc_infer::infer::{self, InferOk};
 use rustc_middle::traits::{ObligationCauseCode, UnifyReceiverContext};
@@ -331,7 +334,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
         // variables.
         let generics = self.tcx.generics_of(pick.item.def_id);
 
-        let arg_count_correct = <dyn AstConv<'_>>::check_generic_arg_count_for_call(
+        let arg_count_correct = check_generic_arg_count_for_call(
             self.tcx,
             self.span,
             pick.item.def_id,
@@ -369,8 +372,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             ) -> subst::GenericArg<'tcx> {
                 match (&param.kind, arg) {
                     (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => {
-                        <dyn AstConv<'_>>::ast_region_to_region(self.cfcx.fcx, lt, Some(param))
-                            .into()
+                        self.cfcx.fcx.astconv().ast_region_to_region(lt, Some(param)).into()
                     }
                     (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => {
                         self.cfcx.to_ty(ty).raw.into()
@@ -399,7 +401,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
             }
         }
 
-        let substs = <dyn AstConv<'_>>::create_substs_for_generic_args(
+        let substs = create_substs_for_generic_args(
             self.tcx,
             pick.item.def_id,
             parent_substs,
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 63067deb7b0..dd827777df9 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -9,6 +9,7 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
 use rustc_hir::def::DefKind;
+use rustc_hir_analysis::autoderef::{self, Autoderef};
 use rustc_infer::infer::canonical::OriginalQueryValues;
 use rustc_infer::infer::canonical::{Canonical, QueryResponse};
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
@@ -29,7 +30,6 @@ use rustc_span::lev_distance::{
 };
 use rustc_span::symbol::sym;
 use rustc_span::{symbol::Ident, Span, Symbol, DUMMY_SP};
-use rustc_trait_selection::autoderef::{self, Autoderef};
 use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt;
 use rustc_trait_selection::traits::query::method_autoderef::MethodAutoderefBadTy;
 use rustc_trait_selection::traits::query::method_autoderef::{
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index a0f048fc09b..ae0df5aa8f1 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -3,6 +3,7 @@ use crate::{has_expected_num_generic_args, FnCtxt, PlaceOp};
 use rustc_ast as ast;
 use rustc_errors::Applicability;
 use rustc_hir as hir;
+use rustc_hir_analysis::autoderef::Autoderef;
 use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
 use rustc_infer::infer::InferOk;
 use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref, PointerCast};
@@ -10,7 +11,6 @@ use rustc_middle::ty::adjustment::{AllowTwoPhase, AutoBorrow, AutoBorrowMutabili
 use rustc_middle::ty::{self, Ty};
 use rustc_span::symbol::{sym, Ident};
 use rustc_span::Span;
-use rustc_trait_selection::autoderef::Autoderef;
 use std::slice;
 
 impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 9747f360eca..080ae6b9466 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -55,6 +55,7 @@ use crate::infer::ExpectedFound;
 use crate::traits::error_reporting::report_object_safety_error;
 use crate::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
+    PredicateObligation,
 };
 
 use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
@@ -91,8 +92,12 @@ pub mod nice_region_error;
 pub struct TypeErrCtxt<'a, 'tcx> {
     pub infcx: &'a InferCtxt<'tcx>,
     pub typeck_results: Option<std::cell::Ref<'a, ty::TypeckResults<'tcx>>>,
-    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
     pub fallback_has_occurred: bool,
+
+    pub normalize_fn_sig: Box<dyn Fn(ty::PolyFnSig<'tcx>) -> ty::PolyFnSig<'tcx> + 'a>,
+
+    pub autoderef_steps:
+        Box<dyn Fn(Ty<'tcx>) -> Vec<(Ty<'tcx>, Vec<PredicateObligation<'tcx>>)> + 'a>,
 }
 
 impl TypeErrCtxt<'_, '_> {
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 6bef3f000a5..8825b5e12c3 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -688,6 +688,10 @@ impl<'tcx> InferCtxt<'tcx> {
             typeck_results: None,
             fallback_has_occurred: false,
             normalize_fn_sig: Box::new(|fn_sig| fn_sig),
+            autoderef_steps: Box::new(|ty| {
+                debug_assert!(false, "shouldn't be using autoderef_steps outside of typeck");
+                vec![(ty, vec![])]
+            }),
         }
     }
 
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index ac903010c8d..5f320708c84 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -9,6 +9,7 @@
 //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/thir.html
 
 use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
+use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
 use rustc_hir as hir;
 use rustc_hir::def_id::DefId;
 use rustc_hir::RangeEnd;
@@ -575,6 +576,12 @@ impl<'tcx> Pat<'tcx> {
     }
 }
 
+impl<'tcx> IntoDiagnosticArg for Pat<'tcx> {
+    fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
+        format!("{}", self).into_diagnostic_arg()
+    }
+}
+
 #[derive(Clone, Debug, HashStable)]
 pub struct Ascription<'tcx> {
     pub annotation: CanonicalUserTypeAnnotation<'tcx>,
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index 50554cf9a82..5d394f71f0d 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -2,10 +2,10 @@ use crate::traits::{ObligationCause, ObligationCauseCode};
 use crate::ty::diagnostics::suggest_constraining_type_param;
 use crate::ty::print::{with_forced_trimmed_paths, FmtPrinter, Printer};
 use crate::ty::{self, BoundRegionKind, Region, Ty, TyCtxt};
-use hir::def::DefKind;
 use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
 use rustc_errors::{pluralize, Diagnostic, MultiSpan};
 use rustc_hir as hir;
+use rustc_hir::def::{CtorOf, DefKind};
 use rustc_hir::def_id::DefId;
 use rustc_span::symbol::{sym, Symbol};
 use rustc_span::{BytePos, Span};
@@ -319,7 +319,11 @@ impl<'tcx> Ty<'tcx> {
                     .into()
                 }
             }
-            ty::FnDef(..) => "fn item".into(),
+            ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
+                DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
+                DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
+                _ => "fn item".into(),
+            },
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(ref inner, ..) if let Some(principal) = inner.principal() => {
                 format!("trait object `dyn {}`", tcx.def_path_str(principal.def_id())).into()
@@ -366,7 +370,11 @@ impl<'tcx> Ty<'tcx> {
                 _ => "reference",
             }
             .into(),
-            ty::FnDef(..) => "fn item".into(),
+            ty::FnDef(def_id, ..) => match tcx.def_kind(def_id) {
+                DefKind::Ctor(CtorOf::Struct, _) => "struct constructor".into(),
+                DefKind::Ctor(CtorOf::Variant, _) => "enum constructor".into(),
+                _ => "fn item".into(),
+            },
             ty::FnPtr(_) => "fn pointer".into(),
             ty::Dynamic(..) => "trait object".into(),
             ty::Closure(..) => "closure".into(),
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 233eecbd5b4..06523b0a1de 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -1,9 +1,13 @@
+use crate::thir::pattern::deconstruct_pat::DeconstructedPat;
 use crate::thir::pattern::MatchCheckCtxt;
 use rustc_errors::Handler;
 use rustc_errors::{
-    error_code, Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+    error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    IntoDiagnostic, MultiSpan, SubdiagnosticMessage,
 };
+use rustc_hir::def::Res;
 use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::thir::Pat;
 use rustc_middle::ty::{self, Ty};
 use rustc_span::{symbol::Ident, Span};
 
@@ -624,3 +628,223 @@ pub enum MultipleMutBorrowOccurence {
         name_moved: Ident,
     },
 }
+
+#[derive(Diagnostic)]
+#[diag(mir_build_union_pattern)]
+pub struct UnionPattern {
+    #[primary_span]
+    pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_type_not_structural)]
+pub struct TypeNotStructural<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub non_sm_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_invalid_pattern)]
+pub struct InvalidPattern<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub non_sm_ty: Ty<'tcx>,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_unsized_pattern)]
+pub struct UnsizedPattern<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub non_sm_ty: Ty<'tcx>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_float_pattern)]
+pub struct FloatPattern;
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_pointer_pattern)]
+pub struct PointerPattern;
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_indirect_structural_match)]
+pub struct IndirectStructuralMatch<'tcx> {
+    pub non_sm_ty: Ty<'tcx>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_nontrivial_structural_match)]
+pub struct NontrivialStructuralMatch<'tcx> {
+    pub non_sm_ty: Ty<'tcx>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_overlapping_range_endpoints)]
+#[note]
+pub struct OverlappingRangeEndpoints<'tcx> {
+    #[label(range)]
+    pub range: Span,
+    #[subdiagnostic]
+    pub overlap: Vec<Overlap<'tcx>>,
+}
+
+pub struct Overlap<'tcx> {
+    pub span: Span,
+    pub range: Pat<'tcx>,
+}
+
+impl<'tcx> AddToDiagnostic for Overlap<'tcx> {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        let Overlap { span, range } = self;
+
+        // FIXME(mejrs) unfortunately `#[derive(LintDiagnostic)]`
+        // does not support `#[subdiagnostic(eager)]`...
+        let message = format!("this range overlaps on `{range}`...");
+        diag.span_label(span, message);
+    }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_build_non_exhaustive_omitted_pattern)]
+#[help]
+#[note]
+pub(crate) struct NonExhaustiveOmittedPattern<'tcx> {
+    pub scrut_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub uncovered: Uncovered<'tcx>,
+}
+
+#[derive(Subdiagnostic)]
+#[label(mir_build_uncovered)]
+pub(crate) struct Uncovered<'tcx> {
+    #[primary_span]
+    span: Span,
+    count: usize,
+    witness_1: Pat<'tcx>,
+    witness_2: Pat<'tcx>,
+    witness_3: Pat<'tcx>,
+    remainder: usize,
+}
+
+impl<'tcx> Uncovered<'tcx> {
+    pub fn new<'p>(
+        span: Span,
+        cx: &MatchCheckCtxt<'p, 'tcx>,
+        witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
+    ) -> Self {
+        let witness_1 = witnesses.get(0).unwrap().to_pat(cx);
+        Self {
+            span,
+            count: witnesses.len(),
+            // Substitute dummy values if witnesses is smaller than 3. These will never be read.
+            witness_2: witnesses.get(1).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
+            witness_3: witnesses.get(2).map(|w| w.to_pat(cx)).unwrap_or_else(|| witness_1.clone()),
+            witness_1,
+            remainder: witnesses.len().saturating_sub(3),
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_build_pattern_not_covered, code = "E0005")]
+pub(crate) struct PatternNotCovered<'s, 'tcx> {
+    #[primary_span]
+    pub span: Span,
+    pub origin: &'s str,
+    #[subdiagnostic]
+    pub uncovered: Uncovered<'tcx>,
+    #[subdiagnostic]
+    pub inform: Option<Inform>,
+    #[subdiagnostic]
+    pub interpreted_as_const: Option<InterpretedAsConst>,
+    #[subdiagnostic]
+    pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
+    #[note(pattern_ty)]
+    pub _p: (),
+    pub pattern_ty: Ty<'tcx>,
+    #[subdiagnostic]
+    pub let_suggestion: Option<SuggestLet>,
+    #[subdiagnostic]
+    pub res_defined_here: Option<ResDefinedHere>,
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_build_inform_irrefutable)]
+#[note(mir_build_more_information)]
+pub struct Inform;
+
+pub struct AdtDefinedHere<'tcx> {
+    pub adt_def_span: Span,
+    pub ty: Ty<'tcx>,
+    pub variants: Vec<Variant>,
+}
+
+pub struct Variant {
+    pub span: Span,
+}
+
+impl<'tcx> AddToDiagnostic for AdtDefinedHere<'tcx> {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        diag.set_arg("ty", self.ty);
+        let mut spans = MultiSpan::from(self.adt_def_span);
+
+        for Variant { span } in self.variants {
+            spans.push_span_label(span, rustc_errors::fluent::mir_build_variant_defined_here);
+        }
+
+        diag.span_note(spans, rustc_errors::fluent::mir_build_adt_defined_here);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[label(mir_build_res_defined_here)]
+pub struct ResDefinedHere {
+    #[primary_span]
+    pub def_span: Span,
+    pub res: Res,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+    mir_build_interpreted_as_const,
+    code = "{variable}_var",
+    applicability = "maybe-incorrect"
+)]
+#[label(mir_build_confused)]
+pub struct InterpretedAsConst {
+    #[primary_span]
+    pub span: Span,
+    pub article: &'static str,
+    pub variable: String,
+    pub res: Res,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestLet {
+    #[multipart_suggestion(mir_build_suggest_if_let, applicability = "has-placeholders")]
+    If {
+        #[suggestion_part(code = "if ")]
+        start_span: Span,
+        #[suggestion_part(code = " {{ todo!() }}")]
+        semi_span: Span,
+        count: usize,
+    },
+    #[suggestion(
+        mir_build_suggest_let_else,
+        code = " else {{ todo!() }}",
+        applicability = "has-placeholders"
+    )]
+    Else {
+        #[primary_span]
+        end_span: Span,
+        count: usize,
+    },
+}
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 2b05e92fdcf..fb7ae6f1d24 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -10,6 +10,7 @@
 #![feature(let_chains)]
 #![feature(min_specialization)]
 #![feature(once_cell)]
+#![feature(try_blocks)]
 #![recursion_limit = "256"]
 
 #[macro_use]
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index e7ee0d9e908..e13c0662ef8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -9,8 +9,7 @@ use crate::errors::*;
 use rustc_arena::TypedArena;
 use rustc_ast::Mutability;
 use rustc_errors::{
-    pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-    MultiSpan,
+    struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
 };
 use rustc_hir as hir;
 use rustc_hir::def::*;
@@ -378,8 +377,8 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
 
         let pattern = self.lower_pattern(&mut cx, pat, &mut false);
         let pattern_ty = pattern.ty();
-        let arms = vec![MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false }];
-        let report = compute_match_usefulness(&cx, &arms, pat.hir_id, pattern_ty);
+        let arm = MatchArm { pat: pattern, hir_id: pat.hir_id, has_guard: false };
+        let report = compute_match_usefulness(&cx, &[arm], pat.hir_id, pattern_ty);
 
         // Note: we ignore whether the pattern is unreachable (i.e. whether the type is empty). We
         // only care about exhaustiveness here.
@@ -390,145 +389,73 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
             return;
         }
 
-        let joined_patterns = joined_uncovered_patterns(&cx, &witnesses);
-
-        let mut bindings = vec![];
-
-        let mut err = struct_span_err!(
-            self.tcx.sess,
-            pat.span,
-            E0005,
-            "refutable pattern in {}: {} not covered",
-            origin,
-            joined_patterns
-        );
-        let suggest_if_let = match &pat.kind {
-            hir::PatKind::Path(hir::QPath::Resolved(None, path))
-                if path.segments.len() == 1 && path.segments[0].args.is_none() =>
+        let (inform, interpreted_as_const, res_defined_here,let_suggestion) =
+            if let hir::PatKind::Path(hir::QPath::Resolved(
+                None,
+                hir::Path {
+                    segments: &[hir::PathSegment { args: None, res, ident, .. }],
+                    ..
+                },
+            )) = &pat.kind
             {
-                const_not_var(&mut err, cx.tcx, pat, path);
-                false
-            }
-            _ => {
-                pat.walk(&mut |pat: &hir::Pat<'_>| {
-                    match pat.kind {
-                        hir::PatKind::Binding(_, _, ident, _) => {
-                            bindings.push(ident);
+                (
+                    None,
+                    Some(InterpretedAsConst {
+                        span: pat.span,
+                        article: res.article(),
+                        variable: ident.to_string().to_lowercase(),
+                        res,
+                    }),
+                    try {
+                        ResDefinedHere {
+                            def_span: cx.tcx.hir().res_span(res)?,
+                            res,
                         }
-                        _ => {}
+                    },
+                    None,
+                )
+            } else if let Some(span) = sp && self.tcx.sess.source_map().is_span_accessible(span) {
+                let mut bindings = vec![];
+                pat.walk_always(&mut |pat: &hir::Pat<'_>| {
+                    if let hir::PatKind::Binding(_, _, ident, _) = pat.kind {
+                        bindings.push(ident);
                     }
-                    true
                 });
-
-                err.span_label(pat.span, pattern_not_covered_label(&witnesses, &joined_patterns));
-                true
-            }
-        };
-
-        if let (Some(span), true) = (sp, suggest_if_let) {
-            err.note(
-                "`let` bindings require an \"irrefutable pattern\", like a `struct` or \
-                 an `enum` with only one variant",
-            );
-            if self.tcx.sess.source_map().is_span_accessible(span) {
                 let semi_span = span.shrink_to_hi().with_lo(span.hi() - BytePos(1));
                 let start_span = span.shrink_to_lo();
                 let end_span = semi_span.shrink_to_lo();
-                err.multipart_suggestion(
-                    &format!(
-                        "you might want to use `if let` to ignore the variant{} that {} matched",
-                        pluralize!(witnesses.len()),
-                        match witnesses.len() {
-                            1 => "isn't",
-                            _ => "aren't",
-                        },
-                    ),
-                    vec![
-                        match &bindings[..] {
-                            [] => (start_span, "if ".to_string()),
-                            [binding] => (start_span, format!("let {} = if ", binding)),
-                            bindings => (
-                                start_span,
-                                format!(
-                                    "let ({}) = if ",
-                                    bindings
-                                        .iter()
-                                        .map(|ident| ident.to_string())
-                                        .collect::<Vec<_>>()
-                                        .join(", ")
-                                ),
-                            ),
-                        },
-                        match &bindings[..] {
-                            [] => (semi_span, " { todo!() }".to_string()),
-                            [binding] => {
-                                (end_span, format!(" {{ {} }} else {{ todo!() }}", binding))
-                            }
-                            bindings => (
-                                end_span,
-                                format!(
-                                    " {{ ({}) }} else {{ todo!() }}",
-                                    bindings
-                                        .iter()
-                                        .map(|ident| ident.to_string())
-                                        .collect::<Vec<_>>()
-                                        .join(", ")
-                                ),
-                            ),
-                        },
-                    ],
-                    Applicability::HasPlaceholders,
-                );
-                if !bindings.is_empty() {
-                    err.span_suggestion_verbose(
-                        semi_span.shrink_to_lo(),
-                        &format!(
-                            "alternatively, you might want to use \
-                             let else to handle the variant{} that {} matched",
-                            pluralize!(witnesses.len()),
-                            match witnesses.len() {
-                                1 => "isn't",
-                                _ => "aren't",
-                            },
-                        ),
-                        " else { todo!() }",
-                        Applicability::HasPlaceholders,
-                    );
-                }
-            }
-            err.note(
-                "for more information, visit \
-                 https://doc.rust-lang.org/book/ch18-02-refutability.html",
-            );
-        }
+                let count = witnesses.len();
 
-        adt_defined_here(&cx, &mut err, pattern_ty, &witnesses);
-        err.note(&format!("the matched value is of type `{}`", pattern_ty));
-        err.emit();
-    }
-}
+                let let_suggestion = if bindings.is_empty() {SuggestLet::If{start_span, semi_span, count}} else{ SuggestLet::Else{end_span, count }};
+                (sp.map(|_|Inform), None, None, Some(let_suggestion))
+            } else{
+                (sp.map(|_|Inform), None, None,  None)
+            };
 
-/// A path pattern was interpreted as a constant, not a new variable.
-/// This caused an irrefutable match failure in e.g. `let`.
-fn const_not_var(err: &mut Diagnostic, tcx: TyCtxt<'_>, pat: &Pat<'_>, path: &hir::Path<'_>) {
-    let descr = path.res.descr();
-    err.span_label(
-        pat.span,
-        format!("interpreted as {} {} pattern, not a new variable", path.res.article(), descr,),
-    );
+        let adt_defined_here = try {
+            let ty = pattern_ty.peel_refs();
+            let ty::Adt(def, _) = ty.kind() else { None? };
+            let adt_def_span = cx.tcx.hir().get_if_local(def.did())?.ident()?.span;
+            let mut variants = vec![];
 
-    err.span_suggestion(
-        pat.span,
-        "introduce a variable instead",
-        format!("{}_var", path.segments[0].ident).to_lowercase(),
-        // Cannot use `MachineApplicable` as it's not really *always* correct
-        // because there may be such an identifier in scope or the user maybe
-        // really wanted to match against the constant. This is quite unlikely however.
-        Applicability::MaybeIncorrect,
-    );
+            for span in maybe_point_at_variant(&cx, *def, witnesses.iter().take(5)) {
+                variants.push(Variant { span });
+            }
+            AdtDefinedHere { adt_def_span, ty, variants }
+        };
 
-    if let Some(span) = tcx.hir().res_span(path.res) {
-        err.span_label(span, format!("{} defined here", descr));
+        self.tcx.sess.emit_err(PatternNotCovered {
+            span: pat.span,
+            origin,
+            uncovered: Uncovered::new(pat.span, &cx, witnesses),
+            inform,
+            interpreted_as_const,
+            _p: (),
+            pattern_ty,
+            let_suggestion,
+            res_defined_here,
+            adt_defined_here,
+        });
     }
 }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 6470efab2e9..7f3519945c3 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,11 +1,9 @@
-use rustc_errors::DelayDm;
 use rustc_hir as hir;
 use rustc_index::vec::Idx;
 use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
 use rustc_middle::mir::{self, Field};
 use rustc_middle::thir::{FieldPat, Pat, PatKind};
-use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_session::lint;
 use rustc_span::Span;
 use rustc_trait_selection::traits::predicate_for_trait_def;
@@ -15,6 +13,10 @@ use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation};
 use std::cell::Cell;
 
 use super::PatCtxt;
+use crate::errors::{
+    FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
+    PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
+};
 
 impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
     /// Converts an evaluated constant to a pattern (if possible).
@@ -105,47 +107,6 @@ impl<'tcx> ConstToPat<'tcx> {
         self.infcx.tcx
     }
 
-    fn adt_derive_msg(&self, adt_def: AdtDef<'tcx>) -> String {
-        let path = self.tcx().def_path_str(adt_def.did());
-        format!(
-            "to use a constant of type `{}` in a pattern, \
-            `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-            path, path,
-        )
-    }
-
-    fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option<String> {
-        traits::search_for_structural_match_violation(self.span, self.tcx(), ty).map(|non_sm_ty| {
-            with_no_trimmed_paths!(match non_sm_ty.kind() {
-                ty::Adt(adt, _) => self.adt_derive_msg(*adt),
-                ty::Dynamic(..) => {
-                    "trait objects cannot be used in patterns".to_string()
-                }
-                ty::Alias(ty::Opaque, ..) => {
-                    "opaque types cannot be used in patterns".to_string()
-                }
-                ty::Closure(..) => {
-                    "closures cannot be used in patterns".to_string()
-                }
-                ty::Generator(..) | ty::GeneratorWitness(..) => {
-                    "generators cannot be used in patterns".to_string()
-                }
-                ty::Float(..) => {
-                    "floating-point numbers cannot be used in patterns".to_string()
-                }
-                ty::FnPtr(..) => {
-                    "function pointers cannot be used in patterns".to_string()
-                }
-                ty::RawPtr(..) => {
-                    "raw pointers cannot be used in patterns".to_string()
-                }
-                _ => {
-                    bug!("use of a value of `{non_sm_ty}` inside a pattern")
-                }
-            })
-        })
-    }
-
     fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
         ty.is_structural_eq_shallow(self.infcx.tcx)
     }
@@ -176,7 +137,8 @@ impl<'tcx> ConstToPat<'tcx> {
             // If we were able to successfully convert the const to some pat,
             // double-check that all types in the const implement `Structural`.
 
-            let structural = self.search_for_structural_match_violation(cv.ty());
+            let structural =
+                traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
             debug!(
                 "search_for_structural_match_violation cv.ty: {:?} returned: {:?}",
                 cv.ty(),
@@ -194,17 +156,18 @@ impl<'tcx> ConstToPat<'tcx> {
                 return inlined_const_as_pat;
             }
 
-            if let Some(msg) = structural {
+            if let Some(non_sm_ty) = structural {
                 if !self.type_may_have_partial_eq_impl(cv.ty()) {
-                    // span_fatal avoids ICE from resolution of non-existent method (rare case).
-                    self.tcx().sess.span_fatal(self.span, &msg);
+                    // fatal avoids ICE from resolution of non-existent method (rare case).
+                    self.tcx()
+                        .sess
+                        .emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
                 } else if mir_structural_match_violation && !self.saw_const_match_lint.get() {
-                    self.tcx().struct_span_lint_hir(
+                    self.tcx().emit_spanned_lint(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         self.id,
                         self.span,
-                        msg,
-                        |lint| lint,
+                        IndirectStructuralMatch { non_sm_ty },
                     );
                 } else {
                     debug!(
@@ -278,12 +241,11 @@ impl<'tcx> ConstToPat<'tcx> {
         let kind = match cv.ty().kind() {
             ty::Float(_) => {
                 if self.include_lint_checks {
-                    tcx.struct_span_lint_hir(
+                    tcx.emit_spanned_lint(
                         lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
                         id,
                         span,
-                        "floating-point types cannot be used in patterns",
-                        |lint| lint,
+                        FloatPattern,
                     );
                 }
                 PatKind::Constant { value: cv }
@@ -291,29 +253,22 @@ impl<'tcx> ConstToPat<'tcx> {
             ty::Adt(adt_def, _) if adt_def.is_union() => {
                 // Matching on union fields is unsafe, we can't hide it in constants
                 self.saw_const_match_error.set(true);
-                let msg = "cannot use unions in constant patterns";
-                if self.include_lint_checks {
-                    tcx.sess.span_err(span, msg);
-                } else {
-                    tcx.sess.delay_span_bug(span, msg);
-                }
+                let err = UnionPattern { span };
+                tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                 PatKind::Wild
             }
             ty::Adt(..)
                 if !self.type_may_have_partial_eq_impl(cv.ty())
                     // FIXME(#73448): Find a way to bring const qualification into parity with
                     // `search_for_structural_match_violation` and then remove this condition.
-                    && self.search_for_structural_match_violation(cv.ty()).is_some() =>
+
+                    // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
+                    // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
+                    && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty()) =>
             {
-                // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
-                // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-                let msg = self.search_for_structural_match_violation(cv.ty()).unwrap();
                 self.saw_const_match_error.set(true);
-                if self.include_lint_checks {
-                    tcx.sess.span_err(self.span, &msg);
-                } else {
-                    tcx.sess.delay_span_bug(self.span, &msg);
-                }
+                let err = TypeNotStructural { span, non_sm_ty };
+                tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                 PatKind::Wild
             }
             // If the type is not structurally comparable, just emit the constant directly,
@@ -331,19 +286,11 @@ impl<'tcx> ConstToPat<'tcx> {
                     && !self.saw_const_match_lint.get()
                 {
                     self.saw_const_match_lint.set(true);
-                    tcx.struct_span_lint_hir(
+                    tcx.emit_spanned_lint(
                         lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                         id,
                         span,
-                        DelayDm(|| {
-                            format!(
-                                "to use a constant of type `{}` in a pattern, \
-                                 `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                                cv.ty(),
-                                cv.ty(),
-                            )
-                        }),
-                        |lint| lint,
+                        IndirectStructuralMatch { non_sm_ty: cv.ty() },
                     );
                 }
                 // Since we are behind a reference, we can just bubble the error up so we get a
@@ -357,18 +304,9 @@ impl<'tcx> ConstToPat<'tcx> {
                     adt_def,
                     cv.ty()
                 );
-                let path = tcx.def_path_str(adt_def.did());
-                let msg = format!(
-                    "to use a constant of type `{}` in a pattern, \
-                     `{}` must be annotated with `#[derive(PartialEq, Eq)]`",
-                    path, path,
-                );
                 self.saw_const_match_error.set(true);
-                if self.include_lint_checks {
-                    tcx.sess.span_err(span, &msg);
-                } else {
-                    tcx.sess.delay_span_bug(span, &msg);
-                }
+                let err = TypeNotStructural { span, non_sm_ty: cv.ty() };
+                tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                 PatKind::Wild
             }
             ty::Adt(adt_def, substs) if adt_def.is_enum() => {
@@ -401,12 +339,8 @@ impl<'tcx> ConstToPat<'tcx> {
                 // These are not allowed and will error elsewhere anyway.
                 ty::Dynamic(..) => {
                     self.saw_const_match_error.set(true);
-                    let msg = format!("`{}` cannot be used in patterns", cv.ty());
-                    if self.include_lint_checks {
-                        tcx.sess.span_err(span, &msg);
-                    } else {
-                        tcx.sess.delay_span_bug(span, &msg);
-                    }
+                    let err = InvalidPattern { span, non_sm_ty: cv.ty() };
+                    tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                     PatKind::Wild
                 }
                 // `&str` is represented as `ConstValue::Slice`, let's keep using this
@@ -471,32 +405,26 @@ impl<'tcx> ConstToPat<'tcx> {
                 // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
                 // reference. This makes the rest of the matching logic simpler as it doesn't have
                 // to figure out how to get a reference again.
-                ty::Adt(adt_def, _) if !self.type_marked_structural(*pointee_ty) => {
+                ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
                     if self.behind_reference.get() {
                         if self.include_lint_checks
                             && !self.saw_const_match_error.get()
                             && !self.saw_const_match_lint.get()
                         {
-                            self.saw_const_match_lint.set(true);
-                            let msg = self.adt_derive_msg(adt_def);
-                            self.tcx().struct_span_lint_hir(
+                           self.saw_const_match_lint.set(true);
+                           tcx.emit_spanned_lint(
                                 lint::builtin::INDIRECT_STRUCTURAL_MATCH,
                                 self.id,
-                                self.span,
-                                msg,
-                                |lint| lint,
+                                span,
+                                IndirectStructuralMatch { non_sm_ty: *pointee_ty },
                             );
                         }
                         PatKind::Constant { value: cv }
                     } else {
                         if !self.saw_const_match_error.get() {
                             self.saw_const_match_error.set(true);
-                            let msg = self.adt_derive_msg(adt_def);
-                            if self.include_lint_checks {
-                                tcx.sess.span_err(span, &msg);
-                            } else {
-                                tcx.sess.delay_span_bug(span, &msg);
-                            }
+                            let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
+                            tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                         }
                         PatKind::Wild
                     }
@@ -508,12 +436,10 @@ impl<'tcx> ConstToPat<'tcx> {
                     if !pointee_ty.is_sized(tcx, param_env) {
                         // `tcx.deref_mir_constant()` below will ICE with an unsized type
                         // (except slices, which are handled in a separate arm above).
-                        let msg = format!("cannot use unsized non-slice type `{}` in constant patterns", pointee_ty);
-                        if self.include_lint_checks {
-                            tcx.sess.span_err(span, &msg);
-                        } else {
-                            tcx.sess.delay_span_bug(span, &msg);
-                        }
+
+                        let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
+                        tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
+
                         PatKind::Wild
                     } else {
                         let old = self.behind_reference.replace(true);
@@ -545,27 +471,19 @@ impl<'tcx> ConstToPat<'tcx> {
                     && !self.saw_const_match_lint.get()
                 {
                     self.saw_const_match_lint.set(true);
-                    let msg = "function pointers and unsized pointers in patterns behave \
-                        unpredictably and should not be relied upon. \
-                        See https://github.com/rust-lang/rust/issues/70861 for details.";
-                    tcx.struct_span_lint_hir(
+                    tcx.emit_spanned_lint(
                         lint::builtin::POINTER_STRUCTURAL_MATCH,
                         id,
                         span,
-                        msg,
-                        |lint| lint,
+                        PointerPattern
                     );
                 }
                 PatKind::Constant { value: cv }
             }
             _ => {
                 self.saw_const_match_error.set(true);
-                let msg = format!("`{}` cannot be used in patterns", cv.ty());
-                if self.include_lint_checks {
-                    tcx.sess.span_err(span, &msg);
-                } else {
-                    tcx.sess.delay_span_bug(span, &msg);
-                }
+                let err = InvalidPattern { span, non_sm_ty: cv.ty() };
+                    tcx.sess.create_err(err).emit_unless(!self.include_lint_checks);
                 PatKind::Wild
             }
         };
@@ -576,21 +494,17 @@ impl<'tcx> ConstToPat<'tcx> {
             && mir_structural_match_violation
             // FIXME(#73448): Find a way to bring const qualification into parity with
             // `search_for_structural_match_violation` and then remove this condition.
-            && self.search_for_structural_match_violation(cv.ty()).is_some()
-        {
-            self.saw_const_match_lint.set(true);
+
             // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we
             // could get `Option<NonStructEq>`, even though `Option` is annotated with derive.
-            let msg = self.search_for_structural_match_violation(cv.ty()).unwrap().replace(
-                "in a pattern,",
-                "in a pattern, the constant's initializer must be trivial or",
-            );
-            tcx.struct_span_lint_hir(
+            && let Some(non_sm_ty) = traits::search_for_structural_match_violation(span, tcx, cv.ty())
+        {
+            self.saw_const_match_lint.set(true);
+            tcx.emit_spanned_lint(
                 lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH,
                 id,
                 span,
-                msg,
-                |lint| lint,
+                NontrivialStructuralMatch {non_sm_ty}
             );
         }
 
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index a95349d7670..17b3c475f83 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -67,6 +67,7 @@ use self::SliceKind::*;
 
 use super::compare_const_vals;
 use super::usefulness::{MatchCheckCtxt, PatCtxt};
+use crate::errors::{Overlap, OverlappingRangeEndpoints};
 
 /// Recursively expand this pattern into its subpatterns. Only useful for or-patterns.
 fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
@@ -96,7 +97,7 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> {
 /// `IntRange` is never used to encode an empty range or a "range" that wraps
 /// around the (offset) space: i.e., `range.lo <= range.hi`.
 #[derive(Clone, PartialEq, Eq)]
-pub(super) struct IntRange {
+pub(crate) struct IntRange {
     range: RangeInclusive<u128>,
     /// Keeps the bias used for encoding the range. It depends on the type of the range and
     /// possibly the pointer size of the current architecture. The algorithm ensures we never
@@ -284,32 +285,21 @@ impl IntRange {
             return;
         }
 
-        let overlaps: Vec<_> = pats
+        let overlap: Vec<_> = pats
             .filter_map(|pat| Some((pat.ctor().as_int_range()?, pat.span())))
             .filter(|(range, _)| self.suspicious_intersection(range))
-            .map(|(range, span)| (self.intersection(&range).unwrap(), span))
+            .map(|(range, span)| Overlap {
+                range: self.intersection(&range).unwrap().to_pat(pcx.cx.tcx, pcx.ty),
+                span,
+            })
             .collect();
 
-        if !overlaps.is_empty() {
-            pcx.cx.tcx.struct_span_lint_hir(
+        if !overlap.is_empty() {
+            pcx.cx.tcx.emit_spanned_lint(
                 lint::builtin::OVERLAPPING_RANGE_ENDPOINTS,
                 hir_id,
                 pcx.span,
-                "multiple patterns overlap on their endpoints",
-                |lint| {
-                    for (int_range, span) in overlaps {
-                        lint.span_label(
-                            span,
-                            &format!(
-                                "this range overlaps on `{}`...",
-                                int_range.to_pat(pcx.cx.tcx, pcx.ty)
-                            ),
-                        );
-                    }
-                    lint.span_label(pcx.span, "... with this range");
-                    lint.note("you likely meant to write mutually exclusive ranges");
-                    lint
-                },
+                OverlappingRangeEndpoints { overlap, range: pcx.span },
             );
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 7d4353c5292..3a6ef87c9c6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -2,7 +2,7 @@
 
 mod check_match;
 mod const_to_pat;
-mod deconstruct_pat;
+pub(crate) mod deconstruct_pat;
 mod usefulness;
 
 pub(crate) use self::check_match::check_match;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 8f80cb95e58..be66d0d4765 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -291,9 +291,8 @@
 
 use self::ArmType::*;
 use self::Usefulness::*;
-
-use super::check_match::{joined_uncovered_patterns, pattern_not_covered_label};
 use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard};
+use crate::errors::{NonExhaustiveOmittedPattern, Uncovered};
 
 use rustc_data_structures::captures::Captures;
 
@@ -743,31 +742,6 @@ impl<'p, 'tcx> Witness<'p, 'tcx> {
     }
 }
 
-/// Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
-/// is not exhaustive enough.
-///
-/// NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
-fn lint_non_exhaustive_omitted_patterns<'p, 'tcx>(
-    cx: &MatchCheckCtxt<'p, 'tcx>,
-    scrut_ty: Ty<'tcx>,
-    sp: Span,
-    hir_id: HirId,
-    witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
-) {
-    cx.tcx.struct_span_lint_hir(NON_EXHAUSTIVE_OMITTED_PATTERNS, hir_id, sp, "some variants are not matched explicitly", |lint| {
-        let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
-        lint.span_label(sp, pattern_not_covered_label(&witnesses, &joined_patterns));
-        lint.help(
-            "ensure that all variants are matched explicitly by adding the suggested match arms",
-        );
-        lint.note(&format!(
-            "the matched value is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
-            scrut_ty,
-        ));
-        lint
-    });
-}
-
 /// Algorithm from <http://moscova.inria.fr/~maranget/papers/warn/index.html>.
 /// The algorithm from the paper has been modified to correctly handle empty
 /// types. The changes are:
@@ -913,7 +887,19 @@ fn is_useful<'p, 'tcx>(
                         .collect::<Vec<_>>()
                 };
 
-                lint_non_exhaustive_omitted_patterns(pcx.cx, pcx.ty, pcx.span, hir_id, patterns);
+                // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns`
+                // is not exhaustive enough.
+                //
+                // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`.
+                cx.tcx.emit_spanned_lint(
+                    NON_EXHAUSTIVE_OMITTED_PATTERNS,
+                    hir_id,
+                    pcx.span,
+                    NonExhaustiveOmittedPattern {
+                        scrut_ty: pcx.ty,
+                        uncovered: Uncovered::new(pcx.span, pcx.cx, patterns),
+                    },
+                );
             }
 
             ret.extend(usefulness);
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 19f404cb5b7..4405537c645 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -1,7 +1,6 @@
 use rustc_errors::{fluent, ErrorGuaranteed, Handler, IntoDiagnostic};
 use rustc_macros::Diagnostic;
 use rustc_middle::ty::{self, PolyTraitRef, Ty};
-use rustc_session::Limit;
 use rustc_span::{Span, Symbol};
 
 #[derive(Diagnostic)]
@@ -22,18 +21,6 @@ pub struct UnableToConstructConstantValue<'a> {
 }
 
 #[derive(Diagnostic)]
-#[help]
-#[diag(trait_selection_auto_deref_reached_recursion_limit, code = "E0055")]
-pub struct AutoDerefReachedRecursionLimit<'a> {
-    #[primary_span]
-    #[label]
-    pub span: Span,
-    pub ty: Ty<'a>,
-    pub suggested_limit: Limit,
-    pub crate_name: Symbol,
-}
-
-#[derive(Diagnostic)]
 #[diag(trait_selection_empty_on_clause_in_rustc_on_unimplemented, code = "E0232")]
 pub struct EmptyOnClauseInOnUnimplemented {
     #[primary_span]
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index a30d1df4ede..081ac966c69 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -35,7 +35,6 @@ extern crate rustc_middle;
 #[macro_use]
 extern crate smallvec;
 
-pub mod autoderef;
 pub mod errors;
 pub mod infer;
 pub mod solve;
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index f59a6aa9810..1b98ead29f8 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -5,7 +5,6 @@ use super::{
     PredicateObligation,
 };
 
-use crate::autoderef::Autoderef;
 use crate::infer::InferCtxt;
 use crate::traits::{NormalizeExt, ObligationCtxt};
 
@@ -750,26 +749,30 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
 
             if let ty::Ref(region, base_ty, mutbl) = *real_ty.skip_binder().kind() {
-                let mut autoderef = Autoderef::new(
-                    self,
-                    obligation.param_env,
-                    obligation.cause.body_id,
-                    span,
-                    base_ty,
-                );
-                if let Some(steps) = autoderef.find_map(|(ty, steps)| {
-                    // Re-add the `&`
-                    let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
-
-                    // Remapping bound vars here
-                    let real_trait_pred_and_ty =
-                        real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
-                    let obligation = self.mk_trait_obligation_with_new_self_ty(
-                        obligation.param_env,
-                        real_trait_pred_and_ty,
-                    );
-                    Some(steps).filter(|_| self.predicate_may_hold(&obligation))
-                }) {
+                let autoderef = (self.autoderef_steps)(base_ty);
+                if let Some(steps) =
+                    autoderef.into_iter().enumerate().find_map(|(steps, (ty, obligations))| {
+                        // Re-add the `&`
+                        let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl });
+
+                        // Remapping bound vars here
+                        let real_trait_pred_and_ty =
+                            real_trait_pred.map_bound(|inner_trait_pred| (inner_trait_pred, ty));
+                        let obligation = self.mk_trait_obligation_with_new_self_ty(
+                            obligation.param_env,
+                            real_trait_pred_and_ty,
+                        );
+                        if obligations
+                            .iter()
+                            .chain([&obligation])
+                            .all(|obligation| self.predicate_may_hold(obligation))
+                        {
+                            Some(steps)
+                        } else {
+                            None
+                        }
+                    })
+                {
                     if steps > 0 {
                         // Don't care about `&mut` because `DerefMut` is used less
                         // often and user will not expect autoderef happens.
@@ -1358,57 +1361,117 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err: &mut Diagnostic,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let span = obligation.cause.span;
+        let mut span = obligation.cause.span;
+        let mut trait_pred = trait_pred;
+        let mut code = obligation.cause.code();
+        while let Some((c, Some(parent_trait_pred))) = code.parent() {
+            // We want the root obligation, in order to detect properly handle
+            // `for _ in &mut &mut vec![] {}`.
+            code = c;
+            trait_pred = parent_trait_pred;
+        }
+        while span.desugaring_kind().is_some() {
+            // Remove all the hir desugaring contexts while maintaining the macro contexts.
+            span.remove_mark();
+        }
+        let mut expr_finder = super::FindExprBySpan::new(span);
+        let Some(hir::Node::Expr(body)) = self.tcx.hir().find(obligation.cause.body_id) else {
+            return false;
+        };
+        expr_finder.visit_expr(&body);
+        let mut maybe_suggest = |suggested_ty, count, suggestions| {
+            // Remapping bound vars here
+            let trait_pred_and_suggested_ty =
+                trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+
+            let new_obligation = self.mk_trait_obligation_with_new_self_ty(
+                obligation.param_env,
+                trait_pred_and_suggested_ty,
+            );
 
-        let mut suggested = false;
-        if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
-            let refs_number =
-                snippet.chars().filter(|c| !c.is_whitespace()).take_while(|c| *c == '&').count();
-            if let Some('\'') = snippet.chars().filter(|c| !c.is_whitespace()).nth(refs_number) {
-                // Do not suggest removal of borrow from type arguments.
-                return false;
+            if self.predicate_may_hold(&new_obligation) {
+                let msg = if count == 1 {
+                    "consider removing the leading `&`-reference".to_string()
+                } else {
+                    format!("consider removing {count} leading `&`-references")
+                };
+
+                err.multipart_suggestion_verbose(
+                    &msg,
+                    suggestions,
+                    Applicability::MachineApplicable,
+                );
+                true
+            } else {
+                false
             }
+        };
 
-            // Skipping binder here, remapping below
-            let mut suggested_ty = trait_pred.self_ty().skip_binder();
+        // Maybe suggest removal of borrows from types in type parameters, like in
+        // `src/test/ui/not-panic/not-panic-safe.rs`.
+        let mut count = 0;
+        let mut suggestions = vec![];
+        // Skipping binder here, remapping below
+        let mut suggested_ty = trait_pred.self_ty().skip_binder();
+        if let Some(mut hir_ty) = expr_finder.ty_result {
+            while let hir::TyKind::Ref(_, mut_ty) = &hir_ty.kind {
+                count += 1;
+                let span = hir_ty.span.until(mut_ty.ty.span);
+                suggestions.push((span, String::new()));
 
-            for refs_remaining in 0..refs_number {
                 let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
                     break;
                 };
                 suggested_ty = *inner_ty;
 
-                // Remapping bound vars here
-                let trait_pred_and_suggested_ty =
-                    trait_pred.map_bound(|trait_pred| (trait_pred, suggested_ty));
+                hir_ty = mut_ty.ty;
 
-                let new_obligation = self.mk_trait_obligation_with_new_self_ty(
-                    obligation.param_env,
-                    trait_pred_and_suggested_ty,
-                );
+                if maybe_suggest(suggested_ty, count, suggestions.clone()) {
+                    return true;
+                }
+            }
+        }
 
-                if self.predicate_may_hold(&new_obligation) {
-                    let sp = self
-                        .tcx
-                        .sess
-                        .source_map()
-                        .span_take_while(span, |c| c.is_whitespace() || *c == '&');
+        // Maybe suggest removal of borrows from expressions, like in `for i in &&&foo {}`.
+        let Some(mut expr) = expr_finder.result else { return false; };
+        let mut count = 0;
+        let mut suggestions = vec![];
+        // Skipping binder here, remapping below
+        let mut suggested_ty = trait_pred.self_ty().skip_binder();
+        'outer: loop {
+            while let hir::ExprKind::AddrOf(_, _, borrowed) = expr.kind {
+                count += 1;
+                let span = if expr.span.eq_ctxt(borrowed.span) {
+                    expr.span.until(borrowed.span)
+                } else {
+                    expr.span.with_hi(expr.span.lo() + BytePos(1))
+                };
+                suggestions.push((span, String::new()));
 
-                    let remove_refs = refs_remaining + 1;
+                let ty::Ref(_, inner_ty, _) = suggested_ty.kind() else {
+                    break 'outer;
+                };
+                suggested_ty = *inner_ty;
 
-                    let msg = if remove_refs == 1 {
-                        "consider removing the leading `&`-reference".to_string()
-                    } else {
-                        format!("consider removing {} leading `&`-references", remove_refs)
-                    };
+                expr = borrowed;
 
-                    err.span_suggestion_short(sp, &msg, "", Applicability::MachineApplicable);
-                    suggested = true;
-                    break;
+                if maybe_suggest(suggested_ty, count, suggestions.clone()) {
+                    return true;
                 }
             }
+            if let hir::ExprKind::Path(hir::QPath::Resolved(None, path)) = expr.kind
+                && let hir::def::Res::Local(hir_id) = path.res
+                && let Some(hir::Node::Pat(binding)) = self.tcx.hir().find(hir_id)
+                && let Some(hir::Node::Local(local)) = self.tcx.hir().find_parent(binding.hir_id)
+                && let None = local.ty
+                && let Some(binding_expr) = local.init
+            {
+                expr = binding_expr;
+            } else {
+                break 'outer;
+            }
         }
-        suggested
+        false
     }
 
     fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs
index 9e0d7cab63e..e898bca88e4 100644
--- a/library/core/src/lib.rs
+++ b/library/core/src/lib.rs
@@ -239,7 +239,6 @@
 #![feature(arm_target_feature)]
 #![feature(avx512_target_feature)]
 #![feature(cmpxchg16b_target_feature)]
-#![feature(f16c_target_feature)]
 #![feature(hexagon_target_feature)]
 #![feature(mips_target_feature)]
 #![feature(powerpc_target_feature)]
@@ -248,6 +247,7 @@
 #![feature(sse4a_target_feature)]
 #![feature(tbm_target_feature)]
 #![feature(wasm_target_feature)]
+#![cfg_attr(bootstrap, feature(f16c_target_feature))]
 
 // allow using `core::` in intra-doc links
 #[allow(unused_extern_crates)]
diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs
index 57096f43974..21518a3f551 100644
--- a/library/core/src/num/int_macros.rs
+++ b/library/core/src/num/int_macros.rs
@@ -1514,37 +1514,50 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
-        /// Calculates `self + rhs + carry` without the ability to overflow.
+        /// Calculates `self` + `rhs` + `carry` and checks for overflow.
         ///
-        /// Performs "signed ternary addition" which takes in an extra bit to add, and may return an
-        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
-        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        /// Performs "ternary addition" of two integer operands and a carry-in
+        /// bit, and returns a tuple of the sum along with a boolean indicating
+        /// whether an arithmetic overflow would occur. On overflow, the wrapped
+        /// value is returned.
         ///
-        /// # Examples
+        /// This allows chaining together multiple additions to create a wider
+        /// addition, and can be useful for bignum addition. This method should
+        /// only be used for the most significant word; for the less significant
+        /// words the unsigned method
+        #[doc = concat!("[`", stringify!($UnsignedT), "::carrying_add`]")]
+        /// should be used.
         ///
-        /// Basic usage:
+        /// The output boolean returned by this method is *not* a carry flag,
+        /// and should *not* be added to a more significant word.
         ///
-        /// ```
-        /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, false), (7, false));")]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".carrying_add(2, true), (8, false));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), (", stringify!($SelfT), "::MIN, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(0, true), (", stringify!($SelfT), "::MIN, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, true), (", stringify!($SelfT), "::MIN + 1, true));")]
-        #[doc = concat!("assert_eq!(",
-            stringify!($SelfT), "::MAX.carrying_add(", stringify!($SelfT), "::MAX, true), ",
-            "(-1, true));"
-        )]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.carrying_add(-1, true), (", stringify!($SelfT), "::MIN, false));")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".carrying_add(", stringify!($SelfT), "::MAX, true), (", stringify!($SelfT), "::MIN, true));")]
-        /// ```
+        /// If the input carry is false, this method is equivalent to
+        /// [`overflowing_add`](Self::overflowing_add).
         ///
-        /// If `carry` is false, this method is equivalent to [`overflowing_add`](Self::overflowing_add):
+        /// # Examples
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5_", stringify!($SelfT), ".carrying_add(2, false), 5_", stringify!($SelfT), ".overflowing_add(2));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.carrying_add(1, false), ", stringify!($SelfT), "::MAX.overflowing_add(1));")]
+        /// // Only the  most significant word is signed.
+        /// //
+        #[doc = concat!("//   10  MAX    (a = 10 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+        #[doc = concat!("// + -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
+        /// // ---------
+        #[doc = concat!("//    6    8    (sum = 6 × 2^", stringify!($BITS), " + 8)")]
+        ///
+        #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($UnsignedT), ") = (10, ", stringify!($UnsignedT), "::MAX);")]
+        #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($UnsignedT), ") = (-5, 9);")]
+        /// let carry0 = false;
+        ///
+        #[doc = concat!("// ", stringify!($UnsignedT), "::carrying_add for the less significant words")]
+        /// let (sum0, carry1) = a0.carrying_add(b0, carry0);
+        /// assert_eq!(carry1, true);
+        ///
+        #[doc = concat!("// ", stringify!($SelfT), "::carrying_add for the most significant word")]
+        /// let (sum1, overflow) = a1.carrying_add(b1, carry1);
+        /// assert_eq!(overflow, false);
+        ///
+        /// assert_eq!((sum1, sum0), (6, 8));
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
@@ -1608,25 +1621,51 @@ macro_rules! int_impl {
             (a as Self, b)
         }
 
-        /// Calculates `self - rhs - borrow` without the ability to overflow.
+        /// Calculates `self` &minus; `rhs` &minus; `borrow` and checks for
+        /// overflow.
         ///
-        /// Performs "signed ternary subtraction" which takes in an extra bit to subtract, and may return an
-        /// additional bit of overflow. This signed function is used only on the highest-ordered data,
-        /// for which the signed overflow result indicates whether the big integer overflowed or not.
+        /// Performs "ternary subtraction" by subtracting both an integer
+        /// operandand a borrow-in bit from `self`, and returns a tuple of the
+        /// difference along with a boolean indicating whether an arithmetic
+        /// overflow would occur. On overflow, the wrapped value is returned.
         ///
-        /// # Examples
+        /// This allows chaining together multiple subtractions to create a
+        /// wider subtraction, and can be useful for bignum subtraction. This
+        /// method should only be used for the most significant word; for the
+        /// less significant words the unsigned method
+        #[doc = concat!("[`", stringify!($UnsignedT), "::borrowing_sub`]")]
+        /// should be used.
         ///
-        /// Basic usage:
+        /// The output boolean returned by this method is *not* a borrow flag,
+        /// and should *not* be subtracted from a more significant word.
+        ///
+        /// If the input borrow is false, this method is equivalent to
+        /// [`overflowing_sub`](Self::overflowing_sub).
+        ///
+        /// # Examples
         ///
         /// ```
         /// #![feature(bigint_helper_methods)]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, false), (3, false));")]
-        #[doc = concat!("assert_eq!(5", stringify!($SelfT), ".borrowing_sub(2, true), (2, false));")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, false), (-1, false));")]
-        #[doc = concat!("assert_eq!(0", stringify!($SelfT), ".borrowing_sub(1, true), (-2, false));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MIN.borrowing_sub(1, true), (", stringify!($SelfT), "::MAX - 1, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, false), (", stringify!($SelfT), "::MIN, true));")]
-        #[doc = concat!("assert_eq!(", stringify!($SelfT), "::MAX.borrowing_sub(-1, true), (", stringify!($SelfT), "::MAX, false));")]
+        /// // Only the  most significant word is signed.
+        /// //
+        #[doc = concat!("//    6    8    (a = 6 × 2^", stringify!($BITS), " + 8)")]
+        #[doc = concat!("// - -5    9    (b = -5 × 2^", stringify!($BITS), " + 9)")]
+        /// // ---------
+        #[doc = concat!("//   10  MAX    (diff = 10 × 2^", stringify!($BITS), " + 2^", stringify!($BITS), " - 1)")]
+        ///
+        #[doc = concat!("let (a1, a0): (", stringify!($SelfT), ", ", stringify!($UnsignedT), ") = (6, 8);")]
+        #[doc = concat!("let (b1, b0): (", stringify!($SelfT), ", ", stringify!($UnsignedT), ") = (-5, 9);")]
+        /// let borrow0 = false;
+        ///
+        #[doc = concat!("// ", stringify!($UnsignedT), "::borrowing_sub for the less significant words")]
+        /// let (diff0, borrow1) = a0.borrowing_sub(b0, borrow0);
+        /// assert_eq!(borrow1, true);
+        ///
+        #[doc = concat!("// ", stringify!($SelfT), "::borrowing_sub for the most significant word")]
+        /// let (diff1, overflow) = a1.borrowing_sub(b1, borrow1);
+        /// assert_eq!(overflow, false);
+        ///
+        #[doc = concat!("assert_eq!((diff1, diff0), (10, ", stringify!($UnsignedT), "::MAX));")]
         /// ```
         #[unstable(feature = "bigint_helper_methods", issue = "85532")]
         #[rustc_const_unstable(feature = "const_bigint_helper_methods", issue = "85532")]
diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs
index 3f8acc8505f..2eb29d4f9c5 100644
--- a/library/core/src/pin.rs
+++ b/library/core/src/pin.rs
@@ -622,9 +622,8 @@ impl<P: Deref> Pin<P> {
     /// that the closure is pinned.
     ///
     /// The better alternative is to avoid all that trouble and do the pinning in the outer function
-    /// instead (here using the unstable `pin` macro):
+    /// instead (here using the [`pin!`][crate::pin::pin] macro):
     /// ```
-    /// #![feature(pin_macro)]
     /// use std::pin::pin;
     /// use std::task::Context;
     /// use std::future::Future;
@@ -1026,7 +1025,6 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// ### Basic usage
 ///
 /// ```rust
-/// #![feature(pin_macro)]
 /// # use core::marker::PhantomPinned as Foo;
 /// use core::pin::{pin, Pin};
 ///
@@ -1044,7 +1042,6 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// ### Manually polling a `Future` (without `Unpin` bounds)
 ///
 /// ```rust
-/// #![feature(pin_macro)]
 /// use std::{
 ///     future::Future,
 ///     pin::pin,
@@ -1083,7 +1080,7 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// ### With `Generator`s
 ///
 /// ```rust
-/// #![feature(generators, generator_trait, pin_macro)]
+/// #![feature(generators, generator_trait)]
 /// use core::{
 ///     ops::{Generator, GeneratorState},
 ///     pin::pin,
@@ -1126,7 +1123,6 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// The following, for instance, fails to compile:
 ///
 /// ```rust,compile_fail
-/// #![feature(pin_macro)]
 /// use core::pin::{pin, Pin};
 /// # use core::{marker::PhantomPinned as Foo, mem::drop as stuff};
 ///
@@ -1168,7 +1164,7 @@ impl<P, U> DispatchFromDyn<Pin<U>> for Pin<P> where P: DispatchFromDyn<U> {}
 /// constructor.
 ///
 /// [`Box::pin`]: ../../std/boxed/struct.Box.html#method.pin
-#[unstable(feature = "pin_macro", issue = "93178")]
+#[stable(feature = "pin_macro", since = "CURRENT_RUSTC_VERSION")]
 #[rustc_macro_transparency = "semitransparent"]
 #[allow_internal_unstable(unsafe_pin_internals)]
 pub macro pin($value:expr $(,)?) {
diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs
index c910cb65c55..42a26ae1675 100644
--- a/library/core/tests/lib.rs
+++ b/library/core/tests/lib.rs
@@ -48,7 +48,6 @@
 #![feature(is_sorted)]
 #![feature(layout_for_ptr)]
 #![feature(pattern)]
-#![feature(pin_macro)]
 #![feature(sort_internals)]
 #![feature(slice_take)]
 #![feature(slice_from_ptr_range)]
diff --git a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs
index 7576ba78f60..fe4078f7710 100644
--- a/src/tools/miri/tests/pass/issues/issue-miri-2068.rs
+++ b/src/tools/miri/tests/pass/issues/issue-miri-2068.rs
@@ -1,5 +1,3 @@
-#![feature(pin_macro)]
-
 use core::future::Future;
 use core::pin::Pin;
 use core::task::{Context, Poll};
diff --git a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
index 3ba21552fd3..96fc0be344d 100644
--- a/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
+++ b/src/tools/miri/tests/pass/stacked-borrows/future-self-referential.rs
@@ -1,5 +1,3 @@
-#![feature(pin_macro)]
-
 use std::future::*;
 use std::marker::PhantomPinned;
 use std::pin::*;
diff --git a/tests/ui/associated-types/substs-ppaux.normal.stderr b/tests/ui/associated-types/substs-ppaux.normal.stderr
index eadaa35b65e..acdc3be8c67 100644
--- a/tests/ui/associated-types/substs-ppaux.normal.stderr
+++ b/tests/ui/associated-types/substs-ppaux.normal.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:16:17
    |
 LL |     fn bar<'a, T>() where T: 'a {}
-   |     --------------------------- fn() {<i8 as Foo<'static, 'static, u8>>::bar::<'static, char>} defined here
+   |     --------------------------- associated function `bar` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -20,7 +20,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:25:17
    |
 LL |     fn bar<'a, T>() where T: 'a {}
-   |     --------------------------- fn() {<i8 as Foo<'static, 'static>>::bar::<'static, char>} defined here
+   |     --------------------------- associated function `bar` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -38,7 +38,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:33:17
    |
 LL |     fn baz() {}
-   |     -------- fn() {<i8 as Foo<'static, 'static, u8>>::baz} defined here
+   |     -------- associated function `baz` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -56,7 +56,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:41:17
    |
 LL | fn foo<'z>() where &'z (): Sized {
-   | -------------------------------- fn() {foo::<'static>} defined here
+   | -------------------------------- function `foo` defined here
 ...
 LL |     let x: () = foo::<'static>;
    |            --   ^^^^^^^^^^^^^^ expected `()`, found fn item
diff --git a/tests/ui/associated-types/substs-ppaux.verbose.stderr b/tests/ui/associated-types/substs-ppaux.verbose.stderr
index 2077543ce30..e4f6ba573ca 100644
--- a/tests/ui/associated-types/substs-ppaux.verbose.stderr
+++ b/tests/ui/associated-types/substs-ppaux.verbose.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:16:17
    |
 LL |     fn bar<'a, T>() where T: 'a {}
-   |     --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::bar::<ReStatic, char>} defined here
+   |     --------------------------- associated function `bar` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::bar::<'static, char>;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -20,7 +20,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:25:17
    |
 LL |     fn bar<'a, T>() where T: 'a {}
-   |     --------------------------- fn() {<i8 as Foo<ReStatic, ReStatic>>::bar::<ReStatic, char>} defined here
+   |     --------------------------- associated function `bar` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u32>>::bar::<'static, char>;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -38,7 +38,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:33:17
    |
 LL |     fn baz() {}
-   |     -------- fn() {<i8 as Foo<ReStatic, ReStatic, u8>>::baz} defined here
+   |     -------- associated function `baz` defined here
 ...
 LL |     let x: () = <i8 as Foo<'static, 'static,  u8>>::baz;
    |            --   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found fn item
@@ -56,7 +56,7 @@ error[E0308]: mismatched types
   --> $DIR/substs-ppaux.rs:41:17
    |
 LL | fn foo<'z>() where &'z (): Sized {
-   | -------------------------------- fn() {foo::<ReStatic>} defined here
+   | -------------------------------- function `foo` defined here
 ...
 LL |     let x: () = foo::<'static>;
    |            --   ^^^^^^^^^^^^^^ expected `()`, found fn item
diff --git a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
index 9aae9013d1b..bd7aaf6fb6d 100644
--- a/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
+++ b/tests/ui/auto-traits/typeck-default-trait-impl-precedence.stderr
@@ -4,7 +4,6 @@ error[E0277]: the trait bound `u32: Signed` is not satisfied
 LL |     is_defaulted::<&'static u32>();
    |                    ^^^^^^^^^^^^ the trait `Signed` is not implemented for `u32`
    |
-   = help: the trait `Signed` is implemented for `i32`
 note: required for `&'static u32` to implement `Defaulted`
   --> $DIR/typeck-default-trait-impl-precedence.rs:10:19
    |
@@ -17,6 +16,11 @@ note: required by a bound in `is_defaulted`
    |
 LL | fn is_defaulted<T:Defaulted>() { }
    |                   ^^^^^^^^^ required by this bound in `is_defaulted`
+help: consider removing the leading `&`-reference
+   |
+LL -     is_defaulted::<&'static u32>();
+LL +     is_defaulted::<u32>();
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/consts/const-match-check.eval1.stderr b/tests/ui/consts/const-match-check.eval1.stderr
index 6e61dbbd8ee..1caf1617e21 100644
--- a/tests/ui/consts/const-match-check.eval1.stderr
+++ b/tests/ui/consts/const-match-check.eval1.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:25:15
    |
 LL |     A = { let 0 = 0; 0 },
diff --git a/tests/ui/consts/const-match-check.eval2.stderr b/tests/ui/consts/const-match-check.eval2.stderr
index 1b3b6e06c3d..f038ba1c8ed 100644
--- a/tests/ui/consts/const-match-check.eval2.stderr
+++ b/tests/ui/consts/const-match-check.eval2.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:31:24
    |
 LL |     let x: [i32; { let 0 = 0; 0 }] = [];
diff --git a/tests/ui/consts/const-match-check.matchck.stderr b/tests/ui/consts/const-match-check.matchck.stderr
index bc8edfa7af9..b1921f8a41e 100644
--- a/tests/ui/consts/const-match-check.matchck.stderr
+++ b/tests/ui/consts/const-match-check.matchck.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:4:22
    |
 LL | const X: i32 = { let 0 = 0; 0 };
@@ -12,7 +12,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL | const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                  ++           ~~~~~~~~~~~
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:8:23
    |
 LL | static Y: i32 = { let 0 = 0; 0 };
@@ -26,7 +26,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL | static Y: i32 = { if let 0 = 0 { todo!() } 0 };
    |                   ++           ~~~~~~~~~~~
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:13:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
@@ -40,7 +40,7 @@ help: you might want to use `if let` to ignore the variants that aren't matched
 LL |     const X: i32 = { if let 0 = 0 { todo!() } 0 };
    |                      ++           ~~~~~~~~~~~
 
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-match-check.rs:19:26
    |
 LL |     const X: i32 = { let 0 = 0; 0 };
diff --git a/tests/ui/consts/const-pattern-irrefutable.rs b/tests/ui/consts/const-pattern-irrefutable.rs
index 2105c12a168..61bdf57ffdb 100644
--- a/tests/ui/consts/const-pattern-irrefutable.rs
+++ b/tests/ui/consts/const-pattern-irrefutable.rs
@@ -9,8 +9,20 @@ use foo::d;
 const a: u8 = 2;
 
 fn main() {
-    let a = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
-    let c = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
-    let d = 4; //~ ERROR refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX
+    let a = 4;
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
+    //~| HELP introduce a variable instead
+    let c = 4;
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+    //~| missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
+    //~| HELP introduce a variable instead
+    let d = 4;
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+    //~| missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
+    //~| HELP introduce a variable instead
     fn f() {} // Check that the `NOTE`s still work with an item here (cf. issue #35115).
 }
diff --git a/tests/ui/consts/const-pattern-irrefutable.stderr b/tests/ui/consts/const-pattern-irrefutable.stderr
index a2b8f072c6e..c156ea1610c 100644
--- a/tests/ui/consts/const-pattern-irrefutable.stderr
+++ b/tests/ui/consts/const-pattern-irrefutable.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-pattern-irrefutable.rs:12:9
    |
 LL | const a: u8 = 2;
@@ -7,13 +7,14 @@ LL | const a: u8 = 2;
 LL |     let a = 4;
    |         ^
    |         |
-   |         interpreted as a constant pattern, not a new variable
+   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `a_var`
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-  --> $DIR/const-pattern-irrefutable.rs:13:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/const-pattern-irrefutable.rs:17:9
    |
 LL |     pub const b: u8 = 2;
    |     --------------- constant defined here
@@ -21,13 +22,14 @@ LL |     pub const b: u8 = 2;
 LL |     let c = 4;
    |         ^
    |         |
-   |         interpreted as a constant pattern, not a new variable
+   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+   |         missing patterns are not covered because `c` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `c_var`
    |
    = note: the matched value is of type `u8`
 
-error[E0005]: refutable pattern in local binding: `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
-  --> $DIR/const-pattern-irrefutable.rs:14:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/const-pattern-irrefutable.rs:22:9
    |
 LL |     pub const d: u8 = 2;
    |     --------------- constant defined here
@@ -35,7 +37,8 @@ LL |     pub const d: u8 = 2;
 LL |     let d = 4;
    |         ^
    |         |
-   |         interpreted as a constant pattern, not a new variable
+   |         patterns `0_u8..=1_u8` and `3_u8..=u8::MAX` not covered
+   |         missing patterns are not covered because `d` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `d_var`
    |
    = note: the matched value is of type `u8`
diff --git a/tests/ui/consts/const_let_refutable.stderr b/tests/ui/consts/const_let_refutable.stderr
index d7e8c048f7d..d6119028f5b 100644
--- a/tests/ui/consts/const_let_refutable.stderr
+++ b/tests/ui/consts/const_let_refutable.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in function argument: `&[]`, `&[_]` and `&[_, _, _, ..]` not covered
+error[E0005]: refutable pattern in function argument
   --> $DIR/const_let_refutable.rs:3:16
    |
 LL | const fn slice(&[a, b]: &[i32]) -> i32 {
diff --git a/tests/ui/empty/empty-never-array.rs b/tests/ui/empty/empty-never-array.rs
index 3de2b1a78a3..fd93346101d 100644
--- a/tests/ui/empty/empty-never-array.rs
+++ b/tests/ui/empty/empty-never-array.rs
@@ -8,7 +8,8 @@ enum Helper<T, U> {
 
 fn transmute<T, U>(t: T) -> U {
     let Helper::U(u) = Helper::T(t, []);
-    //~^ ERROR refutable pattern in local binding: `Helper::T(_, _)` not covered
+    //~^ ERROR refutable pattern in local binding
+    //~| `Helper::T(_, _)` not covered
     u
 }
 
diff --git a/tests/ui/empty/empty-never-array.stderr b/tests/ui/empty/empty-never-array.stderr
index adf78274368..a488e484b2b 100644
--- a/tests/ui/empty/empty-never-array.stderr
+++ b/tests/ui/empty/empty-never-array.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Helper::T(_, _)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/empty-never-array.rs:10:9
    |
 LL |     let Helper::U(u) = Helper::T(t, []);
@@ -7,18 +7,14 @@ LL |     let Helper::U(u) = Helper::T(t, []);
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Helper<T, U>` defined here
-  --> $DIR/empty-never-array.rs:4:5
+  --> $DIR/empty-never-array.rs:3:6
    |
 LL | enum Helper<T, U> {
-   |      ------
+   |      ^^^^^^
 LL |     T(T, [!; 0]),
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `Helper<T, U>`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let u = if let Helper::U(u) = Helper::T(t, []) { u } else { todo!() };
-   |     ++++++++++                                     ++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Helper::U(u) = Helper::T(t, []) else { todo!() };
    |                                         ++++++++++++++++
diff --git a/tests/ui/error-codes/E0005.stderr b/tests/ui/error-codes/E0005.stderr
index 0f179259356..4692b66413d 100644
--- a/tests/ui/error-codes/E0005.stderr
+++ b/tests/ui/error-codes/E0005.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `None` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/E0005.rs:3:9
    |
 LL |     let Some(y) = x;
@@ -6,17 +6,8 @@ LL |     let Some(y) = x;
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-note: `Option<i32>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Option<i32>`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let y = if let Some(y) = x { y } else { todo!() };
-   |     ++++++++++                 ++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Some(y) = x else { todo!() };
    |                     ++++++++++++++++
diff --git a/tests/ui/error-codes/E0297.stderr b/tests/ui/error-codes/E0297.stderr
index 903422f3b9b..293028f5f68 100644
--- a/tests/ui/error-codes/E0297.stderr
+++ b/tests/ui/error-codes/E0297.stderr
@@ -1,14 +1,9 @@
-error[E0005]: refutable pattern in `for` loop binding: `None` not covered
+error[E0005]: refutable pattern in `for` loop binding
   --> $DIR/E0297.rs:4:9
    |
 LL |     for Some(x) in xs {}
    |         ^^^^^^^ pattern `None` not covered
    |
-note: `Option<i32>` defined here
-  --> $SRC_DIR/core/src/option.rs:LL:COL
-  ::: $SRC_DIR/core/src/option.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Option<i32>`
 
 error: aborting due to previous error
diff --git a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
index e253e4791e8..49e7ab6082c 100644
--- a/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
+++ b/tests/ui/feature-gates/feature-gate-exhaustive-patterns.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Err(_)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/feature-gate-exhaustive-patterns.rs:8:9
    |
 LL |     let Ok(_x) = foo();
@@ -6,17 +6,8 @@ LL |     let Ok(_x) = foo();
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-note: `Result<u32, !>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, !>`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let _x = if let Ok(_x) = foo() { _x } else { todo!() };
-   |     +++++++++++                    +++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Ok(_x) = foo() else { todo!() };
    |                        ++++++++++++++++
diff --git a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr b/tests/ui/for/for-loop-refutable-pattern-error-message.stderr
index 20b689aa5e0..49a82a6769d 100644
--- a/tests/ui/for/for-loop-refutable-pattern-error-message.stderr
+++ b/tests/ui/for/for-loop-refutable-pattern-error-message.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in `for` loop binding: `&i32::MIN..=0_i32` and `&2_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in `for` loop binding
   --> $DIR/for-loop-refutable-pattern-error-message.rs:2:9
    |
 LL |     for &1 in [1].iter() {}
diff --git a/tests/ui/impl-trait/in-trait/issue-102140.stderr b/tests/ui/impl-trait/in-trait/issue-102140.stderr
index 08602185f50..18bb63745d7 100644
--- a/tests/ui/impl-trait/in-trait/issue-102140.stderr
+++ b/tests/ui/impl-trait/in-trait/issue-102140.stderr
@@ -2,11 +2,15 @@ error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
   --> $DIR/issue-102140.rs:23:22
    |
 LL |         MyTrait::foo(&self)
-   |         ------------ -^^^^
-   |         |            |
-   |         |            the trait `MyTrait` is not implemented for `&dyn MyTrait`
-   |         |            help: consider removing the leading `&`-reference
+   |         ------------ ^^^^^ the trait `MyTrait` is not implemented for `&dyn MyTrait`
+   |         |
    |         required by a bound introduced by this call
+   |
+help: consider removing the leading `&`-reference
+   |
+LL -         MyTrait::foo(&self)
+LL +         MyTrait::foo(self)
+   |
 
 error[E0277]: the trait bound `&dyn MyTrait: MyTrait` is not satisfied
   --> $DIR/issue-102140.rs:23:9
diff --git a/tests/ui/issues/issue-15381.rs b/tests/ui/issues/issue-15381.rs
index 392fb1b24dd..23b266bef1d 100644
--- a/tests/ui/issues/issue-15381.rs
+++ b/tests/ui/issues/issue-15381.rs
@@ -2,7 +2,8 @@ fn main() {
     let values: Vec<u8> = vec![1,2,3,4,5,6,7,8];
 
     for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
-        //~^ ERROR refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not
+        //~^ ERROR refutable pattern in `for` loop binding
+        //~| patterns `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
         println!("y={}", y);
     }
 }
diff --git a/tests/ui/issues/issue-15381.stderr b/tests/ui/issues/issue-15381.stderr
index c4667ce1c8b..085958411cc 100644
--- a/tests/ui/issues/issue-15381.stderr
+++ b/tests/ui/issues/issue-15381.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in `for` loop binding: `&[]`, `&[_]`, `&[_, _]` and 1 more not covered
+error[E0005]: refutable pattern in `for` loop binding
   --> $DIR/issue-15381.rs:4:9
    |
 LL |     for &[x,y,z] in values.chunks(3).filter(|&xs| xs.len() == 3) {
diff --git a/tests/ui/issues/issue-35241.stderr b/tests/ui/issues/issue-35241.stderr
index 42a78ed97e0..d600e934bd5 100644
--- a/tests/ui/issues/issue-35241.stderr
+++ b/tests/ui/issues/issue-35241.stderr
@@ -2,15 +2,15 @@ error[E0308]: mismatched types
   --> $DIR/issue-35241.rs:3:20
    |
 LL | struct Foo(u32);
-   | ---------- fn(u32) -> Foo {Foo} defined here
+   | ---------- `Foo` defines a struct constructor here, which should be called
 LL |
 LL | fn test() -> Foo { Foo }
-   |              ---   ^^^ expected struct `Foo`, found fn item
+   |              ---   ^^^ expected struct `Foo`, found struct constructor
    |              |
    |              expected `Foo` because of return type
    |
-   = note: expected struct `Foo`
-             found fn item `fn(u32) -> Foo {Foo}`
+   = note:          expected struct `Foo`
+           found struct constructor `fn(u32) -> Foo {Foo}`
 help: use parentheses to construct this tuple struct
    |
 LL | fn test() -> Foo { Foo(/* u32 */) }
diff --git a/tests/ui/kindck/kindck-copy.stderr b/tests/ui/kindck/kindck-copy.stderr
index 9af89159a8c..aee2aa98a60 100644
--- a/tests/ui/kindck/kindck-copy.stderr
+++ b/tests/ui/kindck/kindck-copy.stderr
@@ -4,12 +4,16 @@ error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied
 LL |     assert_copy::<&'static mut isize>();
    |                   ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize`
    |
-   = help: the trait `Copy` is implemented for `isize`
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
 LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
+help: consider removing the leading `&`-reference
+   |
+LL -     assert_copy::<&'static mut isize>();
+LL +     assert_copy::<isize>();
+   |
 
 error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:28:19
@@ -17,12 +21,16 @@ error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied
 LL |     assert_copy::<&'a mut isize>();
    |                   ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize`
    |
-   = help: the trait `Copy` is implemented for `isize`
 note: required by a bound in `assert_copy`
   --> $DIR/kindck-copy.rs:5:18
    |
 LL | fn assert_copy<T:Copy>() { }
    |                  ^^^^ required by this bound in `assert_copy`
+help: consider removing the leading `&`-reference
+   |
+LL -     assert_copy::<&'a mut isize>();
+LL +     assert_copy::<isize>();
+   |
 
 error[E0277]: the trait bound `Box<isize>: Copy` is not satisfied
   --> $DIR/kindck-copy.rs:31:19
diff --git a/tests/ui/never_type/exhaustive_patterns.stderr b/tests/ui/never_type/exhaustive_patterns.stderr
index e41baf86218..40c7c1d1067 100644
--- a/tests/ui/never_type/exhaustive_patterns.stderr
+++ b/tests/ui/never_type/exhaustive_patterns.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Either::B(_)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/exhaustive_patterns.rs:20:9
    |
 LL |     let Either::A(()) = foo();
@@ -7,13 +7,13 @@ LL |     let Either::A(()) = foo();
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Either<(), !>` defined here
-  --> $DIR/exhaustive_patterns.rs:12:5
+  --> $DIR/exhaustive_patterns.rs:10:6
    |
 LL | enum Either<A, B> {
-   |      ------
+   |      ^^^^^^
 LL |     A(A),
 LL |     B(inner::Wrapper<B>),
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `Either<(), !>`
 help: you might want to use `if let` to ignore the variant that isn't matched
    |
diff --git a/tests/ui/not-panic/not-panic-safe-4.stderr b/tests/ui/not-panic/not-panic-safe-4.stderr
index fc1c594d0d4..9428c125651 100644
--- a/tests/ui/not-panic/not-panic-safe-4.stderr
+++ b/tests/ui/not-panic/not-panic-safe-4.stderr
@@ -12,6 +12,11 @@ note: required by a bound in `assert`
    |
 LL | fn assert<T: UnwindSafe + ?Sized>() {}
    |              ^^^^^^^^^^ required by this bound in `assert`
+help: consider removing the leading `&`-reference
+   |
+LL -     assert::<&RefCell<i32>>();
+LL +     assert::<RefCell<i32>>();
+   |
 
 error[E0277]: the type `UnsafeCell<isize>` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary
   --> $DIR/not-panic-safe-4.rs:9:14
@@ -28,6 +33,11 @@ note: required by a bound in `assert`
    |
 LL | fn assert<T: UnwindSafe + ?Sized>() {}
    |              ^^^^^^^^^^ required by this bound in `assert`
+help: consider removing the leading `&`-reference
+   |
+LL -     assert::<&RefCell<i32>>();
+LL +     assert::<RefCell<i32>>();
+   |
 
 error: aborting due to 2 previous errors
 
diff --git a/tests/ui/not-panic/not-panic-safe.rs b/tests/ui/not-panic/not-panic-safe.rs
index 4165c5dc13a..1b3c6482ce9 100644
--- a/tests/ui/not-panic/not-panic-safe.rs
+++ b/tests/ui/not-panic/not-panic-safe.rs
@@ -5,6 +5,6 @@ use std::panic::UnwindSafe;
 fn assert<T: UnwindSafe + ?Sized>() {}
 
 fn main() {
-    assert::<&mut i32>();
-    //~^ ERROR the type `&mut i32` may not be safely transferred across an unwind boundary
+    assert::<&mut &mut &i32>();
+    //~^ ERROR the type `&mut &mut &i32` may not be safely transferred across an unwind boundary
 }
diff --git a/tests/ui/not-panic/not-panic-safe.stderr b/tests/ui/not-panic/not-panic-safe.stderr
index 2cd51a43998..37a6aee3906 100644
--- a/tests/ui/not-panic/not-panic-safe.stderr
+++ b/tests/ui/not-panic/not-panic-safe.stderr
@@ -1,19 +1,21 @@
-error[E0277]: the type `&mut i32` may not be safely transferred across an unwind boundary
+error[E0277]: the type `&mut &mut &i32` may not be safely transferred across an unwind boundary
   --> $DIR/not-panic-safe.rs:8:14
    |
-LL |     assert::<&mut i32>();
-   |              -^^^^^^^
-   |              |
-   |              `&mut i32` may not be safely transferred across an unwind boundary
-   |              help: consider removing the leading `&`-reference
+LL |     assert::<&mut &mut &i32>();
+   |              ^^^^^^^^^^^^^^ `&mut &mut &i32` may not be safely transferred across an unwind boundary
    |
-   = help: the trait `UnwindSafe` is not implemented for `&mut i32`
-   = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32`
+   = help: the trait `UnwindSafe` is not implemented for `&mut &mut &i32`
+   = note: `UnwindSafe` is implemented for `&&mut &i32`, but not for `&mut &mut &i32`
 note: required by a bound in `assert`
   --> $DIR/not-panic-safe.rs:5:14
    |
 LL | fn assert<T: UnwindSafe + ?Sized>() {}
    |              ^^^^^^^^^^ required by this bound in `assert`
+help: consider removing 2 leading `&`-references
+   |
+LL -     assert::<&mut &mut &i32>();
+LL +     assert::<&i32>();
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
index 95b22ac0594..4adcf4feee9 100644
--- a/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
+++ b/tests/ui/or-patterns/issue-69875-should-have-been-expanded-earlier-non-exhaustive.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=-1_i32` and `3_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/issue-69875-should-have-been-expanded-earlier-non-exhaustive.rs:2:10
    |
 LL |     let (0 | (1 | 2)) = 0;
diff --git a/tests/ui/pattern/usefulness/issue-31561.rs b/tests/ui/pattern/usefulness/issue-31561.rs
index 5b878851a31..82414f0418b 100644
--- a/tests/ui/pattern/usefulness/issue-31561.rs
+++ b/tests/ui/pattern/usefulness/issue-31561.rs
@@ -6,5 +6,6 @@ enum Thing {
 
 fn main() {
     let Thing::Foo(y) = Thing::Foo(1);
-    //~^ ERROR refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered
+    //~^ ERROR refutable pattern in local binding
+    //~| `Thing::Bar` and `Thing::Baz` not covered
 }
diff --git a/tests/ui/pattern/usefulness/issue-31561.stderr b/tests/ui/pattern/usefulness/issue-31561.stderr
index 20f2f09500a..5367de5e513 100644
--- a/tests/ui/pattern/usefulness/issue-31561.stderr
+++ b/tests/ui/pattern/usefulness/issue-31561.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Thing::Bar` and `Thing::Baz` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/issue-31561.rs:8:9
    |
 LL |     let Thing::Foo(y) = Thing::Foo(1);
@@ -7,21 +7,17 @@ LL |     let Thing::Foo(y) = Thing::Foo(1);
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Thing` defined here
-  --> $DIR/issue-31561.rs:3:5
+  --> $DIR/issue-31561.rs:1:6
    |
 LL | enum Thing {
-   |      -----
+   |      ^^^^^
 LL |     Foo(u8),
 LL |     Bar,
-   |     ^^^ not covered
+   |     --- not covered
 LL |     Baz
-   |     ^^^ not covered
+   |     --- not covered
    = note: the matched value is of type `Thing`
-help: you might want to use `if let` to ignore the variants that aren't matched
-   |
-LL |     let y = if let Thing::Foo(y) = Thing::Foo(1) { y } else { todo!() };
-   |     ++++++++++                                   ++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variants that aren't matched
+help: you might want to use `let else` to handle the variants that aren't matched
    |
 LL |     let Thing::Foo(y) = Thing::Foo(1) else { todo!() };
    |                                       ++++++++++++++++
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs
index af42fc1aeb4..5145f769075 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs
+++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.rs
@@ -15,9 +15,6 @@ enum E {
     //~^ NOTE `E` defined here
     //~| NOTE `E` defined here
     //~| NOTE `E` defined here
-    //~| NOTE `E` defined here
-    //~| NOTE `E` defined here
-    //~| NOTE `E` defined here
     //~| NOTE  not covered
     //~| NOTE  not covered
     //~| NOTE  not covered
@@ -41,37 +38,41 @@ fn by_val(e: E) {
         E::A => {}
     }
 
-    let E::A = e; //~ ERROR refutable pattern in local binding: `E::B` and `E::C` not covered
-    //~^ NOTE patterns `E::B` and `E::C` not covered
+    let E::A = e;
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `E::B` and `E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `E`
 }
 
 fn by_ref_once(e: &E) {
-    match e { //~ ERROR non-exhaustive patterns: `&E::B` and `&E::C` not covered
-    //~^ NOTE patterns `&E::B` and `&E::C` not covered
+    match e {
+    //~^ ERROR non-exhaustive patterns
+    //~| patterns `&E::B` and `&E::C` not covered
     //~| NOTE the matched value is of type `&E`
         E::A => {}
     }
 
-    let E::A = e; //~ ERROR refutable pattern in local binding: `&E::B` and `&E::C` not covered
-    //~^ NOTE patterns `&E::B` and `&E::C` not covered
+    let E::A = e;
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `&E::B` and `&E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `&E`
 }
 
 fn by_ref_thrice(e: & &mut &E) {
-    match e { //~ ERROR non-exhaustive patterns: `&&mut &E::B` and `&&mut &E::C` not covered
-    //~^ NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered
+    match e {
+    //~^ ERROR non-exhaustive patterns
+    //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered
     //~| NOTE the matched value is of type `&&mut &E`
         E::A => {}
     }
 
     let E::A = e;
-    //~^ ERROR refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered
-    //~| NOTE patterns `&&mut &E::B` and `&&mut &E::C` not covered
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `&&mut &E::B` and `&&mut &E::C` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
     //~| NOTE the matched value is of type `&&mut &E`
@@ -83,20 +84,21 @@ enum Opt {
     Some(u8),
     None,
     //~^ NOTE `Opt` defined here
-    //~| NOTE `Opt` defined here
     //~| NOTE not covered
     //~| NOTE not covered
 }
 
 fn ref_pat(e: Opt) {
-    match e {//~ ERROR non-exhaustive patterns: `Opt::None` not covered
-        //~^ NOTE pattern `Opt::None` not covered
+    match e {
+        //~^ ERROR non-exhaustive patterns
+        //~| pattern `Opt::None` not covered
         //~| NOTE the matched value is of type `Opt`
         Opt::Some(ref _x) => {}
     }
 
-    let Opt::Some(ref _x) = e; //~ ERROR refutable pattern in local binding: `Opt::None` not covered
-    //~^ NOTE the matched value is of type `Opt`
+    let Opt::Some(ref _x) = e;
+    //~^ ERROR refutable pattern in local binding
+    //~| NOTE the matched value is of type `Opt`
     //~| NOTE pattern `Opt::None` not covered
     //~| NOTE `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with
     //~| NOTE for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
diff --git a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
index 678c9b2ab58..769d4070fb5 100644
--- a/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
+++ b/tests/ui/pattern/usefulness/non-exhaustive-defined-here.stderr
@@ -1,5 +1,5 @@
 error[E0004]: non-exhaustive patterns: `E::B` and `E::C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:38:11
+  --> $DIR/non-exhaustive-defined-here.rs:35:11
    |
 LL |     match e1 {
    |           ^^ patterns `E::B` and `E::C` not covered
@@ -22,8 +22,8 @@ LL ~         E::A => {}
 LL +         E::B | E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `E::B` and `E::C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:44:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/non-exhaustive-defined-here.rs:41:9
    |
 LL |     let E::A = e;
    |         ^^^^ patterns `E::B` and `E::C` not covered
@@ -31,16 +31,16 @@ LL |     let E::A = e;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `E` defined here
-  --> $DIR/non-exhaustive-defined-here.rs:14:5
+  --> $DIR/non-exhaustive-defined-here.rs:6:6
    |
 LL | enum E {
-   |      -
+   |      ^
 ...
 LL |     B,
-   |     ^ not covered
+   |     - not covered
 ...
 LL |     C
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
@@ -48,7 +48,7 @@ LL |     if let E::A = e { todo!() }
    |     ++              ~~~~~~~~~~~
 
 error[E0004]: non-exhaustive patterns: `&E::B` and `&E::C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:52:11
+  --> $DIR/non-exhaustive-defined-here.rs:50:11
    |
 LL |     match e {
    |           ^ patterns `&E::B` and `&E::C` not covered
@@ -71,8 +71,8 @@ LL ~         E::A => {}
 LL +         &E::B | &E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `&E::B` and `&E::C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:58:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/non-exhaustive-defined-here.rs:57:9
    |
 LL |     let E::A = e;
    |         ^^^^ patterns `&E::B` and `&E::C` not covered
@@ -80,16 +80,16 @@ LL |     let E::A = e;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `E` defined here
-  --> $DIR/non-exhaustive-defined-here.rs:14:5
+  --> $DIR/non-exhaustive-defined-here.rs:6:6
    |
 LL | enum E {
-   |      -
+   |      ^
 ...
 LL |     B,
-   |     ^ not covered
+   |     - not covered
 ...
 LL |     C
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `&E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
@@ -120,8 +120,8 @@ LL ~         E::A => {}
 LL +         &&mut &E::B | &&mut &E::C => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `&&mut &E::B` and `&&mut &E::C` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:72:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/non-exhaustive-defined-here.rs:73:9
    |
 LL |     let E::A = e;
    |         ^^^^ patterns `&&mut &E::B` and `&&mut &E::C` not covered
@@ -129,16 +129,16 @@ LL |     let E::A = e;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `E` defined here
-  --> $DIR/non-exhaustive-defined-here.rs:14:5
+  --> $DIR/non-exhaustive-defined-here.rs:6:6
    |
 LL | enum E {
-   |      -
+   |      ^
 ...
 LL |     B,
-   |     ^ not covered
+   |     - not covered
 ...
 LL |     C
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `&&mut &E`
 help: you might want to use `if let` to ignore the variants that aren't matched
    |
@@ -152,7 +152,7 @@ LL |     match e {
    |           ^ pattern `Opt::None` not covered
    |
 note: `Opt` defined here
-  --> $DIR/non-exhaustive-defined-here.rs:84:5
+  --> $DIR/non-exhaustive-defined-here.rs:85:5
    |
 LL | enum Opt {
    |      ---
@@ -166,8 +166,8 @@ LL ~         Opt::Some(ref _x) => {}
 LL +         Opt::None => todo!()
    |
 
-error[E0005]: refutable pattern in local binding: `Opt::None` not covered
-  --> $DIR/non-exhaustive-defined-here.rs:98:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/non-exhaustive-defined-here.rs:99:9
    |
 LL |     let Opt::Some(ref _x) = e;
    |         ^^^^^^^^^^^^^^^^^ pattern `Opt::None` not covered
@@ -175,19 +175,15 @@ LL |     let Opt::Some(ref _x) = e;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Opt` defined here
-  --> $DIR/non-exhaustive-defined-here.rs:84:5
+  --> $DIR/non-exhaustive-defined-here.rs:81:6
    |
 LL | enum Opt {
-   |      ---
+   |      ^^^
 ...
 LL |     None,
-   |     ^^^^ not covered
+   |     ---- not covered
    = note: the matched value is of type `Opt`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let _x = if let Opt::Some(ref _x) = e { _x } else { todo!() };
-   |     +++++++++++                           +++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Opt::Some(ref _x) = e else { todo!() };
    |                               ++++++++++++++++
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
index 7c9aa51e748..7a3e991d593 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.rs
@@ -1,7 +1,9 @@
 fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
-//~^ ERROR refutable pattern in function argument: `(_, _)` not covered
+//~^ ERROR refutable pattern in function argument
+//~| `(_, _)` not covered
 
 fn main() {
     let (1, (Some(1), 2..=3)) = (1, (None, 2));
-    //~^ ERROR refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
+    //~^ ERROR refutable pattern in local binding
+    //~| `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
 }
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
index d1dacc822e9..c518de47740 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-errors.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in function argument: `(_, _)` not covered
+error[E0005]: refutable pattern in function argument
   --> $DIR/refutable-pattern-errors.rs:1:9
    |
 LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
@@ -6,8 +6,8 @@ LL | fn func((1, (Some(1), 2..=3)): (isize, (Option<isize>, isize))) { }
    |
    = note: the matched value is of type `(isize, (Option<isize>, isize))`
 
-error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
-  --> $DIR/refutable-pattern-errors.rs:5:9
+error[E0005]: refutable pattern in local binding
+  --> $DIR/refutable-pattern-errors.rs:6:9
    |
 LL |     let (1, (Some(1), 2..=3)) = (1, (None, 2));
    |         ^^^^^^^^^^^^^^^^^^^^^ patterns `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
index a2d9e1935de..17dc38ab25d 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.rs
@@ -1,5 +1,6 @@
 fn main() {
     let f = |3: isize| println!("hello");
-    //~^ ERROR refutable pattern in function argument: `_` not covered
+    //~^ ERROR refutable pattern in function argument
+    //~| `_` not covered
     f(4);
 }
diff --git a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
index c9d8cf43f95..55f0b2319fb 100644
--- a/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
+++ b/tests/ui/pattern/usefulness/refutable-pattern-in-fn-arg.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in function argument: `_` not covered
+error[E0005]: refutable pattern in function argument
   --> $DIR/refutable-pattern-in-fn-arg.rs:2:14
    |
 LL |     let f = |3: isize| println!("hello");
diff --git a/tests/ui/pin-macro/cant_access_internals.rs b/tests/ui/pin-macro/cant_access_internals.rs
index 120d08894f8..5826a18b571 100644
--- a/tests/ui/pin-macro/cant_access_internals.rs
+++ b/tests/ui/pin-macro/cant_access_internals.rs
@@ -1,5 +1,4 @@
 // edition:2018
-#![feature(pin_macro)]
 
 use core::{
     marker::PhantomPinned,
diff --git a/tests/ui/pin-macro/cant_access_internals.stderr b/tests/ui/pin-macro/cant_access_internals.stderr
index 060c9c48c21..d43027657f0 100644
--- a/tests/ui/pin-macro/cant_access_internals.stderr
+++ b/tests/ui/pin-macro/cant_access_internals.stderr
@@ -1,5 +1,5 @@
 error[E0658]: use of unstable library feature 'unsafe_pin_internals'
-  --> $DIR/cant_access_internals.rs:12:15
+  --> $DIR/cant_access_internals.rs:11:15
    |
 LL |     mem::take(phantom_pinned.pointer);
    |               ^^^^^^^^^^^^^^^^^^^^^^
diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
index ca2b6cf7593..59774bc753d 100644
--- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
+++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.rs
@@ -1,5 +1,4 @@
 // edition:2018
-#![feature(pin_macro)]
 
 use core::{
     convert::identity,
diff --git a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
index fc1be052fb7..4ecc6370d3c 100644
--- a/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
+++ b/tests/ui/pin-macro/lifetime_errors_on_promotion_misusage.stderr
@@ -1,5 +1,5 @@
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/lifetime_errors_on_promotion_misusage.rs:12:35
+  --> $DIR/lifetime_errors_on_promotion_misusage.rs:11:35
    |
 LL |     let phantom_pinned = identity(pin!(PhantomPinned));
    |                                   ^^^^^^^^^^^^^^^^^^^ - temporary value is freed at the end of this statement
@@ -13,7 +13,7 @@ LL |     stuff(phantom_pinned)
    = note: this error originates in the macro `pin` (in Nightly builds, run with -Z macro-backtrace for more info)
 
 error[E0716]: temporary value dropped while borrowed
-  --> $DIR/lifetime_errors_on_promotion_misusage.rs:19:30
+  --> $DIR/lifetime_errors_on_promotion_misusage.rs:18:30
    |
 LL |     let phantom_pinned = {
    |         -------------- borrow later stored here
diff --git a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr
index 86ad6aa847c..1b4d80d9057 100644
--- a/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr
+++ b/tests/ui/recursion/recursive-types-are-not-uninhabited.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Err(_)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/recursive-types-are-not-uninhabited.rs:6:9
    |
 LL |     let Ok(x) = res;
@@ -6,17 +6,8 @@ LL |     let Ok(x) = res;
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-note: `Result<u32, &R<'_>>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, &R<'_>>`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let x = if let Ok(x) = res { x } else { todo!() };
-   |     ++++++++++                 ++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Ok(x) = res else { todo!() };
    |                     ++++++++++++++++
diff --git a/tests/ui/resolve/privacy-enum-ctor.stderr b/tests/ui/resolve/privacy-enum-ctor.stderr
index d734fa76b4a..a24fe4d23ea 100644
--- a/tests/ui/resolve/privacy-enum-ctor.stderr
+++ b/tests/ui/resolve/privacy-enum-ctor.stderr
@@ -264,15 +264,15 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:27:20
    |
 LL |             Fn(u8),
-   |             -- fn(u8) -> Z {Z::Fn} defined here
+   |             -- `Fn` defines an enum variant constructor here, which should be called
 ...
 LL |         let _: Z = Z::Fn;
-   |                -   ^^^^^ expected enum `Z`, found fn item
+   |                -   ^^^^^ expected enum `Z`, found enum constructor
    |                |
    |                expected due to this
    |
-   = note: expected enum `Z`
-           found fn item `fn(u8) -> Z {Z::Fn}`
+   = note:          expected enum `Z`
+           found enum constructor `fn(u8) -> Z {Z::Fn}`
 help: use parentheses to construct this tuple variant
    |
 LL |         let _: Z = Z::Fn(/* u8 */);
@@ -305,15 +305,15 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:43:16
    |
 LL |         Fn(u8),
-   |         -- fn(u8) -> E {E::Fn} defined here
+   |         -- `Fn` defines an enum variant constructor here, which should be called
 ...
 LL |     let _: E = m::E::Fn;
-   |            -   ^^^^^^^^ expected enum `E`, found fn item
+   |            -   ^^^^^^^^ expected enum `E`, found enum constructor
    |            |
    |            expected due to this
    |
-   = note: expected enum `E`
-           found fn item `fn(u8) -> E {E::Fn}`
+   = note:          expected enum `E`
+           found enum constructor `fn(u8) -> E {E::Fn}`
 help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = m::E::Fn(/* u8 */);
@@ -346,15 +346,15 @@ error[E0308]: mismatched types
   --> $DIR/privacy-enum-ctor.rs:51:16
    |
 LL |         Fn(u8),
-   |         -- fn(u8) -> E {E::Fn} defined here
+   |         -- `Fn` defines an enum variant constructor here, which should be called
 ...
 LL |     let _: E = E::Fn;
-   |            -   ^^^^^ expected enum `E`, found fn item
+   |            -   ^^^^^ expected enum `E`, found enum constructor
    |            |
    |            expected due to this
    |
-   = note: expected enum `E`
-           found fn item `fn(u8) -> E {E::Fn}`
+   = note:          expected enum `E`
+           found enum constructor `fn(u8) -> E {E::Fn}`
 help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = E::Fn(/* u8 */);
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
index ac819dce6db..15f08486f0f 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.rs
@@ -1,7 +1,8 @@
 fn main() {
     let A = 3;
-    //~^ ERROR refutable pattern in local binding: `i32::MIN..=1_i32` and
-    //~| interpreted as a constant pattern, not a new variable
+    //~^ ERROR refutable pattern in local binding
+    //~| patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+    //~| missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
     //~| HELP introduce a variable instead
     //~| SUGGESTION a_var
 
diff --git a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
index 618bcaca14c..1c1cab25fbf 100644
--- a/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
+++ b/tests/ui/suggestions/const-pat-non-exaustive-let-new-var.stderr
@@ -1,10 +1,11 @@
-error[E0005]: refutable pattern in local binding: `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/const-pat-non-exaustive-let-new-var.rs:2:9
    |
 LL |     let A = 3;
    |         ^
    |         |
-   |         interpreted as a constant pattern, not a new variable
+   |         patterns `i32::MIN..=1_i32` and `3_i32..=i32::MAX` not covered
+   |         missing patterns are not covered because `a` is interpreted as a constant pattern, not a new variable
    |         help: introduce a variable instead: `a_var`
 ...
 LL |     const A: i32 = 2;
diff --git a/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr b/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr
index d0ddb34d9fe..4cbcd31fa5e 100644
--- a/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr
+++ b/tests/ui/suggestions/fn-or-tuple-struct-without-args.stderr
@@ -2,7 +2,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:29:20
    |
 LL | fn foo(a: usize, b: usize) -> usize { a }
-   | ----------------------------------- fn(usize, usize) -> usize {foo} defined here
+   | ----------------------------------- function `foo` defined here
 ...
 LL |     let _: usize = foo;
    |            -----   ^^^ expected `usize`, found fn item
@@ -20,15 +20,15 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:30:16
    |
 LL | struct S(usize, usize);
-   | -------- fn(usize, usize) -> S {S} defined here
+   | -------- `S` defines a struct constructor here, which should be called
 ...
 LL |     let _: S = S;
-   |            -   ^ expected struct `S`, found fn item
+   |            -   ^ expected struct `S`, found struct constructor
    |            |
    |            expected due to this
    |
-   = note: expected struct `S`
-             found fn item `fn(usize, usize) -> S {S}`
+   = note:          expected struct `S`
+           found struct constructor `fn(usize, usize) -> S {S}`
 help: use parentheses to construct this tuple struct
    |
 LL |     let _: S = S(/* usize */, /* usize */);
@@ -38,7 +38,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:31:20
    |
 LL | fn bar() -> usize { 42 }
-   | ----------------- fn() -> usize {bar} defined here
+   | ----------------- function `bar` defined here
 ...
 LL |     let _: usize = bar;
    |            -----   ^^^ expected `usize`, found fn item
@@ -56,15 +56,15 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:32:16
    |
 LL | struct V();
-   | -------- fn() -> V {V} defined here
+   | -------- `V` defines a struct constructor here, which should be called
 ...
 LL |     let _: V = V;
-   |            -   ^ expected struct `V`, found fn item
+   |            -   ^ expected struct `V`, found struct constructor
    |            |
    |            expected due to this
    |
-   = note: expected struct `V`
-             found fn item `fn() -> V {V}`
+   = note:          expected struct `V`
+           found struct constructor `fn() -> V {V}`
 help: use parentheses to construct this tuple struct
    |
 LL |     let _: V = V();
@@ -74,7 +74,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:33:20
    |
 LL |     fn baz(x: usize, y: usize) -> usize { x }
-   |     ----------------------------------- fn(usize, usize) -> usize {<_ as T>::baz} defined here
+   |     ----------------------------------- associated function `baz` defined here
 ...
 LL |     let _: usize = T::baz;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -92,7 +92,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:34:20
    |
 LL |     fn bat(x: usize) -> usize { 42 }
-   |     ------------------------- fn(usize) -> usize {<_ as T>::bat} defined here
+   |     ------------------------- associated function `bat` defined here
 ...
 LL |     let _: usize = T::bat;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -110,15 +110,15 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:35:16
    |
 LL |     A(usize),
-   |     - fn(usize) -> E {E::A} defined here
+   |     - `A` defines an enum variant constructor here, which should be called
 ...
 LL |     let _: E = E::A;
-   |            -   ^^^^ expected enum `E`, found fn item
+   |            -   ^^^^ expected enum `E`, found enum constructor
    |            |
    |            expected due to this
    |
-   = note: expected enum `E`
-           found fn item `fn(usize) -> E {E::A}`
+   = note:          expected enum `E`
+           found enum constructor `fn(usize) -> E {E::A}`
 help: use parentheses to construct this tuple variant
    |
 LL |     let _: E = E::A(/* usize */);
@@ -134,7 +134,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:37:20
    |
 LL |     fn baz(x: usize, y: usize) -> usize { x }
-   |     ----------------------------------- fn(usize, usize) -> usize {<X as T>::baz} defined here
+   |     ----------------------------------- associated function `baz` defined here
 ...
 LL |     let _: usize = X::baz;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -152,7 +152,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:38:20
    |
 LL |     fn bat(x: usize) -> usize { 42 }
-   |     ------------------------- fn(usize) -> usize {<X as T>::bat} defined here
+   |     ------------------------- associated function `bat` defined here
 ...
 LL |     let _: usize = X::bat;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -170,7 +170,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:39:20
    |
 LL |     fn bax(x: usize) -> usize { 42 }
-   |     ------------------------- fn(usize) -> usize {<X as T>::bax} defined here
+   |     ------------------------- associated function `bax` defined here
 ...
 LL |     let _: usize = X::bax;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -188,7 +188,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:40:20
    |
 LL |     fn bach(x: usize) -> usize;
-   |     --------------------------- fn(usize) -> usize {<X as T>::bach} defined here
+   |     --------------------------- associated function `bach` defined here
 ...
 LL |     let _: usize = X::bach;
    |            -----   ^^^^^^^ expected `usize`, found fn item
@@ -206,7 +206,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:41:20
    |
 LL |     fn ban(&self) -> usize { 42 }
-   |     ---------------------- for<'a> fn(&'a X) -> usize {<X as T>::ban} defined here
+   |     ---------------------- associated function `ban` defined here
 ...
 LL |     let _: usize = X::ban;
    |            -----   ^^^^^^ expected `usize`, found fn item
@@ -224,7 +224,7 @@ error[E0308]: mismatched types
   --> $DIR/fn-or-tuple-struct-without-args.rs:42:20
    |
 LL |     fn bal(&self) -> usize;
-   |     ----------------------- for<'a> fn(&'a X) -> usize {<X as T>::bal} defined here
+   |     ----------------------- associated function `bal` defined here
 ...
 LL |     let _: usize = X::bal;
    |            -----   ^^^^^^ expected `usize`, found fn item
diff --git a/tests/ui/suggestions/suggest-remove-refs-1.stderr b/tests/ui/suggestions/suggest-remove-refs-1.stderr
index 1a843f3f509..387770535f6 100644
--- a/tests/ui/suggestions/suggest-remove-refs-1.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-1.stderr
@@ -2,13 +2,15 @@ error[E0277]: `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
   --> $DIR/suggest-remove-refs-1.rs:6:19
    |
 LL |     for (i, _) in &v.iter().enumerate() {
-   |                   -^^^^^^^^^^^^^^^^^^^^
-   |                   |
-   |                   `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
-   |                   help: consider removing the leading `&`-reference
+   |                   ^^^^^^^^^^^^^^^^^^^^^ `&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
+help: consider removing the leading `&`-reference
+   |
+LL -     for (i, _) in &v.iter().enumerate() {
+LL +     for (i, _) in v.iter().enumerate() {
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/suggest-remove-refs-2.stderr b/tests/ui/suggestions/suggest-remove-refs-2.stderr
index f39361d529f..1632b2abb2f 100644
--- a/tests/ui/suggestions/suggest-remove-refs-2.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-2.stderr
@@ -2,13 +2,15 @@ error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterat
   --> $DIR/suggest-remove-refs-2.rs:6:19
    |
 LL |     for (i, _) in & & & & &v.iter().enumerate() {
-   |                   ---------^^^^^^^^^^^^^^^^^^^^
-   |                   |
-   |                   `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
-   |                   help: consider removing 5 leading `&`-references
+   |                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
+help: consider removing 5 leading `&`-references
+   |
+LL -     for (i, _) in & & & & &v.iter().enumerate() {
+LL +     for (i, _) in v.iter().enumerate() {
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/suggest-remove-refs-3.stderr b/tests/ui/suggestions/suggest-remove-refs-3.stderr
index 31cca323d0e..7bf421a7729 100644
--- a/tests/ui/suggestions/suggest-remove-refs-3.stderr
+++ b/tests/ui/suggestions/suggest-remove-refs-3.stderr
@@ -1,18 +1,20 @@
 error[E0277]: `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
   --> $DIR/suggest-remove-refs-3.rs:6:19
    |
-LL |        for (i, _) in & & &
-   |  ____________________^
-   | | ___________________|
-   | ||
-LL | ||         & &v
-   | ||___________- help: consider removing 5 leading `&`-references
-LL | |          .iter()
-LL | |          .enumerate() {
-   | |_____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
+LL |       for (i, _) in & & &
+   |  ___________________^
+LL | |         & &v
+LL | |         .iter()
+LL | |         .enumerate() {
+   | |____________________^ `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` is not an iterator
    |
    = help: the trait `Iterator` is not implemented for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>`
    = note: required for `&&&&&Enumerate<std::slice::Iter<'_, {integer}>>` to implement `IntoIterator`
+help: consider removing 5 leading `&`-references
+   |
+LL -     for (i, _) in & & &
+LL +     for (i, _) in v
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/suggestions/suggest-remove-refs-4.fixed b/tests/ui/suggestions/suggest-remove-refs-4.fixed
new file mode 100644
index 00000000000..dd63d215972
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-4.fixed
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let foo = [1,2,3].iter();
+    for _i in foo {} //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/suggest-remove-refs-4.rs b/tests/ui/suggestions/suggest-remove-refs-4.rs
new file mode 100644
index 00000000000..3c3d9b1b3f9
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-4.rs
@@ -0,0 +1,5 @@
+// run-rustfix
+fn main() {
+    let foo = &[1,2,3].iter();
+    for _i in &foo {} //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/suggest-remove-refs-4.stderr b/tests/ui/suggestions/suggest-remove-refs-4.stderr
new file mode 100644
index 00000000000..e4ad17e0671
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-4.stderr
@@ -0,0 +1,17 @@
+error[E0277]: `&&std::slice::Iter<'_, {integer}>` is not an iterator
+  --> $DIR/suggest-remove-refs-4.rs:4:15
+   |
+LL |     for _i in &foo {}
+   |               ^^^^ `&&std::slice::Iter<'_, {integer}>` is not an iterator
+   |
+   = help: the trait `Iterator` is not implemented for `&&std::slice::Iter<'_, {integer}>`
+   = note: required for `&&std::slice::Iter<'_, {integer}>` to implement `IntoIterator`
+help: consider removing 2 leading `&`-references
+   |
+LL ~     let foo = [1,2,3].iter();
+LL ~     for _i in foo {}
+   |
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/suggestions/suggest-remove-refs-5.fixed b/tests/ui/suggestions/suggest-remove-refs-5.fixed
new file mode 100644
index 00000000000..9f59f9c199a
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-5.fixed
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+    let v = &mut Vec::<i32>::new();
+    for _ in v {} //~ ERROR E0277
+
+    let v = &mut [1u8];
+    for _ in v {} //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/suggest-remove-refs-5.rs b/tests/ui/suggestions/suggest-remove-refs-5.rs
new file mode 100644
index 00000000000..d56aa0c9ca4
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-5.rs
@@ -0,0 +1,8 @@
+// run-rustfix
+fn main() {
+    let v = &mut &mut Vec::<i32>::new();
+    for _ in &mut &mut v {} //~ ERROR E0277
+
+    let v = &mut &mut [1u8];
+    for _ in &mut v {} //~ ERROR E0277
+}
diff --git a/tests/ui/suggestions/suggest-remove-refs-5.stderr b/tests/ui/suggestions/suggest-remove-refs-5.stderr
new file mode 100644
index 00000000000..7de84d6122b
--- /dev/null
+++ b/tests/ui/suggestions/suggest-remove-refs-5.stderr
@@ -0,0 +1,37 @@
+error[E0277]: `Vec<i32>` is not an iterator
+  --> $DIR/suggest-remove-refs-5.rs:4:14
+   |
+LL |     for _ in &mut &mut v {}
+   |              ^^^^^^^^^^^ `Vec<i32>` is not an iterator; try calling `.into_iter()` or `.iter()`
+   |
+   = help: the trait `Iterator` is not implemented for `Vec<i32>`
+   = note: required for `&mut Vec<i32>` to implement `Iterator`
+   = note: 3 redundant requirements hidden
+   = note: required for `&mut &mut &mut &mut Vec<i32>` to implement `Iterator`
+   = note: required for `&mut &mut &mut &mut Vec<i32>` to implement `IntoIterator`
+help: consider removing 3 leading `&`-references
+   |
+LL ~     let v = &mut Vec::<i32>::new();
+LL ~     for _ in v {}
+   |
+
+error[E0277]: `[u8; 1]` is not an iterator
+  --> $DIR/suggest-remove-refs-5.rs:7:14
+   |
+LL |     for _ in &mut v {}
+   |              ^^^^^^ `[u8; 1]` is not an iterator; try calling `.into_iter()` or `.iter()`
+   |
+   = help: the trait `Iterator` is not implemented for `[u8; 1]`
+   = note: required for `&mut [u8; 1]` to implement `Iterator`
+   = note: 2 redundant requirements hidden
+   = note: required for `&mut &mut &mut [u8; 1]` to implement `Iterator`
+   = note: required for `&mut &mut &mut [u8; 1]` to implement `IntoIterator`
+help: consider removing 2 leading `&`-references
+   |
+LL ~     let v = &mut [1u8];
+LL ~     for _ in v {}
+   |
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/typeck/issue-57404.stderr b/tests/ui/typeck/issue-57404.stderr
index 5065ac32ad2..a631dbb39fb 100644
--- a/tests/ui/typeck/issue-57404.stderr
+++ b/tests/ui/typeck/issue-57404.stderr
@@ -2,14 +2,17 @@ error[E0277]: `&mut ()` is not a tuple
   --> $DIR/issue-57404.rs:6:41
    |
 LL |     handlers.unwrap().as_mut().call_mut(&mut ());
-   |                                -------- -^^^^^^
-   |                                |        |
-   |                                |        the trait `Tuple` is not implemented for `&mut ()`
-   |                                |        help: consider removing the leading `&`-reference
+   |                                -------- ^^^^^^^ the trait `Tuple` is not implemented for `&mut ()`
+   |                                |
    |                                required by a bound introduced by this call
    |
 note: required by a bound in `call_mut`
   --> $SRC_DIR/core/src/ops/function.rs:LL:COL
+help: consider removing the leading `&`-reference
+   |
+LL -     handlers.unwrap().as_mut().call_mut(&mut ());
+LL +     handlers.unwrap().as_mut().call_mut(());
+   |
 
 error: aborting due to previous error
 
diff --git a/tests/ui/typeck/issue-87181/empty-tuple-method.rs b/tests/ui/typeck/issue-87181/empty-tuple-method.rs
index be68ad32ae5..96b3f8dab8d 100644
--- a/tests/ui/typeck/issue-87181/empty-tuple-method.rs
+++ b/tests/ui/typeck/issue-87181/empty-tuple-method.rs
@@ -10,5 +10,5 @@ impl Foo {
 fn main() {
     let thing = Bar { bar: Foo };
     thing.bar.foo();
-    //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope [E0599]
+    //~^ ERROR no method named `foo` found for struct constructor `fn() -> Foo {Foo}` in the current scope [E0599]
 }
diff --git a/tests/ui/typeck/issue-87181/empty-tuple-method.stderr b/tests/ui/typeck/issue-87181/empty-tuple-method.stderr
index 23e7b7cc363..f0ca49e6d1e 100644
--- a/tests/ui/typeck/issue-87181/empty-tuple-method.stderr
+++ b/tests/ui/typeck/issue-87181/empty-tuple-method.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo}` in the current scope
+error[E0599]: no method named `foo` found for struct constructor `fn() -> Foo {Foo}` in the current scope
   --> $DIR/empty-tuple-method.rs:12:15
    |
 LL |     thing.bar.foo();
diff --git a/tests/ui/typeck/issue-87181/enum-variant.rs b/tests/ui/typeck/issue-87181/enum-variant.rs
index d87f99c3c5a..ed01656ce72 100644
--- a/tests/ui/typeck/issue-87181/enum-variant.rs
+++ b/tests/ui/typeck/issue-87181/enum-variant.rs
@@ -12,5 +12,5 @@ impl Foo {
 fn main() {
     let thing = Bar { bar: Foo::Tup };
     thing.bar.foo();
-    //~^ ERROR no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope [E0599]
+    //~^ ERROR no method named `foo` found for enum constructor `fn() -> Foo {Foo::Tup}` in the current scope [E0599]
 }
diff --git a/tests/ui/typeck/issue-87181/enum-variant.stderr b/tests/ui/typeck/issue-87181/enum-variant.stderr
index 2247ea27021..d313a887abd 100644
--- a/tests/ui/typeck/issue-87181/enum-variant.stderr
+++ b/tests/ui/typeck/issue-87181/enum-variant.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for fn item `fn() -> Foo {Foo::Tup}` in the current scope
+error[E0599]: no method named `foo` found for enum constructor `fn() -> Foo {Foo::Tup}` in the current scope
   --> $DIR/enum-variant.rs:14:15
    |
 LL |     thing.bar.foo();
diff --git a/tests/ui/typeck/issue-87181/tuple-method.rs b/tests/ui/typeck/issue-87181/tuple-method.rs
index e88f642b070..6310984438c 100644
--- a/tests/ui/typeck/issue-87181/tuple-method.rs
+++ b/tests/ui/typeck/issue-87181/tuple-method.rs
@@ -10,5 +10,5 @@ impl Foo {
 fn main() {
     let thing = Bar { bar: Foo };
     thing.bar.foo();
-    //~^ ERROR no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope [E0599]
+    //~^ ERROR no method named `foo` found for struct constructor `fn(u8, i32) -> Foo {Foo}` in the current scope [E0599]
 }
diff --git a/tests/ui/typeck/issue-87181/tuple-method.stderr b/tests/ui/typeck/issue-87181/tuple-method.stderr
index e27c41858d3..de3dc15a54b 100644
--- a/tests/ui/typeck/issue-87181/tuple-method.stderr
+++ b/tests/ui/typeck/issue-87181/tuple-method.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `foo` found for fn item `fn(u8, i32) -> Foo {Foo}` in the current scope
+error[E0599]: no method named `foo` found for struct constructor `fn(u8, i32) -> Foo {Foo}` in the current scope
   --> $DIR/tuple-method.rs:12:15
    |
 LL |     thing.bar.foo();
diff --git a/tests/ui/typeck/issue-96738.stderr b/tests/ui/typeck/issue-96738.stderr
index 0d4d87ef47e..547cffffa2e 100644
--- a/tests/ui/typeck/issue-96738.stderr
+++ b/tests/ui/typeck/issue-96738.stderr
@@ -1,4 +1,4 @@
-error[E0599]: no method named `nonexistent_method` found for fn item `fn(_) -> Option<_> {Option::<_>::Some}` in the current scope
+error[E0599]: no method named `nonexistent_method` found for enum constructor `fn(_) -> Option<_> {Option::<_>::Some}` in the current scope
   --> $DIR/issue-96738.rs:2:10
    |
 LL |     Some.nonexistent_method();
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.rs b/tests/ui/uninhabited/uninhabited-irrefutable.rs
index 1a0f3c5e550..4b001aca2d1 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.rs
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.rs
@@ -24,5 +24,7 @@ enum Foo {
 
 fn main() {
     let x: Foo = Foo::D(123, 456);
-    let Foo::D(_y, _z) = x; //~ ERROR refutable pattern in local binding: `Foo::A(_)` not covered
+    let Foo::D(_y, _z) = x;
+    //~^ ERROR refutable pattern in local binding
+    //~| `Foo::A(_)` not covered
 }
diff --git a/tests/ui/uninhabited/uninhabited-irrefutable.stderr b/tests/ui/uninhabited/uninhabited-irrefutable.stderr
index 32f287a1818..8cafea555c1 100644
--- a/tests/ui/uninhabited/uninhabited-irrefutable.stderr
+++ b/tests/ui/uninhabited/uninhabited-irrefutable.stderr
@@ -1,4 +1,4 @@
-error[E0005]: refutable pattern in local binding: `Foo::A(_)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/uninhabited-irrefutable.rs:27:9
    |
 LL |     let Foo::D(_y, _z) = x;
@@ -7,18 +7,14 @@ LL |     let Foo::D(_y, _z) = x;
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
 note: `Foo` defined here
-  --> $DIR/uninhabited-irrefutable.rs:19:5
+  --> $DIR/uninhabited-irrefutable.rs:18:6
    |
 LL | enum Foo {
-   |      ---
+   |      ^^^
 LL |     A(foo::SecretlyEmpty),
-   |     ^ not covered
+   |     - not covered
    = note: the matched value is of type `Foo`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let (_y, _z) = if let Foo::D(_y, _z) = x { (_y, _z) } else { todo!() };
-   |     +++++++++++++++++                        +++++++++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Foo::D(_y, _z) = x else { todo!() };
    |                            ++++++++++++++++
diff --git a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
index d33a61ca848..466d7f2eadb 100644
--- a/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
+++ b/tests/ui/uninhabited/uninhabited-matches-feature-gated.stderr
@@ -95,7 +95,7 @@ LL ~         Ok(x) => x,
 LL ~         Err(_) => todo!(),
    |
 
-error[E0005]: refutable pattern in local binding: `Err(_)` not covered
+error[E0005]: refutable pattern in local binding
   --> $DIR/uninhabited-matches-feature-gated.rs:37:9
    |
 LL |     let Ok(x) = x;
@@ -103,17 +103,8 @@ LL |     let Ok(x) = x;
    |
    = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
    = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-note: `Result<u32, Void>` defined here
-  --> $SRC_DIR/core/src/result.rs:LL:COL
-  ::: $SRC_DIR/core/src/result.rs:LL:COL
-   |
-   = note: not covered
    = note: the matched value is of type `Result<u32, Void>`
-help: you might want to use `if let` to ignore the variant that isn't matched
-   |
-LL |     let x = if let Ok(x) = x { x } else { todo!() };
-   |     ++++++++++               ++++++++++++++++++++++
-help: alternatively, you might want to use let else to handle the variant that isn't matched
+help: you might want to use `let else` to handle the variant that isn't matched
    |
 LL |     let Ok(x) = x else { todo!() };
    |                   ++++++++++++++++