about summary refs log tree commit diff
path: root/compiler/rustc_infer
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_infer')
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs425
-rw-r--r--compiler/rustc_infer/src/infer/at.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs15
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs15
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs32
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs43
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs311
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs396
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs76
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note.rs160
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_region.rs427
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs71
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs40
-rw-r--r--compiler/rustc_infer/src/infer/note.rs203
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs2
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs5
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs20
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs11
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs10
21 files changed, 1037 insertions, 1243 deletions
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index c4f11472d55..033a1842edb 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -1,15 +1,18 @@
 use hir::GenericParamKind;
 use rustc_errors::{
     fluent, AddToDiagnostic, Applicability, Diagnostic, DiagnosticMessage, DiagnosticStyledString,
-    MultiSpan, SubdiagnosticMessage,
+    IntoDiagnosticArg, MultiSpan, SubdiagnosticMessage,
 };
 use rustc_hir as hir;
-use rustc_hir::{FnRetTy, Ty};
+use rustc_hir::FnRetTy;
 use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::{Region, TyCtxt};
+use rustc_middle::ty::print::TraitRefPrintOnlyTraitPath;
+use rustc_middle::ty::{Binder, FnSig, Region, Ty, TyCtxt};
 use rustc_span::symbol::kw;
+use rustc_span::Symbol;
 use rustc_span::{symbol::Ident, BytePos, Span};
 
+use crate::infer::error_reporting::nice_region_error::placeholder_error::Highlighted;
 use crate::infer::error_reporting::{
     need_type_info::{GeneratorKindAsDiagArg, UnderspecifiedArgKind},
     ObligationCauseAsDiagArg,
@@ -357,8 +360,8 @@ impl AddToDiagnostic for LifetimeMismatchLabels {
 pub struct AddLifetimeParamsSuggestion<'a> {
     pub tcx: TyCtxt<'a>,
     pub sub: Region<'a>,
-    pub ty_sup: &'a Ty<'a>,
-    pub ty_sub: &'a Ty<'a>,
+    pub ty_sup: &'a hir::Ty<'a>,
+    pub ty_sub: &'a hir::Ty<'a>,
     pub add_note: bool,
 }
 
@@ -369,8 +372,8 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> {
     {
         let mut mk_suggestion = || {
             let (
-                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sub, _), .. },
-                hir::Ty { kind: hir::TyKind::Rptr(lifetime_sup, _), .. },
+                hir::Ty { kind: hir::TyKind::Ref(lifetime_sub, _), .. },
+                hir::Ty { kind: hir::TyKind::Ref(lifetime_sup, _), .. },
             ) = (self.ty_sub, self.ty_sup) else {
                 return false;
             };
@@ -520,3 +523,411 @@ pub struct MismatchedStaticLifetime<'a> {
     #[subdiagnostic]
     pub implicit_static_lifetimes: Vec<ImplicitStaticLifetimeSubdiag>,
 }
+
+#[derive(Diagnostic)]
+pub enum ExplicitLifetimeRequired<'a> {
+    #[diag(infer_explicit_lifetime_required_with_ident, code = "E0621")]
+    WithIdent {
+        #[primary_span]
+        #[label]
+        span: Span,
+        simple_ident: Ident,
+        named: String,
+        #[suggestion(
+            infer_explicit_lifetime_required_sugg_with_ident,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+    #[diag(infer_explicit_lifetime_required_with_param_type, code = "E0621")]
+    WithParamType {
+        #[primary_span]
+        #[label]
+        span: Span,
+        named: String,
+        #[suggestion(
+            infer_explicit_lifetime_required_sugg_with_param_type,
+            code = "{new_ty}",
+            applicability = "unspecified"
+        )]
+        new_ty_span: Span,
+        #[skip_arg]
+        new_ty: Ty<'a>,
+    },
+}
+
+pub enum TyOrSig<'tcx> {
+    Ty(Highlighted<'tcx, Ty<'tcx>>),
+    ClosureSig(Highlighted<'tcx, Binder<'tcx, FnSig<'tcx>>>),
+}
+
+impl IntoDiagnosticArg for TyOrSig<'_> {
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        match self {
+            TyOrSig::Ty(ty) => ty.into_diagnostic_arg(),
+            TyOrSig::ClosureSig(sig) => sig.into_diagnostic_arg(),
+        }
+    }
+}
+
+#[derive(Subdiagnostic)]
+pub enum ActualImplExplNotes<'tcx> {
+    #[note(infer_actual_impl_expl_expected_signature_two)]
+    ExpectedSignatureTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_any)]
+    ExpectedSignatureAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_some)]
+    ExpectedSignatureSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_signature_nothing)]
+    ExpectedSignatureNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_two)]
+    ExpectedPassiveTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_any)]
+    ExpectedPassiveAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_some)]
+    ExpectedPassiveSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_passive_nothing)]
+    ExpectedPassiveNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_expected_other_two)]
+    ExpectedOtherTwo {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_any)]
+    ExpectedOtherAny {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_some)]
+    ExpectedOtherSome {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+    },
+    #[note(infer_actual_impl_expl_expected_other_nothing)]
+    ExpectedOtherNothing {
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+    },
+    #[note(infer_actual_impl_expl_but_actually_implements_trait)]
+    ButActuallyImplementsTrait {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+    },
+    #[note(infer_actual_impl_expl_but_actually_implemented_for_ty)]
+    ButActuallyImplementedForTy {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+    #[note(infer_actual_impl_expl_but_actually_ty_implements)]
+    ButActuallyTyImplements {
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        has_lifetime: bool,
+        lifetime: usize,
+        ty: String,
+    },
+}
+
+pub enum ActualImplExpectedKind {
+    Signature,
+    Passive,
+    Other,
+}
+
+pub enum ActualImplExpectedLifetimeKind {
+    Two,
+    Any,
+    Some,
+    Nothing,
+}
+
+impl<'tcx> ActualImplExplNotes<'tcx> {
+    pub fn new_expected(
+        kind: ActualImplExpectedKind,
+        lt_kind: ActualImplExpectedLifetimeKind,
+        leading_ellipsis: bool,
+        ty_or_sig: TyOrSig<'tcx>,
+        trait_path: Highlighted<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+        lifetime_1: usize,
+        lifetime_2: usize,
+    ) -> Self {
+        match (kind, lt_kind) {
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedSignatureTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedSignatureAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedSignatureSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Signature, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedSignatureNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedPassiveTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedPassiveAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedPassiveSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Passive, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedPassiveNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Two) => {
+                Self::ExpectedOtherTwo {
+                    leading_ellipsis,
+                    ty_or_sig,
+                    trait_path,
+                    lifetime_1,
+                    lifetime_2,
+                }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Any) => {
+                Self::ExpectedOtherAny { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Some) => {
+                Self::ExpectedOtherSome { leading_ellipsis, ty_or_sig, trait_path, lifetime_1 }
+            }
+            (ActualImplExpectedKind::Other, ActualImplExpectedLifetimeKind::Nothing) => {
+                Self::ExpectedOtherNothing { leading_ellipsis, ty_or_sig, trait_path }
+            }
+        }
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_placeholder_mismatch)]
+pub struct TraitPlaceholderMismatch<'tcx> {
+    #[primary_span]
+    pub span: Span,
+    #[label(label_satisfy)]
+    pub satisfy_span: Option<Span>,
+    #[label(label_where)]
+    pub where_span: Option<Span>,
+    #[label(label_dup)]
+    pub dup_span: Option<Span>,
+    pub def_id: String,
+    pub trait_def_id: String,
+
+    #[subdiagnostic]
+    pub actual_impl_expl_notes: Vec<ActualImplExplNotes<'tcx>>,
+}
+
+pub struct ConsiderBorrowingParamHelp {
+    pub spans: Vec<Span>,
+}
+
+impl AddToDiagnostic for ConsiderBorrowingParamHelp {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        let mut type_param_span: MultiSpan = self.spans.clone().into();
+        for &span in &self.spans {
+            // Seems like we can't call f() here as Into<DiagnosticMessage> is required
+            type_param_span.push_span_label(span, fluent::infer_tid_consider_borrowing);
+        }
+        let msg = f(diag, fluent::infer_tid_param_help.into());
+        diag.span_help(type_param_span, msg);
+    }
+}
+
+#[derive(Subdiagnostic)]
+#[help(infer_tid_rel_help)]
+pub struct RelationshipHelp;
+
+#[derive(Diagnostic)]
+#[diag(infer_trait_impl_diff)]
+pub struct TraitImplDiff {
+    #[primary_span]
+    #[label(found)]
+    pub sp: Span,
+    #[label(expected)]
+    pub trait_sp: Span,
+    #[note(expected_found)]
+    pub note: (),
+    #[subdiagnostic]
+    pub param_help: ConsiderBorrowingParamHelp,
+    #[subdiagnostic]
+    // Seems like subdiagnostics are always pushed to the end, so this one
+    // also has to be a subdiagnostic to maintain order.
+    pub rel_help: Option<RelationshipHelp>,
+    pub expected: String,
+    pub found: String,
+}
+
+pub struct DynTraitConstraintSuggestion {
+    pub span: Span,
+    pub ident: Ident,
+}
+
+impl AddToDiagnostic for DynTraitConstraintSuggestion {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        let mut multi_span: MultiSpan = vec![self.span].into();
+        multi_span.push_span_label(self.span, fluent::infer_dtcs_has_lifetime_req_label);
+        multi_span.push_span_label(self.ident.span, fluent::infer_dtcs_introduces_requirement);
+        let msg = f(diag, fluent::infer_dtcs_has_req_note.into());
+        diag.span_note(multi_span, msg);
+        let msg = f(diag, fluent::infer_dtcs_suggestion.into());
+        diag.span_suggestion_verbose(
+            self.span.shrink_to_hi(),
+            msg,
+            " + '_",
+            Applicability::MaybeIncorrect,
+        );
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_calling_introduces, code = "E0772")]
+pub struct ButCallingIntroduces {
+    #[label(label1)]
+    pub param_ty_span: Span,
+    #[primary_span]
+    #[label(label2)]
+    pub cause_span: Span,
+
+    pub has_param_name: bool,
+    pub param_name: String,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+    pub assoc_item: Symbol,
+    pub has_impl_path: bool,
+    pub impl_path: String,
+}
+
+pub struct ReqIntroducedLocations {
+    pub span: MultiSpan,
+    pub spans: Vec<Span>,
+    pub fn_decl_span: Span,
+    pub cause_span: Span,
+    pub add_label: bool,
+}
+
+impl AddToDiagnostic for ReqIntroducedLocations {
+    fn add_to_diagnostic_with<F>(mut self, diag: &mut Diagnostic, f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        for sp in self.spans {
+            self.span.push_span_label(sp, fluent::infer_ril_introduced_here);
+        }
+
+        if self.add_label {
+            self.span.push_span_label(self.fn_decl_span, fluent::infer_ril_introduced_by);
+        }
+        self.span.push_span_label(self.cause_span, fluent::infer_ril_because_of);
+        let msg = f(diag, fluent::infer_ril_static_introduced_by.into());
+        diag.span_note(self.span, msg);
+    }
+}
+
+pub struct MoreTargeted {
+    pub ident: Symbol,
+}
+
+impl AddToDiagnostic for MoreTargeted {
+    fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _f: F)
+    where
+        F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage,
+    {
+        diag.code(rustc_errors::error_code!(E0772));
+        diag.set_primary_message(fluent::infer_more_targeted);
+        diag.set_arg("ident", self.ident);
+    }
+}
+
+#[derive(Diagnostic)]
+#[diag(infer_but_needs_to_satisfy, code = "E0759")]
+pub struct ButNeedsToSatisfy {
+    #[primary_span]
+    pub sp: Span,
+    #[label(influencer)]
+    pub influencer_point: Span,
+    #[label(used_here)]
+    pub spans: Vec<Span>,
+    #[label(require)]
+    pub require_span_as_label: Option<Span>,
+    #[note(require)]
+    pub require_span_as_note: Option<Span>,
+    #[note(introduced_by_bound)]
+    pub bound: Option<Span>,
+
+    #[subdiagnostic]
+    pub req_introduces_loc: Option<ReqIntroducedLocations>,
+
+    pub spans_empty: bool,
+    pub has_lifetime: bool,
+    pub lifetime: String,
+}
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index e9186540a7b..d816a9ed3d7 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -427,3 +427,15 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> {
         }
     }
 }
