]> git.proxmox.com Git - rustc.git/blobdiff - compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
New upstream version 1.71.1+dfsg1
[rustc.git] / compiler / rustc_trait_selection / src / traits / error_reporting / mod.rs
index 1b741b7302b67f1a1b98c03e039f11362722832a..a10ececbb1ea7e972f3577ea411565bc2ad26800 100644 (file)
@@ -1,5 +1,4 @@
 mod ambiguity;
-pub mod method_chain;
 pub mod on_unimplemented;
 pub mod suggestions;
 
@@ -15,8 +14,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
 use crate::traits::query::normalize::QueryNormalizeExt as _;
 use crate::traits::specialize::to_pretty_impl_header;
 use crate::traits::NormalizeExt;
-use on_unimplemented::OnUnimplementedNote;
-use on_unimplemented::TypeErrCtxtExt as _;
+use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_errors::{
     pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -30,9 +28,9 @@ use rustc_hir::{GenericParam, Item, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_middle::traits::select::OverflowError;
+use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
 use rustc_middle::ty::abstract_const::NotConstEvaluatable;
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fast_reject::TreatProjections;
 use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
 use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
 use rustc_middle::ty::{
@@ -273,7 +271,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                 let underscores = vec!["_"; expected_args.len()].join(", ");
                 err.span_suggestion_verbose(
                     closure_arg_span.unwrap_or(found_span),
-                    &format!(
+                    format!(
                         "consider changing the closure to take and ignore the expected argument{}",
                         pluralize!(expected_args.len())
                     ),
@@ -360,7 +358,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
                     span: DUMMY_SP,
                     kind: TypeVariableOriginKind::MiscVariable,
                 });
-                let trait_ref = self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]);
+                let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
                 let obligation = Obligation::new(
                     self.tcx,
                     ObligationCause::dummy(),
@@ -439,7 +437,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     // 1) strictly implied by another error.
                     // 2) implied by an error with a smaller index.
                     for error2 in error_set {
-                        if error2.index.map_or(false, |index2| is_suppressed[index2]) {
+                        if error2.index.is_some_and(|index2| is_suppressed[index2]) {
                             // Avoid errors being suppressed by already-suppressed
                             // errors, to prevent all errors from being suppressed
                             // at once.
@@ -467,7 +465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment errors")
+        self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
     }
 
     /// Reports that an overflow has occurred and halts compilation. We
@@ -561,6 +559,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             suggest_increasing_limit,
             |err| {
                 self.note_obligation_cause_code(
+                    obligation.cause.body_id,
                     err,
                     predicate,
                     obligation.param_env,
@@ -577,7 +576,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             Limit(0) => Limit(2),
             limit => limit * 2,
         };
-        err.help(&format!(
+        err.help(format!(
             "consider increasing the recursion limit by adding a \
              `#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
             suggested_limit,
@@ -707,42 +706,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                      conversion on the error value using the `From` trait"
                                         .to_owned(),
                                 ),
-                                Some(None),
+                                Some(AppendConstMessage::Default),
                             )
                         } else {
                             (message, note, append_const_msg)
                         };
 
-                        let err_msg = message
-                            .and_then(|cannot_do_this| {
-                                match (predicate_is_const, append_const_msg) {
-                                    // do nothing if predicate is not const
-                                    (false, _) => Some(cannot_do_this),
-                                    // suggested using default post message
-                                    (true, Some(None)) => {
-                                        Some(format!("{cannot_do_this} in const contexts"))
-                                    }
-                                    // overridden post message
-                                    (true, Some(Some(post_message))) => {
-                                        Some(format!("{cannot_do_this}{post_message}"))
-                                    }
-                                    // fallback to generic message
-                                    (true, None) => None,
-                                }
-                            })
-                            .unwrap_or_else(|| {
-                                format!(
-                                    "the trait bound `{}` is not satisfied{}",
-                                    trait_predicate, post_message,
-                                )
-                            });
+                        let err_msg = self.get_standard_error_message(
+                            &trait_predicate,
+                            message,
+                            predicate_is_const,
+                            append_const_msg,
+                            post_message,
+                        );
 
                         let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
                             == self.tcx.lang_items().transmute_trait()
                         {
                             // Recompute the safe transmute reason and use that for the error reporting
                             self.get_safe_transmute_error_and_reason(
-                                trait_predicate,
                                 obligation.clone(),
                                 trait_ref,
                                 span,
@@ -756,7 +738,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
                             err.span_label(
                                 ret_span,
-                                &format!(
+                                format!(
                                     "expected `{}` because of this",
                                     trait_ref.skip_binder().self_ty()
                                 ),
@@ -764,22 +746,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         }
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
-                            match obligation.cause.code().peel_derives() {
-                                ObligationCauseCode::RustCall => {
-                                    err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
-                                }
-                                ObligationCauseCode::BindingObligation(def_id, _)
-                                | ObligationCauseCode::ItemObligation(def_id)
-                                    if tcx.is_fn_trait(*def_id) =>
-                                {
-                                    err.code(rustc_errors::error_code!(E0059));
-                                    err.set_primary_message(format!(
-                                        "type parameter to bare `{}` trait must be a tuple",
-                                        tcx.def_path_str(*def_id)
-                                    ));
-                                }
-                                _ => {}
-                            }
+                            self.add_tuple_trait_message(
+                                &obligation.cause.code().peel_derives(),
+                                &mut err,
+                            );
                         }
 
                         if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
@@ -789,33 +759,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
                         }
 
-                        let explanation = if let ObligationCauseCode::MainFunctionType =
-                            obligation.cause.code()
-                        {
-                            "consider using `()`, or a `Result`".to_owned()
-                        } else {
-                            let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
-                                ty::FnDef(_, _) => Some("fn item"),
-                                ty::Closure(_, _) => Some("closure"),
-                                _ => None,
-                            };
+                        let explanation = get_explanation_based_on_obligation(
+                            &obligation,
+                            trait_ref,
+                            &trait_predicate,
+                            pre_message,
+                        );
 
-                            match ty_desc {
-                                Some(desc) => format!(
-                                    "{}the trait `{}` is not implemented for {} `{}`",
-                                    pre_message,
-                                    trait_predicate.print_modifiers_and_trait_path(),
-                                    desc,
-                                    trait_ref.skip_binder().self_ty(),
-                                ),
-                                None => format!(
-                                    "{}the trait `{}` is not implemented for `{}`",
-                                    pre_message,
-                                    trait_predicate.print_modifiers_and_trait_path(),
-                                    trait_ref.skip_binder().self_ty(),
-                                ),
-                            }
-                        };
                         self.check_for_binding_assigned_block_without_tail_expression(
                             &obligation,
                             &mut err,
@@ -831,7 +781,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             err.emit();
                             return;
                         }
-                        if let Some(ref s) = label {
+                        if let Some(s) = label {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s);
@@ -839,7 +789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 // When the self type is a type param We don't need to "the trait
                                 // `std::marker::Sized` is not implemented for `T`" as we will point
                                 // at the type param with a label to suggest constraining it.
-                                err.help(&explanation);
+                                err.help(explanation);
                             }
                         } else if let Some(custom_explanation) = safe_transmute_explanation {
                             err.span_label(span, custom_explanation);
@@ -847,42 +797,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             err.span_label(span, explanation);
                         }
 
-                        if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
-                            Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
-                            self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
-                        }
-
-                        let mut unsatisfied_const = false;
-                        if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
-                            let non_const_predicate = trait_ref.without_const();
-                            let non_const_obligation = Obligation {
-                                cause: obligation.cause.clone(),
-                                param_env: obligation.param_env.without_const(),
-                                predicate: non_const_predicate.to_predicate(tcx),
-                                recursion_depth: obligation.recursion_depth,
-                            };
-                            if self.predicate_may_hold(&non_const_obligation) {
-                                unsatisfied_const = true;
-                                err.span_note(
-                                    span,
-                                    &format!(
-                                        "the trait `{}` is implemented for `{}`, \
-                                        but that implementation is not `const`",
-                                        non_const_predicate.print_modifiers_and_trait_path(),
-                                        trait_ref.skip_binder().self_ty(),
-                                    ),
+                        if let ObligationCauseCode::Coercion { source, target } =
+                            *obligation.cause.code().peel_derives()
+                        {
+                            if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+                                self.suggest_borrowing_for_object_cast(
+                                    &mut err,
+                                    &root_obligation,
+                                    source,
+                                    target,
                                 );
                             }
                         }
 
+                        let UnsatisfiedConst(unsatisfied_const) = self
+                            .maybe_add_note_for_unsatisfied_const(
+                                &obligation,
+                                trait_ref,
+                                &trait_predicate,
+                                &mut err,
+                                span,
+                            );
+
                         if let Some((msg, span)) = type_def {
-                            err.span_label(span, &msg);
+                            err.span_label(span, msg);
                         }
-                        if let Some(ref s) = note {
+                        if let Some(s) = note {
                             // If it has a custom `#[rustc_on_unimplemented]` note, let's display it
-                            err.note(s.as_str());
+                            err.note(s);
                         }
-                        if let Some(ref s) = parent_label {
+                        if let Some(s) = parent_label {
                             let body = obligation.cause.body_id;
                             err.span_label(tcx.def_span(body), s);
                         }
@@ -941,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             return;
                         }
 
-                        if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
+                        if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
                             err.emit();
                             return;
                         }
@@ -971,137 +915,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             );
                         }
 
-                        let body_def_id = obligation.cause.body_id;
-                        // Try to report a help message
-                        if is_fn_trait
-                            && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
-                            obligation.param_env,
-                            trait_ref.self_ty(),
-                            trait_predicate.skip_binder().constness,
-                            trait_predicate.skip_binder().polarity,
-                        )
-                        {
-                            // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
-                            // suggestion to add trait bounds for the type, since we only typically implement
-                            // these traits once.
-
-                            // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
-                            // to implement.
-                            let selected_kind =
-                                self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
-                                    .expect("expected to map DefId to ClosureKind");
-                            if !implemented_kind.extends(selected_kind) {
-                                err.note(
-                                    &format!(
-                                        "`{}` implements `{}`, but it must implement `{}`, which is more general",
-                                        trait_ref.skip_binder().self_ty(),
-                                        implemented_kind,
-                                        selected_kind
-                                    )
-                                );
-                            }
-
-                            // Note any argument mismatches
-                            let given_ty = params.skip_binder();
-                            let expected_ty = trait_ref.skip_binder().substs.type_at(1);
-                            if let ty::Tuple(given) = given_ty.kind()
-                                && let ty::Tuple(expected) = expected_ty.kind()
-                            {
-                                if expected.len() != given.len() {
-                                    // Note number of types that were expected and given
-                                    err.note(
-                                        &format!(
-                                            "expected a closure taking {} argument{}, but one taking {} argument{} was given",
-                                            given.len(),
-                                            pluralize!(given.len()),
-                                            expected.len(),
-                                            pluralize!(expected.len()),
-                                        )
-                                    );
-                                } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
-                                    // Print type mismatch
-                                    let (expected_args, given_args) =
-                                        self.cmp(given_ty, expected_ty);
-                                    err.note_expected_found(
-                                        &"a closure with arguments",
-                                        expected_args,
-                                        &"a closure with arguments",
-                                        given_args,
-                                    );
-                                }
-                            }
-                        } else if !trait_ref.has_non_region_infer()
-                            && self.predicate_can_apply(obligation.param_env, trait_predicate)
-                        {
-                            // If a where-clause may be useful, remind the
-                            // user that they can add it.
-                            //
-                            // don't display an on-unimplemented note, as
-                            // these notes will often be of the form
-                            //     "the type `T` can't be frobnicated"
-                            // which is somewhat confusing.
-                            self.suggest_restricting_param_bound(
-                                &mut err,
-                                trait_predicate,
-                                None,
-                                obligation.cause.body_id,
-                            );
-                        } else if !suggested && !unsatisfied_const {
-                            // Can't show anything else useful, try to find similar impls.
-                            let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
-                            if !self.report_similar_impl_candidates(
-                                &impl_candidates,
-                                trait_ref,
-                                body_def_id,
-                                &mut err,
-                                true,
-                            ) {
-                                // This is *almost* equivalent to
-                                // `obligation.cause.code().peel_derives()`, but it gives us the
-                                // trait predicate for that corresponding root obligation. This
-                                // lets us get a derived obligation from a type parameter, like
-                                // when calling `string.strip_suffix(p)` where `p` is *not* an
-                                // implementer of `Pattern<'_>`.
-                                let mut code = obligation.cause.code();
-                                let mut trait_pred = trait_predicate;
-                                let mut peeled = false;
-                                while let Some((parent_code, parent_trait_pred)) = code.parent() {
-                                    code = parent_code;
-                                    if let Some(parent_trait_pred) = parent_trait_pred {
-                                        trait_pred = parent_trait_pred;
-                                        peeled = true;
-                                    }
-                                }
-                                let def_id = trait_pred.def_id();
-                                // Mention *all* the `impl`s for the *top most* obligation, the
-                                // user might have meant to use one of them, if any found. We skip
-                                // auto-traits or fundamental traits that might not be exactly what
-                                // the user might expect to be presented with. Instead this is
-                                // useful for less general traits.
-                                if peeled
-                                    && !self.tcx.trait_is_auto(def_id)
-                                    && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
-                                {
-                                    let trait_ref = trait_pred.to_poly_trait_ref();
-                                    let impl_candidates =
-                                        self.find_similar_impl_candidates(trait_pred);
-                                    self.report_similar_impl_candidates(
-                                        &impl_candidates,
-                                        trait_ref,
-                                        body_def_id,
-                                        &mut err,
-                                        true,
-                                    );
-                                }
-                            }
-
-                            self.maybe_suggest_convert_to_slice(
-                                &mut err,
-                                trait_ref,
-                                impl_candidates.as_slice(),
-                                span,
-                            );
-                        }
+                        self.try_to_add_help_message(
+                            &obligation,
+                            trait_ref,
+                            &trait_predicate,
+                            &mut err,
+                            span,
+                            is_fn_trait,
+                            suggested,
+                            unsatisfied_const,
+                        );
 
                         // Changing mutability doesn't make a difference to whether we have
                         // an `Unsize` impl (Fixes ICE in #71036)
@@ -1196,59 +1019,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
                     ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
                         let found_kind = self.closure_kind(closure_substs).unwrap();
-                        let closure_span = self.tcx.def_span(closure_def_id);
-                        let mut err = struct_span_err!(
-                            self.tcx.sess,
-                            closure_span,
-                            E0525,
-                            "expected a closure that implements the `{}` trait, \
-                             but this closure only implements `{}`",
-                            kind,
-                            found_kind
-                        );
-
-                        err.span_label(
-                            closure_span,
-                            format!("this closure implements `{}`, not `{}`", found_kind, kind),
-                        );
-                        err.span_label(
-                            obligation.cause.span,
-                            format!("the requirement to implement `{}` derives from here", kind),
-                        );
-
-                        // Additional context information explaining why the closure only implements
-                        // a particular trait.
-                        if let Some(typeck_results) = &self.typeck_results {
-                            let hir_id = self
-                                .tcx
-                                .hir()
-                                .local_def_id_to_hir_id(closure_def_id.expect_local());
-                            match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
-                                (ty::ClosureKind::FnOnce, Some((span, place))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnOnce` because it moves the \
-                                         variable `{}` out of its environment",
-                                            ty::place_to_string_for_capture(tcx, place)
-                                        ),
-                                    );
-                                }
-                                (ty::ClosureKind::FnMut, Some((span, place))) => {
-                                    err.span_label(
-                                        *span,
-                                        format!(
-                                            "closure is `FnMut` because it mutates the \
-                                         variable `{}` here",
-                                            ty::place_to_string_for_capture(tcx, place)
-                                        ),
-                                    );
-                                }
-                                _ => {}
-                            }
-                        }
-
-                        err
+                        self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
                     }
 
                     ty::PredicateKind::WellFormed(ty) => {
@@ -1266,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 // which bounds actually failed to hold.
                                 self.tcx.sess.struct_span_err(
                                     span,
-                                    &format!("the type `{}` is not well-formed", ty),
+                                    format!("the type `{}` is not well-formed", ty),
                                 )
                             }
                         }
@@ -1309,7 +1080,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
                         let mut diag = self.tcx.sess.struct_span_err(
                             span,
-                            &format!("the constant `{}` is not of type `{}`", ct, ty),
+                            format!("the constant `{}` is not of type `{}`", ct, ty),
                         );
                         self.note_type_err(
                             &mut diag,
@@ -1325,121 +1096,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 }
             }
 
-            OutputTypeParameterMismatch(
+            OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
                 found_trait_ref,
                 expected_trait_ref,
-                terr @ TypeError::CyclicTy(_),
-            ) => {
-                let self_ty = found_trait_ref.self_ty().skip_binder();
-                let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
-                    (
-                        ObligationCause::dummy_with_span(tcx.def_span(def_id)),
-                        TypeError::CyclicTy(self_ty),
-                    )
-                } else {
-                    (obligation.cause.clone(), terr)
-                };
-                self.report_and_explain_type_error(
-                    TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
-                    terr,
-                )
-            }
-            OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
-                let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
-                let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
-
-                if expected_trait_ref.self_ty().references_error() {
-                    return;
-                }
-
-                let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
-                    return;
-                };
-
-                let found_did = match *found_trait_ty.kind() {
-                    ty::Closure(did, _)
-                    | ty::Foreign(did)
-                    | ty::FnDef(did, _)
-                    | ty::Generator(did, ..) => Some(did),
-                    ty::Adt(def, _) => Some(def.did()),
-                    _ => None,
-                };
-
-                let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
-                let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
-
-                if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
-                    // We check closures twice, with obligations flowing in different directions,
-                    // but we want to complain about them only once.
-                    return;
-                }
-
-                self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
-
-                let mut not_tupled = false;
-
-                let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
-                    ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
-                    _ => {
-                        not_tupled = true;
-                        vec![ArgKind::empty()]
-                    }
-                };
-
-                let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
-                let expected = match expected_ty.kind() {
-                    ty::Tuple(ref tys) => {
-                        tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
-                    }
-                    _ => {
-                        not_tupled = true;
-                        vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
-                    }
-                };
-
-                // If this is a `Fn` family trait and either the expected or found
-                // is not tupled, then fall back to just a regular mismatch error.
-                // This shouldn't be common unless manually implementing one of the
-                // traits manually, but don't make it more confusing when it does
-                // happen.
-                if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
-                    self.report_and_explain_type_error(
-                        TypeTrace::poly_trait_refs(
-                            &obligation.cause,
-                            true,
-                            expected_trait_ref,
-                            found_trait_ref,
-                        ),
-                        ty::error::TypeError::Mismatch,
-                    )
-                } else if found.len() == expected.len() {
-                    self.report_closure_arg_mismatch(
-                        span,
-                        found_span,
-                        found_trait_ref,
-                        expected_trait_ref,
-                        obligation.cause.code(),
-                        found_node,
-                        obligation.param_env,
-                    )
-                } else {
-                    let (closure_span, closure_arg_span, found) = found_did
-                        .and_then(|did| {
-                            let node = self.tcx.hir().get_if_local(did)?;
-                            let (found_span, closure_arg_span, found) =
-                                self.get_fn_like_arguments(node)?;
-                            Some((Some(found_span), closure_arg_span, found))
-                        })
-                        .unwrap_or((found_span, None, found));
-
-                    self.report_arg_count_mismatch(
-                        span,
-                        closure_span,
-                        expected,
-                        found,
-                        found_trait_ty.is_closure(),
-                        closure_arg_span,
-                    )
+                terr: terr @ TypeError::CyclicTy(_),
+            }) => self.report_type_parameter_mismatch_cyclic_type_error(
+                &obligation,
+                found_trait_ref,
+                expected_trait_ref,
+                terr,
+            ),
+            OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
+                found_trait_ref,
+                expected_trait_ref,
+                terr: _,
+            }) => {
+                match self.report_type_parameter_mismatch_error(
+                    &obligation,
+                    span,
+                    found_trait_ref,
+                    expected_trait_ref,
+                ) {
+                    Some(err) => err,
+                    None => return,
                 }
             }
 
@@ -1454,45 +1133,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 )
             }
             SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
-                if !self.tcx.features().generic_const_exprs {
-                    let mut err = self.tcx.sess.struct_span_err(
-                        span,
-                        "constant expression depends on a generic parameter",
-                    );
-                    // FIXME(const_generics): we should suggest to the user how they can resolve this
-                    // issue. However, this is currently not actually possible
-                    // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
-                    //
-                    // Note that with `feature(generic_const_exprs)` this case should not
-                    // be reachable.
-                    err.note("this may fail depending on what value the parameter takes");
-                    err.emit();
-                    return;
-                }
-
-                match obligation.predicate.kind().skip_binder() {
-                    ty::PredicateKind::ConstEvaluatable(ct) => {
-                        let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
-                            bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
-                        };
-                        let mut err =
-                            self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
-                        let const_span = self.tcx.def_span(uv.def.did);
-                        match self.tcx.sess.source_map().span_to_snippet(const_span) {
-                            Ok(snippet) => err.help(&format!(
-                                "try adding a `where` bound using this expression: `where [(); {}]:`",
-                                snippet
-                            )),
-                            _ => err.help("consider adding a `where` bound using this expression"),
-                        };
-                        err
-                    }
-                    _ => {
-                        span_bug!(
-                            span,
-                            "unexpected non-ConstEvaluatable predicate, this should not be reachable"
-                        )
-                    }
+                match self.report_not_const_evaluatable_error(&obligation, span) {
+                    Some(err) => err,
+                    None => return,
                 }
             }
 
@@ -1564,6 +1207,14 @@ trait InferCtxtPrivExt<'tcx> {
         other: bool,
     ) -> bool;
 
+    fn report_similar_impl_candidates_for_root_obligation(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        body_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    );
+
     /// Gets the parent trait chain start
     fn get_parent_trait_ref(
         &self,
@@ -1627,13 +1278,86 @@ trait InferCtxtPrivExt<'tcx> {
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool;
 
+    fn get_standard_error_message(
+        &self,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        message: Option<String>,
+        predicate_is_const: bool,
+        append_const_msg: Option<AppendConstMessage>,
+        post_message: String,
+    ) -> String;
+
     fn get_safe_transmute_error_and_reason(
         &self,
-        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
-        obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        obligation: PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
     ) -> (String, Option<String>);
+
+    fn add_tuple_trait_message(
+        &self,
+        obligation_cause_code: &ObligationCauseCode<'tcx>,
+        err: &mut Diagnostic,
+    );
+
+    fn try_to_add_help_message(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+        is_fn_trait: bool,
+        suggested: bool,
+        unsatisfied_const: bool,
+    );
+
+    fn add_help_message_for_fn_trait(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        err: &mut Diagnostic,
+        implemented_kind: ty::ClosureKind,
+        params: ty::Binder<'tcx, Ty<'tcx>>,
+    );
+
+    fn maybe_add_note_for_unsatisfied_const(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+    ) -> UnsatisfiedConst;
+
+    fn report_closure_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        closure_def_id: DefId,
+        found_kind: ty::ClosureKind,
+        kind: ty::ClosureKind,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+    fn report_type_parameter_mismatch_cyclic_type_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        terr: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+    fn report_type_parameter_mismatch_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
+
+    fn report_not_const_evaluatable_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
 }
 
 impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -1720,6 +1444,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 | ObligationCauseCode::ExprItemObligation(..) = code
                 {
                     self.note_obligation_cause_code(
+                        error.obligation.cause.body_id,
                         &mut diag,
                         error.obligation.predicate,
                         error.obligation.param_env,
@@ -1773,7 +1498,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         .tcx
                         .mk_const(
                             ty::UnevaluatedConst {
-                                def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+                                def: data.projection_ty.def_id,
                                 substs: data.projection_ty.substs,
                             },
                             ct.ty(),
@@ -1793,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         | ObligationCauseCode::BindingObligation(_, _)
                         | ObligationCauseCode::ExprItemObligation(..)
                         | ObligationCauseCode::ExprBindingObligation(..)
-                        | ObligationCauseCode::ObjectCastObligation(..)
+                        | ObligationCauseCode::Coercion { .. }
                         | ObligationCauseCode::OpaqueType
                 );
 
@@ -1838,57 +1563,61 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 });
             let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
 
-            let secondary_span = match predicate.kind().skip_binder() {
-                ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
-                    .tcx
-                    .opt_associated_item(proj.projection_ty.def_id)
-                    .and_then(|trait_assoc_item| {
-                        self.tcx
-                            .trait_of_item(proj.projection_ty.def_id)
-                            .map(|id| (trait_assoc_item, id))
-                    })
-                    .and_then(|(trait_assoc_item, id)| {
-                        let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
-                        self.tcx.find_map_relevant_impl(
-                            id,
-                            proj.projection_ty.self_ty(),
-                            TreatProjections::ForLookup,
-                            |did| {
-                                self.tcx
-                                    .associated_items(did)
-                                    .in_definition_order()
-                                    .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
-                            },
-                        )
-                    })
-                    .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
-                        Some(
-                            hir::Node::TraitItem(hir::TraitItem {
-                                kind: hir::TraitItemKind::Type(_, Some(ty)),
-                                ..
-                            })
-                            | hir::Node::ImplItem(hir::ImplItem {
-                                kind: hir::ImplItemKind::Type(ty),
-                                ..
-                            }),
-                        ) => Some((
-                            ty.span,
-                            with_forced_trimmed_paths!(format!(
-                                "type mismatch resolving `{}`",
-                                self.resolve_vars_if_possible(predicate)
-                                    .print(FmtPrinter::new_with_limit(
-                                        self.tcx,
-                                        Namespace::TypeNS,
-                                        rustc_session::Limit(5),
-                                    ))
-                                    .unwrap()
-                                    .into_buffer()
-                            )),
+            let secondary_span = (|| {
+                let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
+                    predicate.kind().skip_binder()
+                else {
+                    return None;
+                };
+
+                let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
+                let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
+
+                let mut associated_items = vec![];
+                self.tcx.for_each_relevant_impl(
+                    self.tcx.trait_of_item(proj.projection_ty.def_id)?,
+                    proj.projection_ty.self_ty(),
+                    |impl_def_id| {
+                        associated_items.extend(
+                            self.tcx
+                                .associated_items(impl_def_id)
+                                .in_definition_order()
+                                .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
+                        );
+                    },
+                );
+
+                let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
+                    return None;
+                };
+                match self.tcx.hir().get_if_local(associated_item.def_id) {
+                    Some(
+                        hir::Node::TraitItem(hir::TraitItem {
+                            kind: hir::TraitItemKind::Type(_, Some(ty)),
+                            ..
+                        })
+                        | hir::Node::ImplItem(hir::ImplItem {
+                            kind: hir::ImplItemKind::Type(ty),
+                            ..
+                        }),
+                    ) => Some((
+                        ty.span,
+                        with_forced_trimmed_paths!(format!(
+                            "type mismatch resolving `{}`",
+                            self.resolve_vars_if_possible(predicate)
+                                .print(FmtPrinter::new_with_limit(
+                                    self.tcx,
+                                    Namespace::TypeNS,
+                                    rustc_session::Limit(5),
+                                ))
+                                .unwrap()
+                                .into_buffer()
                         )),
-                        _ => None,
-                    }),
-                _ => None,
-            };
+                    )),
+                    _ => None,
+                }
+            })();
+
             self.note_type_err(
                 &mut diag,
                 &obligation.cause,
@@ -1971,13 +1700,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                 ty::Tuple(..) => Some(10),
                 ty::Param(..) => Some(11),
                 ty::Alias(ty::Projection, ..) => Some(12),
-                ty::Alias(ty::Opaque, ..) => Some(13),
-                ty::Never => Some(14),
-                ty::Adt(..) => Some(15),
-                ty::Generator(..) => Some(16),
-                ty::Foreign(..) => Some(17),
-                ty::GeneratorWitness(..) => Some(18),
-                ty::GeneratorWitnessMIR(..) => Some(19),
+                ty::Alias(ty::Inherent, ..) => Some(13),
+                ty::Alias(ty::Opaque, ..) => Some(14),
+                ty::Never => Some(15),
+                ty::Adt(..) => Some(16),
+                ty::Generator(..) => Some(17),
+                ty::Foreign(..) => Some(18),
+                ty::GeneratorWitness(..) => Some(19),
+                ty::GeneratorWitnessMIR(..) => Some(20),
                 ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
             }
         }
@@ -2058,7 +1788,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
             // If any of the candidates is a perfect match, we don't want to show all of them.
             // This is particularly relevant for the case of numeric types (as they all have the
-            // same cathegory).
+            // same category).
             candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
         }
         candidates
@@ -2120,7 +1850,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             candidates.sort();
             candidates.dedup();
             let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
-            err.help(&format!(
+            err.help(format!(
                 "the following {other}types implement trait `{}`:{}{}",
                 trait_ref.print_only_trait_path(),
                 candidates[..end].join(""),
@@ -2197,6 +1927,51 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         report(normalized_impl_candidates, err)
     }
 
+    fn report_similar_impl_candidates_for_root_obligation(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+        body_def_id: LocalDefId,
+        err: &mut Diagnostic,
+    ) {
+        // This is *almost* equivalent to
+        // `obligation.cause.code().peel_derives()`, but it gives us the
+        // trait predicate for that corresponding root obligation. This
+        // lets us get a derived obligation from a type parameter, like
+        // when calling `string.strip_suffix(p)` where `p` is *not* an
+        // implementer of `Pattern<'_>`.
+        let mut code = obligation.cause.code();
+        let mut trait_pred = trait_predicate;
+        let mut peeled = false;
+        while let Some((parent_code, parent_trait_pred)) = code.parent() {
+            code = parent_code;
+            if let Some(parent_trait_pred) = parent_trait_pred {
+                trait_pred = parent_trait_pred;
+                peeled = true;
+            }
+        }
+        let def_id = trait_pred.def_id();
+        // Mention *all* the `impl`s for the *top most* obligation, the
+        // user might have meant to use one of them, if any found. We skip
+        // auto-traits or fundamental traits that might not be exactly what
+        // the user might expect to be presented with. Instead this is
+        // useful for less general traits.
+        if peeled
+            && !self.tcx.trait_is_auto(def_id)
+            && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
+        {
+            let trait_ref = trait_pred.to_poly_trait_ref();
+            let impl_candidates = self.find_similar_impl_candidates(trait_pred);
+            self.report_similar_impl_candidates(
+                &impl_candidates,
+                trait_ref,
+                body_def_id,
+                err,
+                true,
+            );
+        }
+    }
+
     /// Gets the parent trait chain start
     fn get_parent_trait_ref(
         &self,
@@ -2230,14 +2005,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         err: &mut Diagnostic,
         trait_ref: &ty::PolyTraitRef<'tcx>,
     ) -> bool {
-        let get_trait_impl = |trait_def_id| {
-            self.tcx.find_map_relevant_impl(
+        let get_trait_impls = |trait_def_id| {
+            let mut trait_impls = vec![];
+            self.tcx.for_each_relevant_impl(
                 trait_def_id,
                 trait_ref.skip_binder().self_ty(),
-                TreatProjections::ForLookup,
-                Some,
-            )
+                |impl_def_id| {
+                    trait_impls.push(impl_def_id);
+                },
+            );
+            trait_impls
         };
+
         let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
         let traits_with_same_path: std::collections::BTreeSet<_> = self
             .tcx
@@ -2247,17 +2026,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             .collect();
         let mut suggested = false;
         for trait_with_same_path in traits_with_same_path {
-            if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
-                let impl_span = self.tcx.def_span(impl_def_id);
-                err.span_help(impl_span, "trait impl with same name found");
-                let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
-                let crate_msg = format!(
-                    "perhaps two different versions of crate `{}` are being used?",
-                    trait_crate
-                );
-                err.note(&crate_msg);
-                suggested = true;
+            let trait_impls = get_trait_impls(trait_with_same_path);
+            if trait_impls.is_empty() {
+                continue;
             }
+            let impl_spans: Vec<_> =
+                trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
+            err.span_help(
+                impl_spans,
+                format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
+            );
+            let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+            let crate_msg = format!(
+                "perhaps two different versions of crate `{}` are being used?",
+                trait_crate
+            );
+            err.note(crate_msg);
+            suggested = true;
         }
         suggested
     }
@@ -2388,7 +2173,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                                 err.cancel();
                                 return;
                             }
-                            err.note(&format!("cannot satisfy `{}`", predicate));
+                            err.note(format!("cannot satisfy `{}`", predicate));
                             let impl_candidates = self.find_similar_impl_candidates(
                                 predicate.to_opt_poly_trait_pred().unwrap(),
                             );
@@ -2408,7 +2193,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                             err.cancel();
                             return;
                         }
-                        err.note(&format!("cannot satisfy `{}`", predicate));
+                        err.note(format!("cannot satisfy `{}`", predicate));
                     }
                 }
 