+
+impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> {
+    fn to_trace(
+        _: TyCtxt<'tcx>,
+        cause: &ObligationCause<'tcx>,
+        a_is_expected: bool,
+        a: Self,
+        b: Self,
+    ) -> TypeTrace<'tcx> {
+        TypeTrace { cause: cause.clone(), values: Sigs(ExpectedFound::new(a_is_expected, a, b)) }
+    }
+}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index ec5221379d2..091635e6c73 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -6,8 +6,7 @@
 //! [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html
 
 use crate::infer::canonical::{
-    Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, Canonicalized,
-    OriginalQueryValues,
+    Canonical, CanonicalTyVarKind, CanonicalVarInfo, CanonicalVarKind, OriginalQueryValues,
 };
 use crate::infer::InferCtxt;
 use rustc_middle::ty::flags::FlagComputation;
@@ -40,7 +39,7 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -59,7 +58,7 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -99,7 +98,7 @@ impl<'tcx> InferCtxt<'tcx> {
     /// out the [chapter in the rustc dev guide][c].
     ///
     /// [c]: https://rust-lang.github.io/chalk/book/canonical_queries/canonicalization.html#canonicalizing-the-query-result
-    pub fn canonicalize_response<V>(&self, value: V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_response<V>(&self, value: V) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -113,7 +112,7 @@ impl<'tcx> InferCtxt<'tcx> {
         )
     }
 
-    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonicalized<'tcx, V>
+    pub fn canonicalize_user_type_annotation<V>(&self, value: V) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -135,7 +134,7 @@ impl<'tcx> InferCtxt<'tcx> {
         &self,
         value: V,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
@@ -524,7 +523,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
         tcx: TyCtxt<'tcx>,
         canonicalize_region_mode: &dyn CanonicalizeMode,
         query_state: &mut OriginalQueryValues<'tcx>,
-    ) -> Canonicalized<'tcx, V>
+    ) -> Canonical<'tcx, V>
     where
         V: TypeFoldable<'tcx>,
     {
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index 996b1c40e3f..3d49182f0b8 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -9,7 +9,7 @@
 
 use crate::infer::canonical::substitute::{substitute_value, CanonicalExt};
 use crate::infer::canonical::{
-    Canonical, CanonicalVarValues, CanonicalizedQueryResponse, Certainty, OriginalQueryValues,
+    Canonical, CanonicalQueryResponse, CanonicalVarValues, Certainty, OriginalQueryValues,
     QueryOutlivesConstraint, QueryRegionConstraints, QueryResponse,
 };
 use crate::infer::nll_relate::{NormalizationStrategy, TypeRelating, TypeRelatingDelegate};
@@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> {
         inference_vars: CanonicalVarValues<'tcx>,
         answer: T,
         fulfill_cx: &mut dyn TraitEngine<'tcx>,
-    ) -> Fallible<CanonicalizedQueryResponse<'tcx, T>>
+    ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
     where
         T: Debug + TypeFoldable<'tcx>,
         Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
@@ -151,11 +151,12 @@ impl<'tcx> InferCtxt<'tcx> {
         })
     }
 
-    fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
-        self.inner
-            .borrow_mut()
-            .opaque_type_storage
-            .take_opaque_types()
+    /// FIXME: This method should only be used for canonical queries and therefore be private.
+    ///
+    /// As the new solver does canonicalization slightly differently, this is also used there
+    /// for now. This should hopefully change fairly soon.
+    pub fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+        std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
             .into_iter()
             .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
             .collect()
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 269fc95420a..5c3e9a2d5cc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -1,4 +1,3 @@
-// ignore-tidy-filelength
 //! Error Reporting Code for the inference engine
 //!
 //! Because of the way inference, and in particular region inference,
@@ -303,6 +302,7 @@ pub fn unexpected_hidden_region_diagnostic<'tcx>(
                     None,
                     format!("captures `{}`", hidden_region),
                     None,
+                    Some(reg_info.def_id),
                 )
             }
         }
@@ -729,7 +729,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             format!("this and all prior arms are found to be of type `{}`", t),
                         );
                     }
-                    let outer_error_span = if any_multiline_arm {
+                    let outer = if any_multiline_arm || !source_map.is_multiline(cause.span) {
                         // Cover just `match` and the scrutinee expression, not
                         // the entire match body, to reduce diagram noise.
                         cause.span.shrink_to_lo().to(scrut_span)
@@ -737,7 +737,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                         cause.span
                     };
                     let msg = "`match` arms have incompatible types";
-                    err.span_label(outer_error_span, msg);
+                    err.span_label(outer, msg);
                     self.suggest_remove_semi_or_return_binding(
                         err,
                         prior_arm_block_id,
@@ -1428,8 +1428,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         impl<'tcx> OpaqueTypesVisitor<'tcx> {
             fn visit_expected_found(
                 tcx: TyCtxt<'tcx>,
-                expected: Ty<'tcx>,
-                found: Ty<'tcx>,
+                expected: impl TypeVisitable<'tcx>,
+                found: impl TypeVisitable<'tcx>,
                 ignore_span: Span,
             ) -> Self {
                 let mut types_visitor = OpaqueTypesVisitor {
@@ -1569,6 +1569,11 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                             _ => (false, Mismatch::Fixed("type")),
                         }
                     }
+                    ValuePairs::Sigs(infer::ExpectedFound { expected, found }) => {
+                        OpaqueTypesVisitor::visit_expected_found(self.tcx, expected, found, span)
+                            .report(diag);
+                        (false, Mismatch::Fixed("signature"))
+                    }
                     ValuePairs::TraitRefs(_) | ValuePairs::PolyTraitRefs(_) => {
                         (false, Mismatch::Fixed("trait"))
                     }
@@ -1836,7 +1841,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
         // In some (most?) cases cause.body_id points to actual body, but in some cases
         // it's an actual definition. According to the comments (e.g. in
-        // rustc_hir_analysis/check/compare_method.rs:compare_predicate_entailment) the latter
+        // rustc_hir_analysis/check/compare_impl_item.rs:compare_predicate_entailment) the latter
         // is relied upon by some other code. This might (or might not) need cleanup.
         let body_owner_def_id =
             self.tcx.hir().opt_local_def_id(cause.body_id).unwrap_or_else(|| {
@@ -2040,6 +2045,17 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     ret => ret,
                 }
             }
+            infer::Sigs(exp_found) => {
+                let exp_found = self.resolve_vars_if_possible(exp_found);
+                if exp_found.references_error() {
+                    return None;
+                }
+                let (exp, fnd) = self.cmp_fn_sig(
+                    &ty::Binder::dummy(exp_found.expected),
+                    &ty::Binder::dummy(exp_found.found),
+                );
+                Some((exp, fnd, None, None))
+            }
         }
     }
 
@@ -2199,10 +2215,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             );
         }
 
-        fn binding_suggestion<'tcx, S: fmt::Display>(
+        fn binding_suggestion<S: fmt::Display>(
             err: &mut Diagnostic,
             type_param_span: Option<(Span, bool)>,
-            bound_kind: GenericKind<'tcx>,
+            bound_kind: GenericKind<'_>,
             sub: S,
             add_lt_sugg: Option<(Span, String)>,
         ) {
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index d8f540b7446..39f4d502259 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -96,8 +96,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
                 }
             }
 
-            hir::TyKind::Rptr(ref lifetime, _) => {
-                // the lifetime of the TyRptr
+            hir::TyKind::Ref(ref lifetime, _) => {
+                // the lifetime of the Ref
                 let hir_id = lifetime.hir_id;
                 match (self.tcx.named_region(hir_id), self.bound_region) {
                     // Find the index of the named region that was part of the
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
index 8a0e332f9c7..59fb74eb543 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs
@@ -9,7 +9,7 @@ mod different_lifetimes;
 pub mod find_anon_type;
 mod mismatched_static_lifetime;
 mod named_anon_conflict;
-mod placeholder_error;
+pub(crate) mod placeholder_error;
 mod placeholder_relation;
 mod static_impl_trait;
 mod trait_impl_difference;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
index 3fe7c1598fc..4e13ec90228 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs
@@ -1,8 +1,11 @@
 //! Error Reporting for Anonymous Region Lifetime Errors
 //! where one region is named and the other is anonymous.
-use crate::infer::error_reporting::nice_region_error::find_anon_type::find_anon_type;
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
-use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, ErrorGuaranteed};
+use crate::{
+    errors::ExplicitLifetimeRequired,
+    infer::error_reporting::nice_region_error::find_anon_type::find_anon_type,
+};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
 use rustc_middle::ty;
 use rustc_span::symbol::kw;
 
@@ -86,31 +89,17 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         {
             return None;
         }
-
-        let (error_var, span_label_var) = match param.pat.simple_ident() {
-            Some(simple_ident) => (
-                format!("the type of `{}`", simple_ident),
-                format!("the type of `{}`", simple_ident),
-            ),
-            None => ("parameter type".to_owned(), "type".to_owned()),
+        let named = named.to_string();
+        let err = match param.pat.simple_ident() {
+            Some(simple_ident) => ExplicitLifetimeRequired::WithIdent {
+                span,
+                simple_ident,
+                named,
+                new_ty_span,
+                new_ty,
+            },
+            None => ExplicitLifetimeRequired::WithParamType { span, named, new_ty_span, new_ty },
         };
-
-        let mut diag = struct_span_err!(
-            self.tcx().sess,
-            span,
-            E0621,
-            "explicit lifetime required in {}",
-            error_var
-        );
-
-        diag.span_label(span, format!("lifetime `{}` required", named));
-        diag.span_suggestion(
-            new_ty_span,
-            &format!("add explicit lifetime `{}` to {}", named, span_label_var),
-            new_ty,
-            Applicability::Unspecified,
-        );
-
-        Some(diag)
+        Some(self.tcx().sess.parse_sess.create_err(err))
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index fed9fda74bf..202f39521e9 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -1,10 +1,14 @@
+use crate::errors::{
+    ActualImplExpectedKind, ActualImplExpectedLifetimeKind, ActualImplExplNotes,
+    TraitPlaceholderMismatch, TyOrSig,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::ValuePairs;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::intern::Interned;
-use rustc_errors::{Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, IntoDiagnosticArg};
 use rustc_hir::def::Namespace;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::error::ExpectedFound;
@@ -12,7 +16,43 @@ use rustc_middle::ty::print::{FmtPrinter, Print, RegionHighlightMode};
 use rustc_middle::ty::subst::SubstsRef;
 use rustc_middle::ty::{self, RePlaceholder, ReVar, Region, TyCtxt};
 
-use std::fmt::{self, Write};
+use std::fmt;
+
+// HACK(eddyb) maybe move this in a more central location.
+#[derive(Copy, Clone)]
+pub struct Highlighted<'tcx, T> {
+    tcx: TyCtxt<'tcx>,
+    highlight: RegionHighlightMode<'tcx>,
+    value: T,
+}
+
+impl<'tcx, T> IntoDiagnosticArg for Highlighted<'tcx, T>
+where
+    T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+    fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+        rustc_errors::DiagnosticArgValue::Str(self.to_string().into())
+    }
+}
+
+impl<'tcx, T> Highlighted<'tcx, T> {
+    fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
+        Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
+    }
+}
+
+impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
+where
+    T: for<'a> Print<'tcx, FmtPrinter<'a, 'tcx>, Error = fmt::Error, Output = FmtPrinter<'a, 'tcx>>,
+{
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
+        printer.region_highlight_mode = self.highlight;
+
+        let s = self.value.print(printer)?.into_buffer();
+        f.write_str(&s)
+    }
+}
 
 impl<'tcx> NiceRegionError<'_, 'tcx> {
     /// When given a `ConcreteFailure` for a function with arguments containing a named region and
@@ -205,26 +245,21 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
         actual_substs: SubstsRef<'tcx>,
     ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
         let span = cause.span();
-        let msg = format!(
-            "implementation of `{}` is not general enough",
-            self.tcx().def_path_str(trait_def_id),
-        );
-        let mut err = self.tcx().sess.struct_span_err(span, &msg);
-
-        let leading_ellipsis = if let ObligationCauseCode::ItemObligation(def_id)
-        | ObligationCauseCode::ExprItemObligation(def_id, ..) =
-            *cause.code()
-        {
-            err.span_label(span, "doesn't satisfy where-clause");
-            err.span_label(
-                self.tcx().def_span(def_id),
-                &format!("due to a where-clause on `{}`...", self.tcx().def_path_str(def_id)),
-            );
-            true
-        } else {
-            err.span_label(span, &msg);
-            false
-        };
+
+        let (leading_ellipsis, satisfy_span, where_span, dup_span, def_id) =
+            if let ObligationCauseCode::ItemObligation(def_id)
+            | ObligationCauseCode::ExprItemObligation(def_id, ..) = *cause.code()
+            {
+                (
+                    true,
+                    Some(span),
+                    Some(self.tcx().def_span(def_id)),
+                    None,
+                    self.tcx().def_path_str(def_id),
+                )
+            } else {
+                (false, None, None, Some(span), String::new())
+            };
 
         let expected_trait_ref = self
             .cx
@@ -284,8 +319,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
             ?expected_self_ty_has_vid,
         );
 
-        self.explain_actual_impl_that_was_found(
-            &mut err,
+        let actual_impl_expl_notes = self.explain_actual_impl_that_was_found(
             sub_placeholder,
             sup_placeholder,
             has_sub,
@@ -299,7 +333,15 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
             leading_ellipsis,
         );
 
-        err
+        self.tcx().sess.create_err(TraitPlaceholderMismatch {
+            span,
+            satisfy_span,
+            where_span,
+            dup_span,
+            def_id,
+            trait_def_id: self.tcx().def_path_str(trait_def_id),
+            actual_impl_expl_notes,
+        })
     }
 
     /// Add notes with details about the expected and actual trait refs, with attention to cases
@@ -309,7 +351,6 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
     /// due to the number of combinations we have to deal with.
     fn explain_actual_impl_that_was_found(
         &self,
-        err: &mut Diagnostic,
         sub_placeholder: Option<Region<'tcx>>,
         sup_placeholder: Option<Region<'tcx>>,
         has_sub: Option<usize>,
@@ -321,39 +362,7 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
         actual_has_vid: Option<usize>,
         any_self_ty_has_vid: bool,
         leading_ellipsis: bool,
-    ) {
-        // HACK(eddyb) maybe move this in a more central location.
-        #[derive(Copy, Clone)]
-        struct Highlighted<'tcx, T> {
-            tcx: TyCtxt<'tcx>,
-            highlight: RegionHighlightMode<'tcx>,
-            value: T,
-        }
-
-        impl<'tcx, T> Highlighted<'tcx, T> {
-            fn map<U>(self, f: impl FnOnce(T) -> U) -> Highlighted<'tcx, U> {
-                Highlighted { tcx: self.tcx, highlight: self.highlight, value: f(self.value) }
-            }
-        }
-
-        impl<'tcx, T> fmt::Display for Highlighted<'tcx, T>
-        where
-            T: for<'a> Print<
-                'tcx,
-                FmtPrinter<'a, 'tcx>,
-                Error = fmt::Error,
-                Output = FmtPrinter<'a, 'tcx>,
-            >,
-        {
-            fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-                let mut printer = ty::print::FmtPrinter::new(self.tcx, Namespace::TypeNS);
-                printer.region_highlight_mode = self.highlight;
-
-                let s = self.value.print(printer)?.into_buffer();
-                f.write_str(&s)
-            }
-        }
-
+    ) -> Vec<ActualImplExplNotes<'tcx>> {
         // The weird thing here with the `maybe_highlighting_region` calls and the
         // the match inside is meant to be like this:
         //
@@ -380,120 +389,110 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
         let mut expected_trait_ref = highlight_trait_ref(expected_trait_ref);
         expected_trait_ref.highlight.maybe_highlighting_region(sub_placeholder, has_sub);
         expected_trait_ref.highlight.maybe_highlighting_region(sup_placeholder, has_sup);