@@ -2453,9 +2238,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         err.cancel();
                         err = self.tcx.sess.struct_span_err_with_code(
                             span,
-                            &format!(
+                            format!(
                                 "cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
-                             ),
+                            ),
                             rustc_errors::error_code!(E0790),
                         );
 
@@ -2562,7 +2347,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         ErrorCode::E0284,
                         true,
                     );
-                    err.note(&format!("cannot satisfy `{}`", predicate));
+                    err.note(format!("cannot satisfy `{}`", predicate));
                     err
                 } else {
                     // If we can't find a substitution, just print a generic error
@@ -2573,7 +2358,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "type annotations needed: cannot satisfy `{}`",
                         predicate,
                     );
-                    err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+                    err.span_label(span, format!("cannot satisfy `{}`", predicate));
                     err
                 }
             }
@@ -2601,7 +2386,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                         "type annotations needed: cannot satisfy `{}`",
                         predicate,
                     );
-                    err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+                    err.span_label(span, format!("cannot satisfy `{}`", predicate));
                     err
                 }
             }
@@ -2616,7 +2401,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
                     "type annotations needed: cannot satisfy `{}`",
                     predicate,
                 );
-                err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+                err.span_label(span, format!("cannot satisfy `{}`", predicate));
                 err
             }
         };