-        err.note(&{
-            let passive_voice = match (has_sub, has_sup) {
-                (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
-                (None, None) => {
-                    expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
-                    match expected_has_vid {
-                        Some(_) => true,
-                        None => any_self_ty_has_vid,
-                    }
-                }
-            };
 
-            let mut note = if same_self_type {
-                let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
-                self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
-
-                if self_ty.value.is_closure()
-                    && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
-                {
-                    let closure_sig = self_ty.map(|closure| {
-                        if let ty::Closure(_, substs) = closure.kind() {
-                            self.tcx().signature_unclosure(
-                                substs.as_closure().sig(),
-                                rustc_hir::Unsafety::Normal,
-                            )
-                        } else {
-                            bug!("type is not longer closure");
-                        }
-                    });
-
-                    format!(
-                        "{}closure with signature `{}` must implement `{}`",
-                        if leading_ellipsis { "..." } else { "" },
-                        closure_sig,
-                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    )
-                } else {
-                    format!(
-                        "{}`{}` must implement `{}`",
-                        if leading_ellipsis { "..." } else { "" },
-                        self_ty,
-                        expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    )
+        let passive_voice = match (has_sub, has_sup) {
+            (Some(_), _) | (_, Some(_)) => any_self_ty_has_vid,
+            (None, None) => {
+                expected_trait_ref.highlight.maybe_highlighting_region(vid, expected_has_vid);
+                match expected_has_vid {
+                    Some(_) => true,
+                    None => any_self_ty_has_vid,
                 }
-            } else if passive_voice {
-                format!(
-                    "{}`{}` would have to be implemented for the type `{}`",
-                    if leading_ellipsis { "..." } else { "" },
+            }
+        };
+
+        let (kind, ty_or_sig, trait_path) = if same_self_type {
+            let mut self_ty = expected_trait_ref.map(|tr| tr.self_ty());
+            self_ty.highlight.maybe_highlighting_region(vid, actual_has_vid);
+
+            if self_ty.value.is_closure() && self.tcx().is_fn_trait(expected_trait_ref.value.def_id)
+            {
+                let closure_sig = self_ty.map(|closure| {
+                    if let ty::Closure(_, substs) = closure.kind() {
+                        self.tcx().signature_unclosure(
+                            substs.as_closure().sig(),
+                            rustc_hir::Unsafety::Normal,
+                        )
+                    } else {
+                        bug!("type is not longer closure");
+                    }
+                });
+                (
+                    ActualImplExpectedKind::Signature,
+                    TyOrSig::ClosureSig(closure_sig),
                     expected_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    expected_trait_ref.map(|tr| tr.self_ty()),
                 )
             } else {
-                format!(
-                    "{}`{}` must implement `{}`",
-                    if leading_ellipsis { "..." } else { "" },
-                    expected_trait_ref.map(|tr| tr.self_ty()),
+                (
+                    ActualImplExpectedKind::Other,
+                    TyOrSig::Ty(self_ty),
                     expected_trait_ref.map(|tr| tr.print_only_trait_path()),
                 )
-            };
+            }
+        } else if passive_voice {
+            (
+                ActualImplExpectedKind::Passive,
+                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+            )
+        } else {
+            (
+                ActualImplExpectedKind::Other,
+                TyOrSig::Ty(expected_trait_ref.map(|tr| tr.self_ty())),
+                expected_trait_ref.map(|tr| tr.print_only_trait_path()),
+            )
+        };
 
-            match (has_sub, has_sup) {
-                (Some(n1), Some(n2)) => {
-                    let _ = write!(
-                        note,
-                        ", for any two lifetimes `'{}` and `'{}`...",
-                        std::cmp::min(n1, n2),
-                        std::cmp::max(n1, n2),
-                    );
-                }
-                (Some(n), _) | (_, Some(n)) => {
-                    let _ = write!(note, ", for any lifetime `'{}`...", n,);
-                }
-                (None, None) => {
-                    if let Some(n) = expected_has_vid {
-                        let _ = write!(note, ", for some specific lifetime `'{}`...", n,);
-                    }
+        let (lt_kind, lifetime_1, lifetime_2) = match (has_sub, has_sup) {
+            (Some(n1), Some(n2)) => {
+                (ActualImplExpectedLifetimeKind::Two, std::cmp::min(n1, n2), std::cmp::max(n1, n2))
+            }
+            (Some(n), _) | (_, Some(n)) => (ActualImplExpectedLifetimeKind::Any, n, 0),
+            (None, None) => {
+                if let Some(n) = expected_has_vid {
+                    (ActualImplExpectedLifetimeKind::Some, n, 0)
+                } else {
+                    (ActualImplExpectedLifetimeKind::Nothing, 0, 0)
                 }
             }
+        };
 
-            note
-        });
+        let note_1 = ActualImplExplNotes::new_expected(
+            kind,
+            lt_kind,
+            leading_ellipsis,
+            ty_or_sig,
+            trait_path,
+            lifetime_1,
+            lifetime_2,
+        );
 
         let mut actual_trait_ref = highlight_trait_ref(actual_trait_ref);
         actual_trait_ref.highlight.maybe_highlighting_region(vid, actual_has_vid);
-        err.note(&{
-            let passive_voice = match actual_has_vid {
-                Some(_) => any_self_ty_has_vid,
-                None => true,
-            };
 
-            let mut note = if same_self_type {
-                format!(
-                    "...but it actually implements `{}`",
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                )
-            } else if passive_voice {
-                format!(
-                    "...but `{}` is actually implemented for the type `{}`",
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                    actual_trait_ref.map(|tr| tr.self_ty()),
-                )
-            } else {
-                format!(
-                    "...but `{}` actually implements `{}`",
-                    actual_trait_ref.map(|tr| tr.self_ty()),
-                    actual_trait_ref.map(|tr| tr.print_only_trait_path()),
-                )
-            };
+        let passive_voice = match actual_has_vid {
+            Some(_) => any_self_ty_has_vid,
+            None => true,
+        };
 
-            if let Some(n) = actual_has_vid {
-                let _ = write!(note, ", for some specific lifetime `'{}`", n);
+        let trait_path = actual_trait_ref.map(|tr| tr.print_only_trait_path());
+        let ty = actual_trait_ref.map(|tr| tr.self_ty()).to_string();
+        let has_lifetime = actual_has_vid.is_some();
+        let lifetime = actual_has_vid.unwrap_or_default();
+
+        let note_2 = if same_self_type {
+            ActualImplExplNotes::ButActuallyImplementsTrait { trait_path, has_lifetime, lifetime }
+        } else if passive_voice {
+            ActualImplExplNotes::ButActuallyImplementedForTy {
+                trait_path,
+                ty,
+                has_lifetime,
+                lifetime,
             }
+        } else {
+            ActualImplExplNotes::ButActuallyTyImplements { trait_path, ty, has_lifetime, lifetime }
+        };
 
-            note
-        });
+        vec![note_1, note_2]
     }
 }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 9bd2202d260..fb0f09198cc 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -1,20 +1,28 @@
 //! Error Reporting for static impl Traits.
 
+use crate::errors::{
+    ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
+    ReqIntroducedLocations,
+};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
 use crate::infer::{SubregionOrigin, TypeTrace};
 use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{struct_span_err, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{walk_ty, Visitor};
-use rustc_hir::{self as hir, GenericBound, Item, ItemKind, Lifetime, LifetimeName, Node, TyKind};
+use rustc_hir::{
+    self as hir, GenericBound, GenericParamKind, Item, ItemKind, Lifetime, LifetimeName, Node,
+    TyKind,
+};
 use rustc_middle::ty::{
     self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
 };
 use rustc_span::symbol::Ident;
 use rustc_span::Span;
 
+use rustc_span::def_id::LocalDefId;
 use std::ops::ControlFlow;
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
@@ -49,46 +57,32 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                     }
 
                     let param = self.find_param_with_region(*sup_r, *sub_r)?;
-                    let lifetime = if sup_r.has_name() {
-                        format!("lifetime `{}`", sup_r)
-                    } else {
-                        "an anonymous lifetime `'_`".to_string()
+                    let simple_ident = param.param.pat.simple_ident();
+
+                    let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
+                        AssocItemContainer::TraitContainer => {
+                            let id = ctxt.assoc_item.container_id(tcx);
+                            (true, tcx.def_path_str(id))
+                        }
+                        AssocItemContainer::ImplContainer => (false, String::new()),
                     };
-                    let mut err = struct_span_err!(
-                        tcx.sess,
-                        cause.span,
-                        E0772,
-                        "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
-                         requirement",
-                        param
-                            .param
-                            .pat
-                            .simple_ident()
-                            .map(|s| format!("`{}`", s))
-                            .unwrap_or_else(|| "`fn` parameter".to_string()),
-                        lifetime,
-                        ctxt.assoc_item.name,
-                    );
-                    err.span_label(param.param_ty_span, &format!("this data with {}...", lifetime));
-                    err.span_label(
-                        cause.span,
-                        &format!(
-                            "...is used and required to live as long as `'static` here \
-                             because of an implicit lifetime bound on the {}",
-                            match ctxt.assoc_item.container {
-                                AssocItemContainer::TraitContainer => {
-                                    let id = ctxt.assoc_item.container_id(tcx);
-                                    format!("`impl` of `{}`", tcx.def_path_str(id))
-                                }
-                                AssocItemContainer::ImplContainer => "inherent `impl`".to_string(),
-                            },
-                        ),
-                    );
+
+                    let mut err = self.tcx().sess.create_err(ButCallingIntroduces {
+                        param_ty_span: param.param_ty_span,
+                        cause_span: cause.span,
+                        has_param_name: simple_ident.is_some(),
+                        param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
+                        has_lifetime: sup_r.has_name(),
+                        lifetime: sup_r.to_string(),
+                        assoc_item: ctxt.assoc_item.name,
+                        has_impl_path,
+                        impl_path,
+                    });
                     if self.find_impl_on_dyn_trait(&mut err, param.param_ty, &ctxt) {
                         let reported = err.emit();
                         return Some(reported);
                     } else {
-                        err.cancel();
+                        err.cancel()
                     }
                 }
                 return None;
@@ -104,25 +98,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let sp = var_origin.span();
         let return_sp = sub_origin.span();
         let param = self.find_param_with_region(*sup_r, *sub_r)?;
-        let (lifetime_name, lifetime) = if sup_r.has_name() {
-            (sup_r.to_string(), format!("lifetime `{}`", sup_r))
-        } else {
-            ("'_".to_owned(), "an anonymous lifetime `'_`".to_string())
-        };
-        let param_name = param
-            .param
-            .pat
-            .simple_ident()
-            .map(|s| format!("`{}`", s))
-            .unwrap_or_else(|| "`fn` parameter".to_string());
-        let mut err = struct_span_err!(
-            tcx.sess,
-            sp,
-            E0759,
-            "{} has {} but it needs to satisfy a `'static` lifetime requirement",
-            param_name,
-            lifetime,
-        );
+        let lifetime_name = if sup_r.has_name() { sup_r.to_string() } else { "'_".to_owned() };
 
         let (mention_influencer, influencer_point) =
             if sup_origin.span().overlaps(param.param_ty_span) {
@@ -141,7 +117,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             } else {
                 (!sup_origin.span().overlaps(return_sp), param.param_ty_span)
             };
-        err.span_label(influencer_point, &format!("this data with {}...", lifetime));
 
         debug!("try_report_static_impl_trait: param_info={:?}", param);
 
@@ -155,31 +130,19 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         spans.dedup_by_key(|span| (span.lo(), span.hi()));
 
         // We try to make the output have fewer overlapping spans if possible.
-        let require_msg = if spans.is_empty() {
-            "...is used and required to live as long as `'static` here"
-        } else {
-            "...and is required to live as long as `'static` here"
-        };
         let require_span =
             if sup_origin.span().overlaps(return_sp) { sup_origin.span() } else { return_sp };
 
-        for span in &spans {
-            err.span_label(*span, "...is used here...");
-        }
-
-        if spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp) {
-            // If any of the "captured here" labels appears on the same line or after
-            // `require_span`, we put it on a note to ensure the text flows by appearing
-            // always at the end.
-            err.span_note(require_span, require_msg);
+        let spans_empty = spans.is_empty();
+        let require_as_note = spans.iter().any(|sp| sp.overlaps(return_sp) || *sp > return_sp);
+        let bound = if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
+            Some(*bound)
         } else {
-            // We don't need a note, it's already at the end, it can be shown as a `span_label`.
-            err.span_label(require_span, require_msg);
-        }
+            None
+        };
+
+        let mut subdiag = None;
 
-        if let SubregionOrigin::RelateParamBound(_, _, Some(bound)) = sub_origin {
-            err.span_note(*bound, "`'static` lifetime requirement introduced by this bound");
-        }
         if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
             if let ObligationCauseCode::ReturnValue(hir_id)
             | ObligationCauseCode::BlockTailExpression(hir_id) = cause.code()
@@ -187,33 +150,50 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 let parent_id = tcx.hir().get_parent_item(*hir_id);
                 if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
                     let mut span: MultiSpan = fn_decl.output.span().into();
+                    let mut spans = Vec::new();
                     let mut add_label = true;
                     if let hir::FnRetTy::Return(ty) = fn_decl.output {
                         let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
                         v.visit_ty(ty);
                         if !v.0.is_empty() {
                             span = v.0.clone().into();
-                            for sp in v.0 {
-                                span.push_span_label(sp, "`'static` requirement introduced here");
-                            }
+                            spans = v.0;
                             add_label = false;
                         }
                     }
-                    if add_label {
-                        span.push_span_label(
-                            fn_decl.output.span(),
-                            "requirement introduced by this return type",
-                        );
-                    }
-                    span.push_span_label(cause.span, "because of this returned expression");
-                    err.span_note(
+                    let fn_decl_span = fn_decl.output.span();
+
+                    subdiag = Some(ReqIntroducedLocations {
                         span,
-                        "`'static` lifetime requirement introduced by the return type",
-                    );
+                        spans,
+                        fn_decl_span,
+                        cause_span: cause.span,
+                        add_label,
+                    });
                 }
             }
         }
 
+        let diag = ButNeedsToSatisfy {
+            sp,
+            influencer_point,
+            spans: spans.clone(),
+            // If any of the "captured here" labels appears on the same line or after
+            // `require_span`, we put it on a note to ensure the text flows by appearing
+            // always at the end.
+            require_span_as_note: require_as_note.then_some(require_span),
+            // We don't need a note, it's already at the end, it can be shown as a `span_label`.
+            require_span_as_label: (!require_as_note).then_some(require_span),
+            req_introduces_loc: subdiag,
+
+            has_lifetime: sup_r.has_name(),
+            lifetime: sup_r.to_string(),
+            spans_empty,
+            bound,
+        };
+
+        let mut err = self.tcx().sess.create_err(diag);
+
         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id);
 
         let mut override_error_code = None;
@@ -239,7 +219,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             let mut v = TraitObjectVisitor(FxIndexSet::default());
             v.visit_ty(param.param_ty);
             if let Some((ident, self_ty)) =
-                self.get_impl_ident_and_self_ty_from_trait(item_def_id, &v.0)
+                NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
                 && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
             {
                 override_error_code = Some(ident.name);
@@ -247,12 +227,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         }
         if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
             // Provide a more targeted error code and description.
-            err.code(rustc_errors::error_code!(E0772));
-            err.set_primary_message(&format!(
-                "{} has {} but calling `{}` introduces an implicit `'static` lifetime \
-                requirement",
-                param_name, lifetime, ident,
-            ));
+            let retarget_subdiag = MoreTargeted { ident };
+            retarget_subdiag.add_to_diagnostic(&mut err);
         }
 
         let arg = match param.param.pat.simple_ident() {
@@ -268,6 +244,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             Some(arg),
             captures,
             Some((param.param_ty_span, param.param_ty.to_string())),
+            Some(anon_reg_sup.def_id),
         );
 
         let reported = err.emit();
@@ -283,6 +260,7 @@ pub fn suggest_new_region_bound(
     arg: Option<String>,
     captures: String,
     param: Option<(Span, String)>,
+    scope_def_id: Option<LocalDefId>,
 ) {
     debug!("try_report_static_impl_trait: fn_return={:?}", fn_returns);
     // FIXME: account for the need of parens in `&(dyn Trait + '_)`
@@ -309,19 +287,12 @@ pub fn suggest_new_region_bound(
                 let did = item_id.owner_id.to_def_id();
                 let ty = tcx.mk_opaque(did, ty::InternalSubsts::identity_for_item(tcx, did));
 
-                if let Some(span) = opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime {
-                            res: LifetimeName::Static,
-                            ident,
-                            ..
-                        }) => Some(ident.span),
-                        _ => None,
-                    })
-                    .next()
-                {
+                if let Some(span) = opaque.bounds.iter().find_map(|arg| match arg {
+                    GenericBound::Outlives(Lifetime {
+                        res: LifetimeName::Static, ident, ..
+                    }) => Some(ident.span),
+                    _ => None,
+                }) {
                     if let Some(explicit_static) = &explicit_static {
                         err.span_suggestion_verbose(
                             span,
@@ -338,27 +309,78 @@ pub fn suggest_new_region_bound(
                             Applicability::MaybeIncorrect,
                         );
                     }
-                } else if opaque
-                    .bounds
-                    .iter()
-                    .filter_map(|arg| match arg {
-                        GenericBound::Outlives(Lifetime { ident, .. })
-                            if ident.name.to_string() == lifetime_name =>
-                        {
-                            Some(ident.span)
-                        }
-                        _ => None,
-                    })
-                    .next()
-                    .is_some()
-                {
+                } else if opaque.bounds.iter().any(|arg| match arg {
+                    GenericBound::Outlives(Lifetime { ident, .. })
+                        if ident.name.to_string() == lifetime_name =>
+                    {
+                        true
+                    }
+                    _ => false,
+                }) {
                 } else {
-                    err.span_suggestion_verbose(
-                        fn_return.span.shrink_to_hi(),
-                        &format!("{declare} `{ty}` {captures}, {explicit}",),
-                        &plus_lt,
-                        Applicability::MaybeIncorrect,
-                    );
+                    // get a lifetime name of existing named lifetimes if any
+                    let existing_lt_name = if let Some(id) = scope_def_id
+                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let named_lifetimes = generics
+                        .params
+                        .iter()
+                        .filter(|p| matches!(p.kind, GenericParamKind::Lifetime { kind: hir::LifetimeParamKind::Explicit }))
+                        .map(|p| { if let hir::ParamName::Plain(name) = p.name {Some(name.to_string())} else {None}})
+                        .filter(|n| ! matches!(n, None))
+                        .collect::<Vec<_>>()
+                        && named_lifetimes.len() > 0 {
+                        named_lifetimes[0].clone()
+                    } else {
+                        None
+                    };
+                    let name = if let Some(name) = &existing_lt_name {
+                        format!("{}", name)
+                    } else {
+                        format!("'a")
+                    };
+                    // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
+                    // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
+                    if let Some(id) = scope_def_id
+                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let mut spans_suggs = generics
+                            .params
+                            .iter()
+                            .filter(|p| p.is_elided_lifetime())
+                            .map(|p|
+                                  if p.span.hi() - p.span.lo() == rustc_span::BytePos(1) { // Ampersand (elided without '_)
+                                      (p.span.shrink_to_hi(),format!("{name} "))
+                                  } else { // Underscore (elided with '_)
+                                      (p.span, format!("{name}"))
+                                  }
+                            )
+                            .collect::<Vec<_>>()
+                        && spans_suggs.len() > 1
+                    {
+                        let use_lt =
+                        if existing_lt_name == None {
+                            spans_suggs.push((generics.span.shrink_to_hi(), format!("<{name}>")));
+                            format!("you can introduce a named lifetime parameter `{name}`")
+                        } else {
+                            // make use the existing named lifetime
+                            format!("you can use the named lifetime parameter `{name}`")
+                        };
+                        spans_suggs
+                            .push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
+                        err.multipart_suggestion_verbose(
+                            &format!(
+                                "{declare} `{ty}` {captures}, {use_lt}",
+                            ),
+                            spans_suggs,
+                            Applicability::MaybeIncorrect,
+                        );
+                    } else {
+                        err.span_suggestion_verbose(
+                            fn_return.span.shrink_to_hi(),
+                            &format!("{declare} `{ty}` {captures}, {explicit}",),
+                            &plus_lt,
+                            Applicability::MaybeIncorrect,
+                        );
+                    }
                 }
             }
             TyKind::TraitObject(_, lt, _) => {
@@ -403,66 +425,54 @@ pub fn suggest_new_region_bound(
 }
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
-    fn get_impl_ident_and_self_ty_from_trait(
-        &self,
+    pub fn get_impl_ident_and_self_ty_from_trait(
+        tcx: TyCtxt<'tcx>,
         def_id: DefId,
         trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        let tcx = self.tcx();
-        match tcx.hir().get_if_local(def_id) {
-            Some(Node::ImplItem(impl_item)) => {
-                match tcx.hir().find_by_def_id(tcx.hir().get_parent_item(impl_item.hir_id()).def_id)
+        match tcx.hir().get_if_local(def_id)? {
+            Node::ImplItem(impl_item) => {
+                let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+                if let hir::OwnerNode::Item(Item {
+                    kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                    ..
+                }) = tcx.hir().owner(impl_did)
                 {
-                    Some(Node::Item(Item {
-                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                        ..
-                    })) => Some((impl_item.ident, self_ty)),
-                    _ => None,
+                    Some((impl_item.ident, self_ty))
+                } else {
+                    None
                 }
             }
-            Some(Node::TraitItem(trait_item)) => {
-                let trait_did = tcx.hir().get_parent_item(trait_item.hir_id());
-                match tcx.hir().find_by_def_id(trait_did.def_id) {
-                    Some(Node::Item(Item { kind: ItemKind::Trait(..), .. })) => {
-                        // The method being called is defined in the `trait`, but the `'static`
-                        // obligation comes from the `impl`. Find that `impl` so that we can point
-                        // at it in the suggestion.
-                        let trait_did = trait_did.to_def_id();
-                        match tcx
-                            .hir()
-                            .trait_impls(trait_did)
-                            .iter()
-                            .filter_map(|&impl_did| {
-                                match tcx.hir().get_if_local(impl_did.to_def_id()) {
-                                    Some(Node::Item(Item {
-                                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
-                                        ..
-                                    })) if trait_objects.iter().all(|did| {
-                                        // FIXME: we should check `self_ty` against the receiver
-                                        // type in the `UnifyReceiver` context, but for now, use
-                                        // this imperfect proxy. This will fail if there are
-                                        // multiple `impl`s for the same trait like
-                                        // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
-                                        // In that case, only the first one will get suggestions.
-                                        let mut traits = vec![];
-                                        let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
-                                        hir_v.visit_ty(self_ty);
-                                        !traits.is_empty()
-                                    }) =>
-                                    {
-                                        Some(self_ty)
-                                    }
-                                    _ => None,
-                                }
-                            })
-                            .next()
-                        {
-                            Some(self_ty) => Some((trait_item.ident, self_ty)),
-                            _ => None,
-                        }
+            Node::TraitItem(trait_item) => {
+                let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+                debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
+                // The method being called is defined in the `trait`, but the `'static`
+                // obligation comes from the `impl`. Find that `impl` so that we can point
+                // at it in the suggestion.
+                let trait_did = trait_id.to_def_id();
+                tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+                    if let Node::Item(Item {
+                        kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
+                        ..
+                    }) = tcx.hir().find_by_def_id(impl_did)?
+                        && trait_objects.iter().all(|did| {
+                            // FIXME: we should check `self_ty` against the receiver
+                            // type in the `UnifyReceiver` context, but for now, use
+                            // this imperfect proxy. This will fail if there are
+                            // multiple `impl`s for the same trait like
+                            // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
+                            // In that case, only the first one will get suggestions.
+                            let mut traits = vec![];
+                            let mut hir_v = HirTraitObjectVisitor(&mut traits, *did);
+                            hir_v.visit_ty(self_ty);
+                            !traits.is_empty()
+                        })
+                    {
+                        Some((trait_item.ident, *self_ty))
+                    } else {
+                        None
                     }
-                    _ => None,
-                }
+                })
             }
             _ => None,
         }
@@ -493,7 +503,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
         // Get the `Ident` of the method being called and the corresponding `impl` (to point at
         // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
-        let Some((ident, self_ty)) = self.get_impl_ident_and_self_ty_from_trait(instance.def_id(), &v.0) else {
+        let Some((ident, self_ty)) = NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0) else {
             return false;
         };
 
@@ -513,21 +523,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             let mut traits = vec![];
             let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
             hir_v.visit_ty(&self_ty);
-            for span in &traits {
-                let mut multi_span: MultiSpan = vec![*span].into();
-                multi_span
-                    .push_span_label(*span, "this has an implicit `'static` lifetime requirement");
-                multi_span.push_span_label(
-                    ident.span,
-                    "calling this method introduces the `impl`'s 'static` requirement",
-                );
-                err.span_note(multi_span, "the used `impl` has a `'static` requirement");
-                err.span_suggestion_verbose(
-                    span.shrink_to_hi(),
-                    "consider relaxing the implicit `'static` requirement",
-                    " + '_",
-                    Applicability::MaybeIncorrect,
-                );
+            for &span in &traits {
+                let subdiag = DynTraitConstraintSuggestion { span, ident };
+                subdiag.add_to_diagnostic(err);
                 suggested = true;
             }
         }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 5d536e982ed..40c0c806e1f 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -1,15 +1,17 @@
 //! Error Reporting for `impl` items that do not match the obligations from their `trait`.
 
+use crate::errors::{ConsiderBorrowingParamHelp, RelationshipHelp, TraitImplDiff};
 use crate::infer::error_reporting::nice_region_error::NiceRegionError;
 use crate::infer::lexical_region_resolve::RegionResolutionError;
-use crate::infer::Subtype;
+use crate::infer::{Subtype, ValuePairs};
 use crate::traits::ObligationCauseCode::CompareImplItemObligation;
-use rustc_errors::{ErrorGuaranteed, MultiSpan};
+use rustc_errors::ErrorGuaranteed;
 use rustc_hir as hir;
 use rustc_hir::def::Res;
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::Visitor;
 use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::error::ExpectedFound;
 use rustc_middle::ty::print::RegionHighlightMode;
 use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::Span;
@@ -22,22 +24,27 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let error = self.error.as_ref()?;
         debug!("try_report_impl_not_conforming_to_trait {:?}", error);
         if let RegionResolutionError::SubSupConflict(
-                _,
-                var_origin,
-                sub_origin,
-                _sub,
-                sup_origin,
-                _sup,
-                _,
-            ) = error.clone()
+            _,
+            var_origin,
+            sub_origin,
+            _sub,
+            sup_origin,
+            _sup,
+            _,
+        ) = error.clone()
             && let (Subtype(sup_trace), Subtype(sub_trace)) = (&sup_origin, &sub_origin)
-            && let sub_expected_found @ Some((sub_expected, sub_found)) = sub_trace.values.ty()
-            && let sup_expected_found @ Some(_) = sup_trace.values.ty()
             && let CompareImplItemObligation { trait_item_def_id, .. } = sub_trace.cause.code()
-            && sup_expected_found == sub_expected_found
+            && sub_trace.values == sup_trace.values
+            && let ValuePairs::Sigs(ExpectedFound { expected, found }) = sub_trace.values
         {
-            let guar =
-                self.emit_err(var_origin.span(), sub_expected, sub_found, *trait_item_def_id);
+            // FIXME(compiler-errors): Don't like that this needs `Ty`s, but
+            // all of the region highlighting machinery only deals with those.
+            let guar = self.emit_err(
+                var_origin.span(),
+                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(expected)),
+                self.cx.tcx.mk_fn_ptr(ty::Binder::dummy(found)),
+                *trait_item_def_id,
+            );
             return Some(guar);
         }
         None
@@ -51,10 +58,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         trait_def_id: DefId,
     ) -> ErrorGuaranteed {
         let trait_sp = self.tcx().def_span(trait_def_id);
-        let mut err = self
-            .tcx()
-            .sess
-            .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature");
 
         // Mark all unnamed regions in the type with a number.
         // This diagnostic is called in response to lifetime errors, so be informative.
@@ -91,9 +94,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let found =
             self.cx.extract_inference_diagnostics_data(found.into(), Some(found_highlight)).name;
 
-        err.span_label(sp, &format!("found `{}`", found));
-        err.span_label(trait_sp, &format!("expected `{}`", expected));
-
         // Get the span of all the used type parameters in the method.
         let assoc_item = self.tcx().associated_item(trait_def_id);
         let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
@@ -110,26 +110,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             }
             _ => {}
         }
-        let mut type_param_span: MultiSpan = visitor.types.to_vec().into();
-        for &span in &visitor.types {
-            type_param_span
-                .push_span_label(span, "consider borrowing this type parameter in the trait");
-        }
 
-        err.note(&format!("expected `{}`\n   found `{}`", expected, found));
-
-        err.span_help(
-            type_param_span,
-            "the lifetime requirements from the `impl` do not correspond to the requirements in \
-             the `trait`",
-        );
-        if visitor.types.is_empty() {
-            err.help(
-                "verify the lifetime relationships in the `trait` and `impl` between the `self` \
-                 argument, the other inputs and its output",
-            );
-        }
-        err.emit()
+        let diag = TraitImplDiff {
+            sp,
+            trait_sp,
+            note: (),
+            param_help: ConsiderBorrowingParamHelp { spans: visitor.types.to_vec() },
+            rel_help: visitor.types.is_empty().then_some(RelationshipHelp),
+            expected,
+            found,
+        };
+
+        self.tcx().sess.emit_err(diag)
     }
 }
 