@@ -2689,13 +2474,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
 
         match (spans.len(), crates.len(), crate_names.len()) {
             (0, 0, 0) => {
-                err.note(&format!("cannot satisfy `{}`", predicate));
+                err.note(format!("cannot satisfy `{}`", predicate));
             }
             (0, _, 1) => {
-                err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+                err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
             }
             (0, _, _) => {
-                err.note(&format!(
+                err.note(format!(
                     "{} in the following crates: {}{}",
                     msg,
                     crate_names.join(", "),
@@ -2704,19 +2489,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             }
             (_, 0, 0) => {
                 let span: MultiSpan = spans.into();
-                err.span_note(span, &msg);
+                err.span_note(span, msg);
             }
             (_, 1, 1) => {
                 let span: MultiSpan = spans.into();
-                err.span_note(span, &msg);
-                err.note(
-                    &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
-                );
+                err.span_note(span, msg);
+                err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
             }
             _ => {
                 let span: MultiSpan = spans.into();
-                err.span_note(span, &msg);
-                err.note(&format!(
+                err.span_note(span, msg);
+                err.note(format!(
                     "and more `impl`s found in the following crates: {}{}",
                     crate_names.join(", "),
                     post,
@@ -2776,6 +2559,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         // message, and fall back to regular note otherwise.
         if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
             self.note_obligation_cause_code(
+                obligation.cause.body_id,
                 err,
                 obligation.predicate,
                 obligation.param_env,
@@ -2887,7 +2671,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         }
         err.span_help(
             multispan,
-            &format!(
+            format!(
                 "you could relax the implicit `Sized` bound on `{T}` if it were \
                 used through indirection like `&{T}` or `Box<{T}>`",
                 T = param.name.ident(),
@@ -2919,20 +2703,52 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         false
     }
 
+    fn get_standard_error_message(
+        &self,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        message: Option<String>,
+        predicate_is_const: bool,
+        append_const_msg: Option<AppendConstMessage>,
+        post_message: String,
+    ) -> String {
+        message
+            .and_then(|cannot_do_this| {
+                match (predicate_is_const, append_const_msg) {
+                    // do nothing if predicate is not const
+                    (false, _) => Some(cannot_do_this),
+                    // suggested using default post message
+                    (true, Some(AppendConstMessage::Default)) => {
+                        Some(format!("{cannot_do_this} in const contexts"))
+                    }
+                    // overridden post message
+                    (true, Some(AppendConstMessage::Custom(custom_msg))) => {
+                        Some(format!("{cannot_do_this}{custom_msg}"))
+                    }
+                    // fallback to generic message
+                    (true, None) => None,
+                }
+            })
+            .unwrap_or_else(|| {
+                format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message)
+            })
+    }
+
     fn get_safe_transmute_error_and_reason(
         &self,
-        trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
-        obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
-        trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        obligation: PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
         span: Span,
     ) -> (String, Option<String>) {
-        let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
-            dst: p.trait_ref.substs.type_at(0),
-            src: p.trait_ref.substs.type_at(1),
-        });
-        let scope = trait_ref.skip_binder().substs.type_at(2);
+        // Erase regions because layout code doesn't particularly care about regions.
+        let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+
+        let src_and_dst = rustc_transmute::Types {
+            dst: trait_ref.substs.type_at(0),
+            src: trait_ref.substs.type_at(1),
+        };
+        let scope = trait_ref.substs.type_at(2);
         let Some(assume) =
-            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
+            rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
                 span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
             };
         match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2942,24 +2758,27 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             assume,
         ) {
             rustc_transmute::Answer::No(reason) => {
-                let dst = trait_ref.skip_binder().substs.type_at(0);
-                let src = trait_ref.skip_binder().substs.type_at(1);
-                let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string();
+                let dst = trait_ref.substs.type_at(0);
+                let src = trait_ref.substs.type_at(1);
+                let custom_err_msg = format!(
+                    "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
+                );
                 let reason_msg = match reason {
                     rustc_transmute::Reason::SrcIsUnspecified => {
-                        format!("`{src}` does not have a well-specified layout").to_string()
+                        format!("`{src}` does not have a well-specified layout")
                     }
+
                     rustc_transmute::Reason::DstIsUnspecified => {
-                        format!("`{dst}` does not have a well-specified layout").to_string()
+                        format!("`{dst}` does not have a well-specified layout")
                     }
+
                     rustc_transmute::Reason::DstIsBitIncompatible => {
                         format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
-                            .to_string()
                     }
+
                     rustc_transmute::Reason::DstIsPrivate => format!(
                         "`{dst}` is or contains a type or field that is not visible in that scope"
-                    )
-                    .to_string(),
+                    ),
                     // FIXME(bryangarza): Include the number of bytes of src and dst
                     rustc_transmute::Reason::DstIsTooBig => {
                         format!("The size of `{src}` is smaller than the size of `{dst}`")
@@ -2975,8 +2794,449 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             _ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
         }
     }
+
+    fn add_tuple_trait_message(
+        &self,
+        obligation_cause_code: &ObligationCauseCode<'tcx>,
+        err: &mut Diagnostic,
+    ) {
+        match obligation_cause_code {
+            ObligationCauseCode::RustCall => {
+                err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+            }
+            ObligationCauseCode::BindingObligation(def_id, _)
+            | ObligationCauseCode::ItemObligation(def_id)
+                if self.tcx.is_fn_trait(*def_id) =>
+            {
+                err.code(rustc_errors::error_code!(E0059));
+                err.set_primary_message(format!(
+                    "type parameter to bare `{}` trait must be a tuple",
+                    self.tcx.def_path_str(*def_id)
+                ));
+            }
+            _ => {}
+        }
+    }
+
+    fn try_to_add_help_message(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+        is_fn_trait: bool,
+        suggested: bool,
+        unsatisfied_const: bool,
+    ) {
+        let body_def_id = obligation.cause.body_id;
+        // Try to report a help message
+        if is_fn_trait
+            && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+            obligation.param_env,
+            trait_ref.self_ty(),
+            trait_predicate.skip_binder().constness,
+            trait_predicate.skip_binder().polarity,
+        )
+        {
+            self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
+        } else if !trait_ref.has_non_region_infer()
+            && self.predicate_can_apply(obligation.param_env, *trait_predicate)
+        {
+            // If a where-clause may be useful, remind the
+            // user that they can add it.
+            //
+            // don't display an on-unimplemented note, as
+            // these notes will often be of the form
+            //     "the type `T` can't be frobnicated"
+            // which is somewhat confusing.
+            self.suggest_restricting_param_bound(
+                err,
+                *trait_predicate,
+                None,
+                obligation.cause.body_id,
+            );
+        } else if !suggested && !unsatisfied_const {
+            // Can't show anything else useful, try to find similar impls.
+            let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
+            if !self.report_similar_impl_candidates(
+                &impl_candidates,
+                trait_ref,
+                body_def_id,
+                err,
+                true,
+            ) {
+                self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+            }
+
+            self.maybe_suggest_convert_to_slice(
+                err,
+                trait_ref,
+                impl_candidates.as_slice(),
+                span,
+            );
+        }
+    }
+
+    fn add_help_message_for_fn_trait(
+        &self,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        err: &mut Diagnostic,
+        implemented_kind: ty::ClosureKind,
+        params: ty::Binder<'tcx, Ty<'tcx>>,
+    ) {
+        // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
+        // suggestion to add trait bounds for the type, since we only typically implement
+        // these traits once.
+
+        // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
+        // to implement.
+        let selected_kind = self
+            .tcx
+            .fn_trait_kind_from_def_id(trait_ref.def_id())
+            .expect("expected to map DefId to ClosureKind");
+        if !implemented_kind.extends(selected_kind) {
+            err.note(format!(
+                "`{}` implements `{}`, but it must implement `{}`, which is more general",
+                trait_ref.skip_binder().self_ty(),
+                implemented_kind,
+                selected_kind
+            ));
+        }
+
+        // Note any argument mismatches
+        let given_ty = params.skip_binder();
+        let expected_ty = trait_ref.skip_binder().substs.type_at(1);
+        if let ty::Tuple(given) = given_ty.kind()
+            && let ty::Tuple(expected) = expected_ty.kind()
+        {
+            if expected.len() != given.len() {
+                // Note number of types that were expected and given
+                err.note(
+                    format!(
+                        "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+                        given.len(),
+                        pluralize!(given.len()),
+                        expected.len(),
+                        pluralize!(expected.len()),
+                    )
+                );
+            } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
+                // Print type mismatch
+                let (expected_args, given_args) =
+                    self.cmp(given_ty, expected_ty);
+                err.note_expected_found(
+                    &"a closure with arguments",
+                    expected_args,
+                    &"a closure with arguments",
+                    given_args,
+                );
+            }
+        }
+    }
+
+    fn maybe_add_note_for_unsatisfied_const(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        trait_ref: ty::PolyTraitRef<'tcx>,
+        trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+        err: &mut Diagnostic,
+        span: Span,
+    ) -> UnsatisfiedConst {
+        let mut unsatisfied_const = UnsatisfiedConst(false);
+        if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+            let non_const_predicate = trait_ref.without_const();
+            let non_const_obligation = Obligation {
+                cause: obligation.cause.clone(),
+                param_env: obligation.param_env.without_const(),
+                predicate: non_const_predicate.to_predicate(self.tcx),
+                recursion_depth: obligation.recursion_depth,
+            };
+            if self.predicate_may_hold(&non_const_obligation) {
+                unsatisfied_const = UnsatisfiedConst(true);
+                err.span_note(
+                    span,
+                    format!(
+                        "the trait `{}` is implemented for `{}`, \
+                        but that implementation is not `const`",
+                        non_const_predicate.print_modifiers_and_trait_path(),
+                        trait_ref.skip_binder().self_ty(),
+                    ),
+                );
+            }
+        }
+        unsatisfied_const
+    }
+
+    fn report_closure_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        closure_def_id: DefId,
+        found_kind: ty::ClosureKind,
+        kind: ty::ClosureKind,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let closure_span = self.tcx.def_span(closure_def_id);
+        let mut err = struct_span_err!(
+            self.tcx.sess,
+            closure_span,
+            E0525,
+            "expected a closure that implements the `{}` trait, \
+                but this closure only implements `{}`",
+            kind,
+            found_kind
+        );
+
+        err.span_label(
+            closure_span,
+            format!("this closure implements `{}`, not `{}`", found_kind, kind),
+        );
+        err.span_label(
+            obligation.cause.span,
+            format!("the requirement to implement `{}` derives from here", kind),
+        );
+
+        // Additional context information explaining why the closure only implements
+        // a particular trait.
+        if let Some(typeck_results) = &self.typeck_results {
+            let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+            match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
+                (ty::ClosureKind::FnOnce, Some((span, place))) => {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "closure is `FnOnce` because it moves the \
+                            variable `{}` out of its environment",
+                            ty::place_to_string_for_capture(self.tcx, place)
+                        ),
+                    );
+                }
+                (ty::ClosureKind::FnMut, Some((span, place))) => {
+                    err.span_label(
+                        *span,
+                        format!(
+                            "closure is `FnMut` because it mutates the \
+                            variable `{}` here",
+                            ty::place_to_string_for_capture(self.tcx, place)
+                        ),
+                    );
+                }
+                _ => {}
+            }
+        }
+
+        err
+    }
+
+    fn report_type_parameter_mismatch_cyclic_type_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        terr: TypeError<'tcx>,
+    ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+        let self_ty = found_trait_ref.self_ty().skip_binder();
+        let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
+            (
+                ObligationCause::dummy_with_span(self.tcx.def_span(def_id)),
+                TypeError::CyclicTy(self_ty),
+            )
+        } else {
+            (obligation.cause.clone(), terr)
+        };
+        self.report_and_explain_type_error(
+            TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+            terr,
+        )
+    }
+
+    fn report_type_parameter_mismatch_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+        found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+        expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
+        let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
+
+        if expected_trait_ref.self_ty().references_error() {
+            return None;
+        }
+
+        let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
+            return None;
+        };
+
+        let found_did = match *found_trait_ty.kind() {
+            ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) | ty::Generator(did, ..) => {
+                Some(did)
+            }
+            ty::Adt(def, _) => Some(def.did()),
+            _ => None,
+        };
+
+        let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
+        let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
+
+        if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+            // We check closures twice, with obligations flowing in different directions,
+            // but we want to complain about them only once.
+            return None;
+        }
+
+        self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+        let mut not_tupled = false;
+
+        let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
+            ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+            _ => {
+                not_tupled = true;
+                vec![ArgKind::empty()]
+            }
+        };
+
+        let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+        let expected = match expected_ty.kind() {
+            ty::Tuple(ref tys) => {
+                tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
+            }
+            _ => {
+                not_tupled = true;
+                vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
+            }
+        };
+
+        // If this is a `Fn` family trait and either the expected or found
+        // is not tupled, then fall back to just a regular mismatch error.
+        // This shouldn't be common unless manually implementing one of the
+        // traits manually, but don't make it more confusing when it does
+        // happen.
+        Some(
+            if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().gen_trait() && not_tupled
+            {
+                self.report_and_explain_type_error(
+                    TypeTrace::poly_trait_refs(
+                        &obligation.cause,
+                        true,
+                        expected_trait_ref,
+                        found_trait_ref,
+                    ),
+                    ty::error::TypeError::Mismatch,
+                )
+            } else if found.len() == expected.len() {
+                self.report_closure_arg_mismatch(
+                    span,
+                    found_span,
+                    found_trait_ref,
+                    expected_trait_ref,
+                    obligation.cause.code(),
+                    found_node,
+                    obligation.param_env,
+                )
+            } else {
+                let (closure_span, closure_arg_span, found) = found_did
+                    .and_then(|did| {
+                        let node = self.tcx.hir().get_if_local(did)?;
+                        let (found_span, closure_arg_span, found) =
+                            self.get_fn_like_arguments(node)?;
+                        Some((Some(found_span), closure_arg_span, found))
+                    })
+                    .unwrap_or((found_span, None, found));
+
+                self.report_arg_count_mismatch(
+                    span,
+                    closure_span,
+                    expected,
+                    found,
+                    found_trait_ty.is_closure(),
+                    closure_arg_span,
+                )
+            },
+        )
+    }
+
+    fn report_not_const_evaluatable_error(
+        &self,
+        obligation: &PredicateObligation<'tcx>,
+        span: Span,
+    ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+        if !self.tcx.features().generic_const_exprs {
+            let mut err = self
+                .tcx
+                .sess
+                .struct_span_err(span, "constant expression depends on a generic parameter");
+            // FIXME(const_generics): we should suggest to the user how they can resolve this
+            // issue. However, this is currently not actually possible
+            // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
+            //
+            // Note that with `feature(generic_const_exprs)` this case should not
+            // be reachable.
+            err.note("this may fail depending on what value the parameter takes");
+            err.emit();
+            return None;
+        }
+
+        match obligation.predicate.kind().skip_binder() {
+            ty::PredicateKind::ConstEvaluatable(ct) => {
+                let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+                    bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+                };
+                let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+                let const_span = self.tcx.def_span(uv.def);
+                match self.tcx.sess.source_map().span_to_snippet(const_span) {
+                    Ok(snippet) => err.help(format!(
+                        "try adding a `where` bound using this expression: `where [(); {}]:`",
+                        snippet
+                    )),
+                    _ => err.help("consider adding a `where` bound using this expression"),
+                };
+                Some(err)
+            }
+            _ => {
+                span_bug!(
+                    span,
+                    "unexpected non-ConstEvaluatable predicate, this should not be reachable"
+                )
+            }
+        }
+    }
 }
 
+struct UnsatisfiedConst(pub bool);
+
+fn get_explanation_based_on_obligation<'tcx>(
+    obligation: &PredicateObligation<'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+    pre_message: String,
+) -> String {
+    if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+        "consider using `()`, or a `Result`".to_owned()
+    } else {
+        let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+            ty::FnDef(_, _) => Some("fn item"),
+            ty::Closure(_, _) => Some("closure"),
+            _ => None,
+        };
+
+        match ty_desc {
+            Some(desc) => format!(
+                "{}the trait `{}` is not implemented for {} `{}`",
+                pre_message,
+                trait_predicate.print_modifiers_and_trait_path(),
+                desc,
+                trait_ref.skip_binder().self_ty(),
+            ),
+            None => format!(
+                "{}the trait `{}` is not implemented for `{}`",
+                pre_message,
+                trait_predicate.print_modifiers_and_trait_path(),
+                trait_ref.skip_binder().self_ty(),
+            ),
+        }
+    }
+}
 /// Crude way of getting back an `Expr` from a `Span`.
 pub struct FindExprBySpan<'hir> {
     pub span: Span,