@@ -147,7 +139,7 @@ impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx>) {
         match arg.kind {
-            hir::TyKind::Rptr(_, ref mut_ty) => {
+            hir::TyKind::Ref(_, ref mut_ty) => {
                 // We don't want to suggest looking into borrowing `&T` or `&Self`.
                 hir::intravisit::walk_ty(self, mut_ty.ty);
                 return;
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs
index d2dffa4a0b7..7bb79d7bda8 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note.rs
@@ -2,11 +2,14 @@ use crate::errors::RegionOriginNote;
 use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
 use crate::infer::{self, SubregionOrigin};
 use rustc_errors::{
-    fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
+    fluent, struct_span_err, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder,
+    ErrorGuaranteed,
 };
+use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_middle::traits::ObligationCauseCode;
 use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
+use rustc_middle::ty::{self, IsSuggestable, Region};
+use rustc_span::symbol::kw;
 
 use super::ObligationCauseAsDiagArg;
 
@@ -22,16 +25,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             infer::Reborrow(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
             }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reborrow,
-                    name: &var_name.to_string(),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
             infer::RelateObjectBound(span) => {
                 RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
                     .add_to_diagnostic(err);
@@ -159,33 +152,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 err
             }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0313,
-                    "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
-                    var_name
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the borrowed pointer is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    &format!("...but `{}` is only valid for ", var_name),
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
             infer::RelateObjectBound(span) => {
                 let mut err = struct_span_err!(
                     self.tcx.sess,
@@ -313,55 +279,38 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                 );
                 err
             }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
-                .report_extra_impl_obligation(
+            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => {
+                let mut err = self.report_extra_impl_obligation(
                     span,
                     impl_item_def_id,
                     trait_item_def_id,
                     &format!("`{}: {}`", sup, sub),
-                ),
+                );
+                // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
+                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+                    && generics.where_clause_span.contains(span)
+                {
+                    self.suggest_copy_trait_method_bounds(
+                        trait_item_def_id,
+                        impl_item_def_id,
+                        &mut err,
+                    );
+                }
+                err
+            }
             infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
                 let mut err = self.report_concrete_failure(*parent, sub, sup);
-
                 let trait_item_span = self.tcx.def_span(trait_item_def_id);
                 let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
                 err.span_label(
                     trait_item_span,
                     format!("definition of `{}` from trait", item_name),
                 );
-
-                let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
-                let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
-                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
-                    impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
-                let clauses: Vec<_> = trait_predicates
-                    .predicates
-                    .into_iter()
-                    .filter(|&(pred, _)| !impl_predicates.contains(pred))
-                    .map(|(pred, _)| format!("{}", pred))
-                    .collect();
-
-                if !clauses.is_empty() {
-                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
-                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
-                    let suggestion = format!(
-                        "{} {}",
-                        generics.add_where_or_trailing_comma(),
-                        clauses.join(", "),
-                    );
-                    err.span_suggestion(
-                        where_clause_span,
-                        &format!(
-                            "try copying {} from the trait",
-                            if clauses.len() > 1 { "these clauses" } else { "this clause" }
-                        ),
-                        suggestion,
-                        rustc_errors::Applicability::MaybeIncorrect,
-                    );
-                }
-
+                self.suggest_copy_trait_method_bounds(
+                    trait_item_def_id,
+                    impl_item_def_id,
+                    &mut err,
+                );
                 err
             }
             infer::AscribeUserTypeProvePredicate(span) => {
@@ -388,6 +337,65 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
+    pub fn suggest_copy_trait_method_bounds(
+        &self,
+        trait_item_def_id: DefId,
+        impl_item_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    ) {
+        // FIXME(compiler-errors): Right now this is only being used for region
+        // predicate mismatches. Ideally, we'd use it for *all* predicate mismatches,
+        // but right now it's not really very smart when it comes to implicit `Sized`
+        // predicates and bounds on the trait itself.
+
+        let Some(impl_def_id) =
+            self.tcx.associated_item(impl_item_def_id).impl_container(self.tcx) else { return; };
+        let Some(trait_ref) = self
+            .tcx
+            .impl_trait_ref(impl_def_id)
+            else { return; };
+        let trait_substs = trait_ref
+            // Replace the explicit self type with `Self` for better suggestion rendering
+            .with_self_ty(self.tcx, self.tcx.mk_ty_param(0, kw::SelfUpper))
+            .substs;
+        let trait_item_substs =
+            ty::InternalSubsts::identity_for_item(self.tcx, impl_item_def_id.to_def_id())
+                .rebase_onto(self.tcx, impl_def_id, trait_substs);
+
+        let Ok(trait_predicates) = self
+            .tcx
+            .bound_explicit_predicates_of(trait_item_def_id)
+            .map_bound(|p| p.predicates)
+            .subst_iter_copied(self.tcx, trait_item_substs)
+            .map(|(pred, _)| {
+                if pred.is_suggestable(self.tcx, false) {
+                    Ok(pred.to_string())
+                } else {
+                    Err(())
+                }
+            })
+            .collect::<Result<Vec<_>, ()>>() else { return; };
+
+        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else { return; };
+
+        if trait_predicates.is_empty() {
+            err.span_suggestion_verbose(
+                generics.where_clause_span,
+                "remove the `where` clause",
+                String::new(),
+                Applicability::MachineApplicable,
+            );
+        } else {
+            let space = if generics.where_clause_span.is_empty() { " " } else { "" };
+            err.span_suggestion_verbose(
+                generics.where_clause_span,
+                "copy the `where` clause predicates from the trait",
+                format!("{space}where {}", trait_predicates.join(", ")),
+                Applicability::MachineApplicable,
+            );
+        }
+    }
+
     pub(super) fn report_placeholder_failure(
         &self,
         placeholder_origin: SubregionOrigin<'tcx>,
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs b/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
deleted file mode 100644
index 41b115f3377..00000000000
--- a/compiler/rustc_infer/src/infer/error_reporting/note_region.rs
+++ /dev/null
@@ -1,427 +0,0 @@
-use crate::errors::RegionOriginNote;
-use crate::infer::error_reporting::{note_and_explain_region, TypeErrCtxt};
-use crate::infer::{self, SubregionOrigin};
-use rustc_errors::{
-    fluent, struct_span_err, AddToDiagnostic, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
-};
-use rustc_middle::traits::ObligationCauseCode;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::{self, Region};
-
-use super::ObligationCauseAsDiagArg;
-
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    pub(super) fn note_region_origin(&self, err: &mut Diagnostic, origin: &SubregionOrigin<'tcx>) {
-        match *origin {
-            infer::Subtype(ref trace) => RegionOriginNote::WithRequirement {
-                span: trace.cause.span,
-                requirement: ObligationCauseAsDiagArg(trace.cause.clone()),
-                expected_found: self.values_str(trace.values),
-            }
-            .add_to_diagnostic(err),
-            infer::Reborrow(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_reborrow }.add_to_diagnostic(err)
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reborrow,
-                    name: &var_name.to_string(),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::RelateObjectBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_object_bound }
-                    .add_to_diagnostic(err);
-            }
-            infer::DataBorrowed(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_data_borrowed,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_reference_outlives_referent,
-                    name: &self.ty_to_string(ty),
-                    continues: false,
-                }
-                .add_to_diagnostic(err);
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                RegionOriginNote::WithName {
-                    span,
-                    msg: fluent::infer_relate_param_bound,
-                    name: &self.ty_to_string(ty),
-                    continues: opt_span.is_some(),
-                }
-                .add_to_diagnostic(err);
-                if let Some(span) = opt_span {
-                    RegionOriginNote::Plain { span, msg: fluent::infer_relate_param_bound_2 }
-                        .add_to_diagnostic(err);
-                }
-            }
-            infer::RelateRegionParamBound(span) => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_relate_region_param_bound }
-                    .add_to_diagnostic(err);
-            }
-            infer::CompareImplItemObligation { span, .. } => {
-                RegionOriginNote::Plain { span, msg: fluent::infer_compare_impl_item_obligation }
-                    .add_to_diagnostic(err);
-            }
-            infer::CheckAssociatedTypeBounds { ref parent, .. } => {
-                self.note_region_origin(err, &parent);
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                RegionOriginNote::Plain {
-                    span,
-                    msg: fluent::infer_ascribe_user_type_prove_predicate,
-                }
-                .add_to_diagnostic(err);
-            }
-        }
-    }
-
-    pub(super) fn report_concrete_failure(
-        &self,
-        origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        match origin {
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsDoesNotOutlive(sup, sub);
-                let mut err = self.report_and_explain_type_error(trace, terr);
-                match (*sub, *sup) {
-                    (ty::RePlaceholder(_), ty::RePlaceholder(_)) => {}
-                    (ty::RePlaceholder(_), _) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "",
-                            sup,
-                            " doesn't meet the lifetime requirements",
-                            None,
-                        );
-                    }
-                    (_, ty::RePlaceholder(_)) => {
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "the required lifetime does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                    _ => {
-                        note_and_explain_region(self.tcx, &mut err, "", sup, "...", None);
-                        note_and_explain_region(
-                            self.tcx,
-                            &mut err,
-                            "...does not necessarily outlive ",
-                            sub,
-                            "",
-                            None,
-                        );
-                    }
-                }
-                err
-            }
-            infer::Reborrow(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0312,
-                    "lifetime of reference outlives lifetime of borrowed content..."
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the reference is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...but the borrowed content is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::ReborrowUpvar(span, ref upvar_id) => {
-                let var_name = self.tcx.hir().name(upvar_id.var_path.hir_id);
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0313,
-                    "lifetime of borrowed pointer outlives lifetime of captured variable `{}`...",
-                    var_name
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "...the borrowed pointer is valid for ",
-                    sub,
-                    "...",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    &format!("...but `{}` is only valid for ", var_name),
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::RelateObjectBound(span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0476,
-                    "lifetime of the source pointer does not outlive lifetime bound of the \
-                     object type"
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "object type is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "source pointer is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::RelateParamBound(span, ty, opt_span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0477,
-                    "the type `{}` does not fulfill the required lifetime",
-                    self.ty_to_string(ty)
-                );
-                match *sub {
-                    ty::ReStatic => note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "type must satisfy ",
-                        sub,
-                        if opt_span.is_some() { " as required by this binding" } else { "" },
-                        opt_span,
-                    ),
-                    _ => note_and_explain_region(
-                        self.tcx,
-                        &mut err,
-                        "type must outlive ",
-                        sub,
-                        if opt_span.is_some() { " as required by this binding" } else { "" },
-                        opt_span,
-                    ),
-                }
-                err
-            }
-            infer::RelateRegionParamBound(span) => {
-                let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "lifetime parameter instantiated with ",
-                    sup,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but lifetime parameter must outlive ",
-                    sub,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::DataBorrowed(ty, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0490,
-                    "a value of type `{}` is borrowed for too long",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the type is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but the borrow lasts for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::ReferenceOutlivesReferent(ty, span) => {
-                let mut err = struct_span_err!(
-                    self.tcx.sess,
-                    span,
-                    E0491,
-                    "in type `{}`, reference has a longer lifetime than the data it references",
-                    self.ty_to_string(ty)
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "the pointer is valid for ",
-                    sub,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but the referenced data is only valid for ",
-                    sup,
-                    "",
-                    None,
-                );
-                err
-            }
-            infer::CompareImplItemObligation { span, impl_item_def_id, trait_item_def_id } => self
-                .report_extra_impl_obligation(
-                    span,
-                    impl_item_def_id,
-                    trait_item_def_id,
-                    &format!("`{}: {}`", sup, sub),
-                ),
-            infer::CheckAssociatedTypeBounds { impl_item_def_id, trait_item_def_id, parent } => {
-                let mut err = self.report_concrete_failure(*parent, sub, sup);
-
-                let trait_item_span = self.tcx.def_span(trait_item_def_id);
-                let item_name = self.tcx.item_name(impl_item_def_id.to_def_id());
-                err.span_label(
-                    trait_item_span,
-                    format!("definition of `{}` from trait", item_name),
-                );
-
-                let trait_predicates = self.tcx.explicit_predicates_of(trait_item_def_id);
-                let impl_predicates = self.tcx.explicit_predicates_of(impl_item_def_id);
-
-                let impl_predicates: rustc_data_structures::fx::FxHashSet<_> =
-                    impl_predicates.predicates.into_iter().map(|(pred, _)| pred).collect();
-                let clauses: Vec<_> = trait_predicates
-                    .predicates
-                    .into_iter()
-                    .filter(|&(pred, _)| !impl_predicates.contains(pred))
-                    .map(|(pred, _)| format!("{}", pred))
-                    .collect();
-
-                if !clauses.is_empty() {
-                    let generics = self.tcx.hir().get_generics(impl_item_def_id).unwrap();
-                    let where_clause_span = generics.tail_span_for_predicate_suggestion();
-
-                    let suggestion = format!(
-                        "{} {}",
-                        generics.add_where_or_trailing_comma(),
-                        clauses.join(", "),
-                    );
-                    err.span_suggestion(
-                        where_clause_span,
-                        &format!(
-                            "try copying {} from the trait",
-                            if clauses.len() > 1 { "these clauses" } else { "this clause" }
-                        ),
-                        suggestion,
-                        rustc_errors::Applicability::MaybeIncorrect,
-                    );
-                }
-
-                err
-            }
-            infer::AscribeUserTypeProvePredicate(span) => {
-                let mut err =
-                    struct_span_err!(self.tcx.sess, span, E0478, "lifetime bound not satisfied");
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "lifetime instantiated with ",
-                    sup,
-                    "",
-                    None,
-                );
-                note_and_explain_region(
-                    self.tcx,
-                    &mut err,
-                    "but lifetime must outlive ",
-                    sub,
-                    "",
-                    None,
-                );
-                err
-            }
-        }
-    }
-
-    pub(super) fn report_placeholder_failure(
-        &self,
-        placeholder_origin: SubregionOrigin<'tcx>,
-        sub: Region<'tcx>,
-        sup: Region<'tcx>,
-    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
-        // I can't think how to do better than this right now. -nikomatsakis
-        debug!(?placeholder_origin, ?sub, ?sup, "report_placeholder_failure");
-        match placeholder_origin {
-            infer::Subtype(box ref trace)
-                if matches!(
-                    &trace.cause.code().peel_derives(),
-                    ObligationCauseCode::BindingObligation(..)
-                        | ObligationCauseCode::ExprBindingObligation(..)
-                ) =>
-            {
-                // Hack to get around the borrow checker because trace.cause has an `Rc`.
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..) =
-                    &trace.cause.code().peel_derives()
-                {
-                    let span = *span;
-                    let mut err = self.report_concrete_failure(placeholder_origin, sub, sup);
-                    err.span_note(span, "the lifetime requirement is introduced here");
-                    err
-                } else {
-                    unreachable!()
-                }
-            }
-            infer::Subtype(box trace) => {
-                let terr = TypeError::RegionsPlaceholderMismatch;
-                return self.report_and_explain_type_error(trace, terr);
-            }
-            _ => return self.report_concrete_failure(placeholder_origin, sub, sup),
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index 30ca9f41d6e..5b02956a106 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -411,7 +411,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         span: Span,
     ) {
         let hir = self.tcx.hir();
-        let fn_hir_id = hir.get_parent_node(cause.body_id);
+        let fn_hir_id = hir.parent_id(cause.body_id);
         if let Some(node) = self.tcx.hir().find(fn_hir_id) &&
             let hir::Node::Item(hir::Item {
                     kind: hir::ItemKind::Fn(_sig, _, body_id), ..
@@ -585,45 +585,42 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             let hir::StmtKind::Local(local) = &stmt.kind else { continue; };
             local.pat.walk(&mut find_compatible_candidates);
         }
-        match hir.find(hir.get_parent_node(blk.hir_id)) {
-            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => {
-                match hir.find(hir.get_parent_node(*hir_id)) {
-                    Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
-                        pat.walk(&mut find_compatible_candidates);
-                    }
-                    Some(
-                        hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
-                        | hir::Node::ImplItem(hir::ImplItem {
-                            kind: hir::ImplItemKind::Fn(_, body),
-                            ..
-                        })
-                        | hir::Node::TraitItem(hir::TraitItem {
-                            kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
-                            ..
-                        })
-                        | hir::Node::Expr(hir::Expr {
-                            kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
-                            ..
-                        }),
-                    ) => {
-                        for param in hir.body(*body).params {
-                            param.pat.walk(&mut find_compatible_candidates);
-                        }
-                    }
-                    Some(hir::Node::Expr(hir::Expr {
-                        kind:
-                            hir::ExprKind::If(
-                                hir::Expr { kind: hir::ExprKind::Let(let_), .. },
-                                then_block,
-                                _,
-                            ),
+        match hir.find_parent(blk.hir_id) {
+            Some(hir::Node::Expr(hir::Expr { hir_id, .. })) => match hir.find_parent(*hir_id) {
+                Some(hir::Node::Arm(hir::Arm { pat, .. })) => {
+                    pat.walk(&mut find_compatible_candidates);
+                }
+                Some(
+                    hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, _, body), .. })
+                    | hir::Node::ImplItem(hir::ImplItem {
+                        kind: hir::ImplItemKind::Fn(_, body), ..
+                    })
+                    | hir::Node::TraitItem(hir::TraitItem {
+                        kind: hir::TraitItemKind::Fn(_, hir::TraitFn::Provided(body)),
+                        ..
+                    })
+                    | hir::Node::Expr(hir::Expr {
+                        kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
                         ..
-                    })) if then_block.hir_id == *hir_id => {
-                        let_.pat.walk(&mut find_compatible_candidates);
+                    }),
+                ) => {
+                    for param in hir.body(*body).params {
+                        param.pat.walk(&mut find_compatible_candidates);
                     }
-                    _ => {}
                 }
-            }
+                Some(hir::Node::Expr(hir::Expr {
+                    kind:
+                        hir::ExprKind::If(
+                            hir::Expr { kind: hir::ExprKind::Let(let_), .. },
+                            then_block,
+                            _,
+                        ),
+                    ..
+                })) if then_block.hir_id == *hir_id => {
+                    let_.pat.walk(&mut find_compatible_candidates);
+                }
+                _ => {}
+            },
             _ => {}
         }
 
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 268b3bf1dcd..6bef3f000a5 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -361,6 +361,7 @@ pub enum ValuePairs<'tcx> {
     Terms(ExpectedFound<ty::Term<'tcx>>),
     TraitRefs(ExpectedFound<ty::TraitRef<'tcx>>),
     PolyTraitRefs(ExpectedFound<ty::PolyTraitRef<'tcx>>),
+    Sigs(ExpectedFound<ty::FnSig<'tcx>>),
 }
 
 impl<'tcx> ValuePairs<'tcx> {
@@ -409,9 +410,6 @@ pub enum SubregionOrigin<'tcx> {
     /// Creating a pointer `b` to contents of another reference
     Reborrow(Span),
 
-    /// Creating a pointer `b` to contents of an upvar
-    ReborrowUpvar(Span, ty::UpvarId),
-
     /// Data with type `Ty<'tcx>` was borrowed
     DataBorrowed(Ty<'tcx>, Span),
 
@@ -1340,6 +1338,12 @@ impl<'tcx> InferCtxt<'tcx> {
         var_infos
     }
 
+    #[instrument(level = "debug", skip(self), ret)]
+    pub fn take_opaque_types(&self) -> opaque_types::OpaqueTypeMap<'tcx> {
+        debug_assert_ne!(self.defining_use_anchor, DefiningAnchor::Error);
+        std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
+    }
+
     pub fn ty_to_string(&self, t: Ty<'tcx>) -> String {
         self.resolve_vars_if_possible(t).to_string()
     }
@@ -1681,19 +1685,35 @@ impl<'tcx> InferCtxt<'tcx> {
 }
 
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
+    /// Processes registered region obliations and resolves regions, reporting
+    /// any errors if any were raised. Prefer using this function over manually
+    /// calling `resolve_regions_and_report_errors`.
+    pub fn check_region_obligations_and_report_errors(
+        &self,
+        generic_param_scope: LocalDefId,
+        outlives_env: &OutlivesEnvironment<'tcx>,
+    ) -> Result<(), ErrorGuaranteed> {
+        self.process_registered_region_obligations(
+            outlives_env.region_bound_pairs(),
+            outlives_env.param_env,
+        );
+
+        self.resolve_regions_and_report_errors(generic_param_scope, outlives_env)
+    }
+
     /// Process the region constraints and report any errors that
     /// result. After this, no more unification operations should be
     /// done -- or the compiler will panic -- but it is legal to use
     /// `resolve_vars_if_possible` as well as `fully_resolve`.
     ///
     /// Make sure to call [`InferCtxt::process_registered_region_obligations`]
-    /// first, or preferably use [`InferCtxt::check_region_obligations_and_report_errors`]
+    /// first, or preferably use [`TypeErrCtxt::check_region_obligations_and_report_errors`]
     /// to do both of these operations together.
     pub fn resolve_regions_and_report_errors(
         &self,
         generic_param_scope: LocalDefId,
         outlives_env: &OutlivesEnvironment<'tcx>,
-    ) {
+    ) -> Result<(), ErrorGuaranteed> {
         let errors = self.resolve_regions(outlives_env);
 
         if let None = self.tainted_by_errors() {
@@ -1704,6 +1724,15 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             // errors from silly ones.
             self.report_region_errors(generic_param_scope, &errors);
         }
+
+        if errors.is_empty() {
+            Ok(())
+        } else {
+            Err(self
+                .tcx
+                .sess
+                .delay_span_bug(rustc_span::DUMMY_SP, "error should have been emitted"))
+        }
     }
 
     // [Note-Type-error-reporting]
@@ -1945,7 +1974,6 @@ impl<'tcx> SubregionOrigin<'tcx> {
             RelateParamBound(a, ..) => a,
             RelateRegionParamBound(a) => a,
             Reborrow(a) => a,
-            ReborrowUpvar(a, _) => a,
             DataBorrowed(_, a) => a,
             ReferenceOutlivesReferent(_, a) => a,
             CompareImplItemObligation { span, .. } => span,
diff --git a/compiler/rustc_infer/src/infer/note.rs b/compiler/rustc_infer/src/infer/note.rs
deleted file mode 100644
index 2ccbd164faa..00000000000
--- a/compiler/rustc_infer/src/infer/note.rs
+++ /dev/null
@@ -1,203 +0,0 @@
-impl<'tcx> TypeErrCtxt<'_, 'tcx> {
-    fn note_error_origin(
-        &self,
-        err: &mut Diagnostic,
-        cause: &ObligationCause<'tcx>,
-        exp_found: Option<ty::error::ExpectedFound<Ty<'tcx>>>,
-        terr: TypeError<'tcx>,
-    ) {
-        match *cause.code() {
-            ObligationCauseCode::Pattern { origin_expr: true, span: Some(span), root_ty } => {
-                let ty = self.resolve_vars_if_possible(root_ty);
-                if !matches!(ty.kind(), ty::Infer(ty::InferTy::TyVar(_) | ty::InferTy::FreshTy(_)))
-                {
-                    // don't show type `_`
-                    if span.desugaring_kind() == Some(DesugaringKind::ForLoop)
-                        && let ty::Adt(def, substs) = ty.kind()
-                        && Some(def.did()) == self.tcx.get_diagnostic_item(sym::Option)
-                    {
-                        err.span_label(span, format!("this is an iterator with items of type `{}`", substs.type_at(0)));
-                    } else {
-                    err.span_label(span, format!("this expression has type `{}`", ty));
-                }
-                }
-                if let Some(ty::error::ExpectedFound { found, .. }) = exp_found
-                    && ty.is_box() && ty.boxed_ty() == found
-                    && let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span)
-                {
-                    err.span_suggestion(
-                        span,
-                        "consider dereferencing the boxed value",
-                        format!("*{}", snippet),
-                        Applicability::MachineApplicable,
-                    );
-                }
-            }
-            ObligationCauseCode::Pattern { origin_expr: false, span: Some(span), .. } => {
-                err.span_label(span, "expected due to this");
-            }
-            ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                arm_block_id,
-                arm_span,
-                arm_ty,
-                prior_arm_block_id,
-                prior_arm_span,
-                prior_arm_ty,
-                source,
-                ref prior_arms,
-                scrut_hir_id,
-                opt_suggest_box_span,
-                scrut_span,
-                ..
-            }) => match source {
-                hir::MatchSource::TryDesugar => {
-                    if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found {
-                        let scrut_expr = self.tcx.hir().expect_expr(scrut_hir_id);
-                        let scrut_ty = if let hir::ExprKind::Call(_, args) = &scrut_expr.kind {
-                            let arg_expr = args.first().expect("try desugaring call w/out arg");
-                            self.typeck_results.as_ref().and_then(|typeck_results| {
-                                typeck_results.expr_ty_opt(arg_expr)
-                            })
-                        } else {
-                            bug!("try desugaring w/out call expr as scrutinee");
-                        };
-
-                        match scrut_ty {
-                            Some(ty) if expected == ty => {
-                                let source_map = self.tcx.sess.source_map();
-                                err.span_suggestion(
-                                    source_map.end_point(cause.span),
-                                    "try removing this `?`",
-                                    "",
-                                    Applicability::MachineApplicable,
-                                );
-                            }
-                            _ => {}
-                        }
-                    }
-                }
-                _ => {
-                    // `prior_arm_ty` can be `!`, `expected` will have better info when present.
-                    let t = self.resolve_vars_if_possible(match exp_found {
-                        Some(ty::error::ExpectedFound { expected, .. }) => expected,
-                        _ => prior_arm_ty,
-                    });
-                    let source_map = self.tcx.sess.source_map();
-                    let mut any_multiline_arm = source_map.is_multiline(arm_span);
-                    if prior_arms.len() <= 4 {
-                        for sp in prior_arms {
-                            any_multiline_arm |= source_map.is_multiline(*sp);
-                            err.span_label(*sp, format!("this is found to be of type `{}`", t));
-                        }
-                    } else if let Some(sp) = prior_arms.last() {
-                        any_multiline_arm |= source_map.is_multiline(*sp);
-                        err.span_label(
-                            *sp,
-                            format!("this and all prior arms are found to be of type `{}`", t),
-                        );
-                    }
-                    let outer_error_span = if any_multiline_arm {
-                        // Cover just `match` and the scrutinee expression, not
-                        // the entire match body, to reduce diagram noise.
-                        cause.span.shrink_to_lo().to(scrut_span)
-                    } else {
-                        cause.span
-                    };
-                    let msg = "`match` arms have incompatible types";
-                    err.span_label(outer_error_span, msg);
-                    self.suggest_remove_semi_or_return_binding(
-                        err,
-                        prior_arm_block_id,
-                        prior_arm_ty,
-                        prior_arm_span,
-                        arm_block_id,
-                        arm_ty,
-                        arm_span,
-                    );
-                    if let Some(ret_sp) = opt_suggest_box_span {
-                        // Get return type span and point to it.
-                        self.suggest_boxing_for_return_impl_trait(
-                            err,
-                            ret_sp,
-                            prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s),
-                        );
-                    }
-                }
-            },
-            ObligationCauseCode::IfExpression(box IfExpressionCause {
-                then_id,
-                else_id,
-                then_ty,
-                else_ty,
-                outer_span,
-                opt_suggest_box_span,
-            }) => {
-                let then_span = self.find_block_span_from_hir_id(then_id);
-                let else_span = self.find_block_span_from_hir_id(else_id);
-                err.span_label(then_span, "expected because of this");
-                if let Some(sp) = outer_span {
-                    err.span_label(sp, "`if` and `else` have incompatible types");
-                }
-                self.suggest_remove_semi_or_return_binding(
-                    err,
-                    Some(then_id),
-                    then_ty,
-                    then_span,
-                    Some(else_id),
-                    else_ty,
-                    else_span,
-                );
-                if let Some(ret_sp) = opt_suggest_box_span {
-                    self.suggest_boxing_for_return_impl_trait(
-                        err,
-                        ret_sp,
-                        [then_span, else_span].into_iter(),
-                    );
-                }
-            }
-            ObligationCauseCode::LetElse => {
-                err.help("try adding a diverging expression, such as `return` or `panic!(..)`");
-                err.help("...or use `match` instead of `let...else`");
-            }
-            _ => {
-                if let ObligationCauseCode::BindingObligation(_, span)
-                | ObligationCauseCode::ExprBindingObligation(_, span, ..)
-                = cause.code().peel_derives()
-                    && let TypeError::RegionsPlaceholderMismatch = terr
-                {
-                    err.span_note( * span,
-                    "the lifetime requirement is introduced here");
-                }
-            }
-        }
-    }
-}
-
-impl<'tcx> InferCtxt<'tcx> {
-    /// Given a [`hir::Block`], get the span of its last expression or
-    /// statement, peeling off any inner blocks.
-    pub fn find_block_span(&self, block: &'tcx hir::Block<'tcx>) -> Span {
-        let block = block.innermost_block();
-        if let Some(expr) = &block.expr {
-            expr.span
-        } else if let Some(stmt) = block.stmts.last() {
-            // possibly incorrect trailing `;` in the else arm
-            stmt.span
-        } else {
-            // empty block; point at its entirety
-            block.span
-        }
-    }
-
-    /// Given a [`hir::HirId`] for a block, get the span of its last expression
-    /// or statement, peeling off any inner blocks.
-    pub fn find_block_span_from_hir_id(&self, hir_id: hir::HirId) -> Span {
-        match self.tcx.hir().get(hir_id) {
-            hir::Node::Block(blk) => self.find_block_span(blk),
-            // The parser was in a weird state if either of these happen, but
-            // it's better not to panic.
-            hir::Node::Expr(e) => e.span,
-            _ => rustc_span::DUMMY_SP,
-        }
-    }
-}
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index a130fde47ed..749e960bfd0 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -61,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> {
                 .as_local()
                 .map_or(false, |def_id| self.opaque_type_origin(def_id, span).is_some())
         };
-        let value = value.fold_with(&mut ty::fold::BottomUpFolder {
+        let value = value.fold_with(&mut BottomUpFolder {
             tcx: self.tcx,
             lt_op: |lt| lt,
             ct_op: |ct| ct,
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index c146902d594..ae4b85c8799 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -29,11 +29,6 @@ impl<'tcx> OpaqueTypeStorage<'tcx> {
         }
     }
 
-    #[instrument(level = "debug", ret)]
-    pub fn take_opaque_types(&mut self) -> OpaqueTypeMap<'tcx> {
-        std::mem::take(&mut self.opaque_types)
-    }
-
     #[inline]
     pub(crate) fn with_log<'a>(
         &'a mut self,
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index ccae7165d80..a85e6a19b11 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -60,7 +60,6 @@
 //! imply that `'b: 'a`.
 
 use crate::infer::outlives::components::{push_outlives_components, Component};
-use crate::infer::outlives::env::OutlivesEnvironment;
 use crate::infer::outlives::env::RegionBoundPairs;
 use crate::infer::outlives::verify::VerifyBoundCx;
 use crate::infer::{
@@ -69,7 +68,6 @@ use crate::infer::{
 use crate::traits::{ObligationCause, ObligationCauseCode};
 use rustc_data_structures::undo_log::UndoLogs;
 use rustc_hir::def_id::DefId;
-use rustc_hir::def_id::LocalDefId;
 use rustc_middle::mir::ConstraintCategory;
 use rustc_middle::ty::subst::GenericArgKind;
 use rustc_middle::ty::{self, Region, SubstsRef, Ty, TyCtxt, TypeVisitable};
@@ -115,7 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
         std::mem::take(&mut self.inner.borrow_mut().region_obligations)
     }
 
-    /// NOTE: Prefer using [`InferCtxt::check_region_obligations_and_report_errors`]
+    /// NOTE: Prefer using `TypeErrCtxt::check_region_obligations_and_report_errors`
     /// instead of calling this directly.
     ///
     /// Process the region obligations that must be proven (during
@@ -169,22 +167,6 @@ impl<'tcx> InferCtxt<'tcx> {
             outlives.type_must_outlive(origin, sup_type, sub_region, category);
         }
     }
-
-    /// Processes registered region obliations and resolves regions, reporting
-    /// any errors if any were raised. Prefer using this function over manually
-    /// calling `resolve_regions_and_report_errors`.
-    pub fn check_region_obligations_and_report_errors(
-        &self,
-        generic_param_scope: LocalDefId,
-        outlives_env: &OutlivesEnvironment<'tcx>,
-    ) {
-        self.process_registered_region_obligations(
-            outlives_env.region_bound_pairs(),
-            outlives_env.param_env,
-        );
-
-        self.err_ctxt().resolve_regions_and_report_errors(generic_param_scope, outlives_env)
-    }
 }
 
 /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a`
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index 136da4a3cb1..40bbec8ddd0 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -5,7 +5,7 @@ use crate::infer::{GenericKind, VerifyBound};
 use rustc_data_structures::sso::SsoHashSet;
 use rustc_hir::def_id::DefId;
 use rustc_middle::ty::GenericArg;
-use rustc_middle::ty::{self, EarlyBinder, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, OutlivesPredicate, SubstsRef, Ty, TyCtxt};
 
 use smallvec::smallvec;
 
@@ -304,14 +304,13 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
         substs: SubstsRef<'tcx>,
     ) -> impl Iterator<Item = ty::Region<'tcx>> {
         let tcx = self.tcx;
-        let bounds = tcx.item_bounds(def_id);
-        trace!("{:#?}", bounds);
+        let bounds = tcx.bound_item_bounds(def_id);
+        trace!("{:#?}", bounds.0);
         bounds
-            .into_iter()
+            .subst_iter(tcx, substs)
             .filter_map(|p| p.to_opt_type_outlives())
             .filter_map(|p| p.no_bound_vars())
-            .map(|b| b.1)
-            .map(move |r| EarlyBinder(r).subst(tcx, substs))
+            .map(|OutlivesPredicate(_, r)| r)
     }
 
     /// Searches through a predicate list for a predicate `T: 'a`.
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index 22b4bbb17d4..c46edc33ff4 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -357,15 +357,13 @@ impl<'tcx> SccUniverse<'tcx> {
 }
 
 rustc_index::newtype_index! {
-    struct LeakCheckNode {
-        DEBUG_FORMAT = "LeakCheckNode({})"
-    }
+    #[debug_format = "LeakCheckNode({})"]
+    struct LeakCheckNode {}
 }
 
 rustc_index::newtype_index! {
-    struct LeakCheckScc {
-        DEBUG_FORMAT = "LeakCheckScc({})"
-    }
+    #[debug_format = "LeakCheckScc({})"]
+    struct LeakCheckScc {}
 }
 
 /// Represents the graph of constraints. For each `R1: R2` constraint we create