about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2024-07-08 16:44:00 -0400
committerMichael Goulet <michael@errs.io>2024-07-09 09:51:56 -0400
commitcd68a28daa460e04875a16b9677117af93046979 (patch)
tree25886f337d7638059fd3213ac5aa6a2422df486a
parent7af825fea4fea17d0b58fcd8c1f2b6fa11638cfb (diff)
downloadrust-cd68a28daa460e04875a16b9677117af93046979.tar.gz
rust-cd68a28daa460e04875a16b9677117af93046979.zip
Move some stuff into the ambiguity and suggestion modules
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs568
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs58
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs169
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs681
4 files changed, 742 insertions, 734 deletions
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
index e6cb28df593..c301deac616 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -1,10 +1,27 @@
+use std::ops::ControlFlow;
+
+use rustc_errors::{
+    struct_span_code_err, Applicability, Diag, MultiSpan, StashKey, E0283, E0284, E0790,
+};
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, Res};
 use rustc_hir::def_id::DefId;
+use rustc_hir::intravisit::Visitor as _;
+use rustc_hir::LangItem;
+use rustc_infer::infer::error_reporting::{TypeAnnotationNeeded, TypeErrCtxt};
 use rustc_infer::infer::{BoundRegionConversionTime, InferCtxt};
 use rustc_infer::traits::util::elaborate;
-use rustc_infer::traits::{Obligation, ObligationCause, PolyTraitObligation};
-use rustc_middle::ty;
-use rustc_span::{Span, DUMMY_SP};
+use rustc_infer::traits::{
+    Obligation, ObligationCause, ObligationCauseCode, PolyTraitObligation, PredicateObligation,
+};
+use rustc_macros::extension;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitable as _, TypeVisitableExt as _};
+use rustc_span::{ErrorGuaranteed, Span, DUMMY_SP};
 
+use crate::error_reporting::traits::suggestions::TypeErrCtxtExt as _;
+use crate::error_reporting::traits::{
+    to_pretty_impl_header, FindExprBySpan, InferCtxtPrivExt as _,
+};
 use crate::traits::query::evaluate_obligation::InferCtxtExt;
 use crate::traits::ObligationCtxt;
 
@@ -134,3 +151,548 @@ pub fn compute_applicable_impls_for_diagnostics<'tcx>(
 
     ambiguities
 }
+
+#[extension(pub trait TypeErrCtxtAmbiguityExt<'a, 'tcx>)]
+impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
+    #[instrument(skip(self), level = "debug")]
+    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
+        // Unable to successfully determine, probably means
+        // insufficient type information, but could mean
+        // ambiguous impls. The latter *ought* to be a
+        // coherence violation, so we don't report it here.
+
+        let predicate = self.resolve_vars_if_possible(obligation.predicate);
+        let span = obligation.cause.span;
+
+        debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
+
+        // Ambiguity errors are often caused as fallout from earlier errors.
+        // We ignore them if this `infcx` is tainted in some cases below.
+
+        let bound_predicate = predicate.kind();
+        let mut err = match bound_predicate.skip_binder() {
+            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
+                let trait_ref = bound_predicate.rebind(data.trait_ref);
+                debug!(?trait_ref);
+
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+
+                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
+                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
+                    // other `Foo` impls are incoherent.
+                    return guar;
+                }
+
+                // This is kind of a hack: it frequently happens that some earlier
+                // error prevents types from being fully inferred, and then we get
+                // a bunch of uninteresting errors saying something like "<generic
+                // #0> doesn't implement Sized". It may even be true that we
+                // could just skip over all checks where the self-ty is an
+                // inference variable, but I was afraid that there might be an
+                // inference variable created, registered as an obligation, and
+                // then never forced by writeback, and hence by skipping here we'd
+                // be ignoring the fact that we don't KNOW the type works
+                // out. Though even that would probably be harmless, given that
+                // we're only talking about builtin traits, which are known to be
+                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
+                // avoid inundating the user with unnecessary errors, but we now
+                // check upstream for type errors and don't add the obligations to
+                // begin with in those cases.
+                if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
+                    match self.tainted_by_errors() {
+                        None => {
+                            let err = self.emit_inference_failure_err(
+                                obligation.cause.body_id,
+                                span,
+                                trait_ref.self_ty().skip_binder().into(),
+                                TypeAnnotationNeeded::E0282,
+                                false,
+                            );
+                            return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
+                        }
+                        Some(e) => return e,
+                    }
+                }
+
+                // Typically, this ambiguity should only happen if
+                // there are unresolved type inference variables
+                // (otherwise it would suggest a coherence
+                // failure). But given #21974 that is not necessarily
+                // the case -- we can have multiple where clauses that
+                // are only distinguished by a region, which results
+                // in an ambiguity even when all types are fully
+                // known, since we don't dispatch based on region
+                // relationships.
+
+                // Pick the first generic parameter that still contains inference variables as the one
+                // we're going to emit an error for. If there are none (see above), fall back to
+                // a more general error.
+                let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
+
+                let mut err = if let Some(arg) = arg {
+                    self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0283,
+                        true,
+                    )
+                } else {
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0283,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                };
+
+                let mut ambiguities = compute_applicable_impls_for_diagnostics(
+                    self.infcx,
+                    &obligation.with(self.tcx, trait_ref),
+                );
+                let has_non_region_infer =
+                    trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
+                // It doesn't make sense to talk about applicable impls if there are more than a
+                // handful of them. If there are a lot of them, but only a few of them have no type
+                // params, we only show those, as they are more likely to be useful/intended.
+                if ambiguities.len() > 5 {
+                    let infcx = self.infcx;
+                    if !ambiguities.iter().all(|option| match option {
+                        CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
+                        CandidateSource::ParamEnv(_) => true,
+                    }) {
+                        // If not all are blanket impls, we filter blanked impls out.
+                        ambiguities.retain(|option| match option {
+                            CandidateSource::DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
+                            CandidateSource::ParamEnv(_) => true,
+                        });
+                    }
+                }
+                if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
+                    if let Some(e) = self.tainted_by_errors()
+                        && arg.is_none()
+                    {
+                        // If `arg.is_none()`, then this is probably two param-env
+                        // candidates or impl candidates that are equal modulo lifetimes.
+                        // Therefore, if we've already emitted an error, just skip this
+                        // one, since it's not particularly actionable.
+                        err.cancel();
+                        return e;
+                    }
+                    self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
+                } else {
+                    if let Some(e) = self.tainted_by_errors() {
+                        err.cancel();
+                        return e;
+                    }
+                    err.note(format!("cannot satisfy `{predicate}`"));
+                    let impl_candidates =
+                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
+                    if impl_candidates.len() < 40 {
+                        self.report_similar_impl_candidates(
+                            impl_candidates.as_slice(),
+                            trait_ref,
+                            obligation.cause.body_id,
+                            &mut err,
+                            false,
+                            obligation.param_env,
+                        );
+                    }
+                }
+
+                if let ObligationCauseCode::WhereClause(def_id, _)
+                | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
+                {
+                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
+                }
+
+                if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
+                    && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+                {
+                    let mut expr_finder = FindExprBySpan::new(span, self.tcx);
+                    expr_finder.visit_expr(&body.value);
+
+                    if let Some(hir::Expr {
+                        kind:
+                            hir::ExprKind::Call(
+                                hir::Expr {
+                                    kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+                                    ..
+                                },
+                                _,
+                            )
+                            | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
+                        ..
+                    }) = expr_finder.result
+                        && let [
+                            ..,
+                            trait_path_segment @ hir::PathSegment {
+                                res: Res::Def(DefKind::Trait, trait_id),
+                                ..
+                            },
+                            hir::PathSegment {
+                                ident: assoc_item_name,
+                                res: Res::Def(_, item_id),
+                                ..
+                            },
+                        ] = path.segments
+                        && data.trait_ref.def_id == *trait_id
+                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
+                        && let None = self.tainted_by_errors()
+                    {
+                        let (verb, noun) = match self.tcx.associated_item(item_id).kind {
+                            ty::AssocKind::Const => ("refer to the", "constant"),
+                            ty::AssocKind::Fn => ("call", "function"),
+                            // This is already covered by E0223, but this following single match
+                            // arm doesn't hurt here.
+                            ty::AssocKind::Type => ("refer to the", "type"),
+                        };
+
+                        // Replace the more general E0283 with a more specific error
+                        err.cancel();
+                        err = self.dcx().struct_span_err(
+                            span,
+                            format!(
+                                "cannot {verb} associated {noun} on trait without specifying the \
+                                 corresponding `impl` type",
+                            ),
+                        );
+                        err.code(E0790);
+
+                        if let Some(local_def_id) = data.trait_ref.def_id.as_local()
+                            && let hir::Node::Item(hir::Item {
+                                ident: trait_name,
+                                kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
+                                ..
+                            }) = self.tcx.hir_node_by_def_id(local_def_id)
+                            && let Some(method_ref) = trait_item_refs
+                                .iter()
+                                .find(|item_ref| item_ref.ident == *assoc_item_name)
+                        {
+                            err.span_label(
+                                method_ref.span,
+                                format!("`{trait_name}::{assoc_item_name}` defined here"),
+                            );
+                        }
+
+                        err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
+
+                        let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
+
+                        if let Some(impl_def_id) =
+                            trait_impls.non_blanket_impls().values().flatten().next()
+                        {
+                            let non_blanket_impl_count =
+                                trait_impls.non_blanket_impls().values().flatten().count();
+                            // If there is only one implementation of the trait, suggest using it.
+                            // Otherwise, use a placeholder comment for the implementation.
+                            let (message, self_type) = if non_blanket_impl_count == 1 {
+                                (
+                                    "use the fully-qualified path to the only available \
+                                     implementation",
+                                    format!(
+                                        "{}",
+                                        self.tcx.type_of(impl_def_id).instantiate_identity()
+                                    ),
+                                )
+                            } else {
+                                (
+                                    "use a fully-qualified path to a specific available \
+                                     implementation",
+                                    "/* self type */".to_string(),
+                                )
+                            };
+                            let mut suggestions =
+                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
+                            if let Some(generic_arg) = trait_path_segment.args {
+                                let between_span =
+                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
+                                // get rid of :: between Trait and <type>
+                                // must be '::' between them, otherwise the parser won't accept the code
+                                suggestions.push((between_span, "".to_string()));
+                                suggestions
+                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
+                            } else {
+                                suggestions.push((
+                                    trait_path_segment.ident.span.shrink_to_hi(),
+                                    ">".to_string(),
+                                ));
+                            }
+                            err.multipart_suggestion(
+                                message,
+                                suggestions,
+                                Applicability::MaybeIncorrect,
+                            );
+                        }
+                    }
+                };
+
+                err
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
+                // Same hacky approach as above to avoid deluging user
+                // with error messages.
+
+                if let Err(e) = arg.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                self.emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    arg,
+                    TypeAnnotationNeeded::E0282,
+                    false,
+                )
+            }
+
+            ty::PredicateKind::Subtype(data) => {
+                if let Err(e) = data.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                let ty::SubtypePredicate { a_is_expected: _, a, b } = data;
+                // both must be type variables, or the other would've been instantiated
+                assert!(a.is_ty_var() && b.is_ty_var());
+                self.emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    a.into(),
+                    TypeAnnotationNeeded::E0282,
+                    true,
+                )
+            }
+            ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+
+                if let Err(guar) =
+                    self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id))
+                {
+                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
+                    // other `Foo` impls are incoherent.
+                    return guar;
+                }
+                let arg = data
+                    .projection_term
+                    .args
+                    .iter()
+                    .chain(Some(data.term.into_arg()))
+                    .find(|g| g.has_non_region_infer());
+                if let Some(arg) = arg {
+                    self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0284,
+                        true,
+                    )
+                    .with_note(format!("cannot satisfy `{predicate}`"))
+                } else {
+                    // If we can't find a generic parameter, just print a generic error
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0284,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+                }
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
+                if let Err(e) = predicate.error_reported() {
+                    return e;
+                }
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                let arg = data.walk().find(|g| g.is_non_region_infer());
+                if let Some(arg) = arg {
+                    let err = self.emit_inference_failure_err(
+                        obligation.cause.body_id,
+                        span,
+                        arg,
+                        TypeAnnotationNeeded::E0284,
+                        true,
+                    );
+                    err
+                } else {
+                    // If we can't find a generic parameter, just print a generic error
+                    struct_span_code_err!(
+                        self.dcx(),
+                        span,
+                        E0284,
+                        "type annotations needed: cannot satisfy `{}`",
+                        predicate,
+                    )
+                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+                }
+            }
+
+            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
+                .emit_inference_failure_err(
+                    obligation.cause.body_id,
+                    span,
+                    ct.into(),
+                    TypeAnnotationNeeded::E0284,
+                    true,
+                ),
+            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
+                if term.is_infer() =>
+            {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0284,
+                    "type annotations needed: cannot normalize `{alias}`",
+                )
+                .with_span_label(span, format!("cannot normalize `{alias}`"))
+            }
+
+            _ => {
+                if let Some(e) = self.tainted_by_errors() {
+                    return e;
+                }
+                struct_span_code_err!(
+                    self.dcx(),
+                    span,
+                    E0284,
+                    "type annotations needed: cannot satisfy `{}`",
+                    predicate,
+                )
+                .with_span_label(span, format!("cannot satisfy `{predicate}`"))
+            }
+        };
+        self.note_obligation_cause(&mut err, obligation);
+        err.emit()
+    }
+
+    fn annotate_source_of_ambiguity(
+        &self,
+        err: &mut Diag<'_>,
+        ambiguities: &[CandidateSource],
+        predicate: ty::Predicate<'tcx>,
+    ) {
+        let mut spans = vec![];
+        let mut crates = vec![];
+        let mut post = vec![];
+        let mut has_param_env = false;
+        for ambiguity in ambiguities {
+            match ambiguity {
+                CandidateSource::DefId(impl_def_id) => match self.tcx.span_of_impl(*impl_def_id) {
+                    Ok(span) => spans.push(span),
+                    Err(name) => {
+                        crates.push(name);
+                        if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
+                            post.push(header);
+                        }
+                    }
+                },
+                CandidateSource::ParamEnv(span) => {
+                    has_param_env = true;
+                    spans.push(*span);
+                }
+            }
+        }
+        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
+        crate_names.sort();
+        crate_names.dedup();
+        post.sort();
+        post.dedup();
+
+        if self.tainted_by_errors().is_some()
+            && (crate_names.len() == 1
+                && spans.len() == 0
+                && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
+                || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
+        {
+            // Avoid complaining about other inference issues for expressions like
+            // `42 >> 1`, where the types are still `{integer}`, but we want to
+            // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
+            // NOTE(eddyb) this was `.cancel()`, but `err`
+            // is borrowed, so we can't fully defuse it.
+            err.downgrade_to_delayed_bug();
+            return;
+        }
+
+        let msg = format!(
+            "multiple `impl`s{} satisfying `{}` found",
+            if has_param_env { " or `where` clauses" } else { "" },
+            predicate
+        );
+        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
+            format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
+        } else if post.len() == 1 {
+            format!(": `{}`", post[0])
+        } else {
+            String::new()
+        };
+
+        match (spans.len(), crates.len(), crate_names.len()) {
+            (0, 0, 0) => {
+                err.note(format!("cannot satisfy `{predicate}`"));
+            }
+            (0, _, 1) => {
+                err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
+            }
+            (0, _, _) => {
+                err.note(format!(
+                    "{} in the following crates: {}{}",
+                    msg,
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+            (_, 0, 0) => {
+                let span: MultiSpan = spans.into();
+                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,));
+            }
+            _ => {
+                let span: MultiSpan = spans.into();
+                err.span_note(span, msg);
+                err.note(format!(
+                    "and more `impl`s found in the following crates: {}{}",
+                    crate_names.join(", "),
+                    post,
+                ));
+            }
+        }
+    }
+}
+
+struct HasNumericInferVisitor;
+
+impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
+    type Result = ControlFlow<()>;
+
+    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
+        if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
+            ControlFlow::Break(())
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
index 7d334d623cc..e776248e684 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -15,7 +15,6 @@ use rustc_infer::traits::{Obligation, ObligationCause, ObligationCauseCode, Pred
 use rustc_middle::ty::print::PrintTraitRefExt as _;
 use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_span::Span;
-use std::ops::ControlFlow;
 
 pub use self::infer_ctxt_ext::*;
 pub use self::overflow::*;
@@ -91,49 +90,6 @@ impl<'v> Visitor<'v> for FindExprBySpan<'v> {
     }
 }
 
-/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
-/// `param: ?Sized` would be a valid constraint.
-struct FindTypeParam {
-    param: rustc_span::Symbol,
-    invalid_spans: Vec<Span>,
-    nested: bool,
-}
-
-impl<'v> Visitor<'v> for FindTypeParam {
-    fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
-        // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
-    }
-
-    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
-        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
-        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
-        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
-        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
-        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
-        // in that case should make what happened clear enough.
-        match ty.kind {
-            hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
-            hir::TyKind::Path(hir::QPath::Resolved(None, path))
-                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
-            {
-                if !self.nested {
-                    debug!(?ty, "FindTypeParam::visit_ty");
-                    self.invalid_spans.push(ty.span);
-                }
-            }
-            hir::TyKind::Path(_) => {
-                let prev = self.nested;
-                self.nested = true;
-                hir::intravisit::walk_ty(self, ty);
-                self.nested = prev;
-            }
-            _ => {
-                hir::intravisit::walk_ty(self, ty);
-            }
-        }
-    }
-}
-
 /// Summarizes information
 #[derive(Clone)]
 pub enum ArgKind {
@@ -165,20 +121,6 @@ impl ArgKind {
     }
 }
 
-struct HasNumericInferVisitor;
-
-impl<'tcx> ty::TypeVisitor<TyCtxt<'tcx>> for HasNumericInferVisitor {
-    type Result = ControlFlow<()>;
-
-    fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result {
-        if matches!(ty.kind(), ty::Infer(ty::FloatVar(_) | ty::IntVar(_))) {
-            ControlFlow::Break(())
-        } else {
-            ControlFlow::Continue(())
-        }
-    }
-}
-
 #[derive(Copy, Clone)]
 pub enum DefIdOrName {
     DefId(DefId),
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
index fdc6db4abec..11a2b1d3233 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -4623,6 +4623,132 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             );
         }
     }
+
+    #[instrument(level = "debug", skip_all)]
+    fn suggest_unsized_bound_if_applicable(
+        &self,
+        err: &mut Diag<'_>,
+        obligation: &PredicateObligation<'tcx>,
+    ) {
+        let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
+            obligation.predicate.kind().skip_binder()
+        else {
+            return;
+        };
+        let (ObligationCauseCode::WhereClause(item_def_id, span)
+        | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
+            *obligation.cause.code().peel_derives()
+        else {
+            return;
+        };
+        if span.is_dummy() {
+            return;
+        }
+        debug!(?pred, ?item_def_id, ?span);
+
+        let (Some(node), true) = (
+            self.tcx.hir().get_if_local(item_def_id),
+            self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
+        ) else {
+            return;
+        };
+
+        let Some(generics) = node.generics() else {
+            return;
+        };
+        let sized_trait = self.tcx.lang_items().sized_trait();
+        debug!(?generics.params);
+        debug!(?generics.predicates);
+        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
+            return;
+        };
+        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
+        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
+        let explicitly_sized = generics
+            .bounds_for_param(param.def_id)
+            .flat_map(|bp| bp.bounds)
+            .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
+        if explicitly_sized {
+            return;
+        }
+        debug!(?param);
+        match node {
+            hir::Node::Item(
+                item @ hir::Item {
+                    // Only suggest indirection for uses of type parameters in ADTs.
+                    kind:
+                        hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
+                    ..
+                },
+            ) => {
+                if self.suggest_indirection_for_unsized(err, item, param) {
+                    return;
+                }
+            }
+            _ => {}
+        };
+
+        // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
+        let (span, separator, open_paren_sp) =
+            if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
+                (s, " +", open_paren_sp)
+            } else {
+                (param.name.ident().span.shrink_to_hi(), ":", None)
+            };
+
+        let mut suggs = vec![];
+        let suggestion = format!("{separator} ?Sized");
+
+        if let Some(open_paren_sp) = open_paren_sp {
+            suggs.push((open_paren_sp, "(".to_string()));
+            suggs.push((span, format!("){suggestion}")));
+        } else {
+            suggs.push((span, suggestion));
+        }
+
+        err.multipart_suggestion_verbose(
+            "consider relaxing the implicit `Sized` restriction",
+            suggs,
+            Applicability::MachineApplicable,
+        );
+    }
+
+    fn suggest_indirection_for_unsized(
+        &self,
+        err: &mut Diag<'_>,
+        item: &hir::Item<'tcx>,
+        param: &hir::GenericParam<'tcx>,
+    ) -> bool {
+        // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
+        // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
+        // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
+        let mut visitor =
+            FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
+        visitor.visit_item(item);
+        if visitor.invalid_spans.is_empty() {
+            return false;
+        }
+        let mut multispan: MultiSpan = param.span.into();
+        multispan.push_span_label(
+            param.span,
+            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
+        );
+        for sp in visitor.invalid_spans {
+            multispan.push_span_label(
+                sp,
+                format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
+            );
+        }
+        err.span_help(
+            multispan,
+            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(),
+            ),
+        );
+        true
+    }
 }
 
 /// Add a hint to add a missing borrow or remove an unnecessary one.
@@ -5126,3 +5252,46 @@ fn get_deref_type_and_refs(mut ty: Ty<'_>) -> (Ty<'_>, Vec<hir::Mutability>) {
 
     (ty, refs)
 }
+
+/// Look for type `param` in an ADT being used only through a reference to confirm that suggesting
+/// `param: ?Sized` would be a valid constraint.
+struct FindTypeParam {
+    param: rustc_span::Symbol,
+    invalid_spans: Vec<Span>,
+    nested: bool,
+}
+
+impl<'v> Visitor<'v> for FindTypeParam {
+    fn visit_where_predicate(&mut self, _: &'v hir::WherePredicate<'v>) {
+        // Skip where-clauses, to avoid suggesting indirection for type parameters found there.
+    }
+
+    fn visit_ty(&mut self, ty: &hir::Ty<'_>) {
+        // We collect the spans of all uses of the "bare" type param, like in `field: T` or
+        // `field: (T, T)` where we could make `T: ?Sized` while skipping cases that are known to be
+        // valid like `field: &'a T` or `field: *mut T` and cases that *might* have further `Sized`
+        // obligations like `Box<T>` and `Vec<T>`, but we perform no extra analysis for those cases
+        // and suggest `T: ?Sized` regardless of their obligations. This is fine because the errors
+        // in that case should make what happened clear enough.
+        match ty.kind {
+            hir::TyKind::Ptr(_) | hir::TyKind::Ref(..) | hir::TyKind::TraitObject(..) => {}
+            hir::TyKind::Path(hir::QPath::Resolved(None, path))
+                if path.segments.len() == 1 && path.segments[0].ident.name == self.param =>
+            {
+                if !self.nested {
+                    debug!(?ty, "FindTypeParam::visit_ty");
+                    self.invalid_spans.push(ty.span);
+                }
+            }
+            hir::TyKind::Path(_) => {
+                let prev = self.nested;
+                self.nested = true;
+                hir::intravisit::walk_ty(self, ty);
+                self.nested = prev;
+            }
+            _ => {
+                hir::intravisit::walk_ty(self, ty);
+            }
+        }
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs
index ee5f4f44251..dec3b26420c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/type_err_ctxt_ext.rs
@@ -1,15 +1,12 @@
-// ignore-tidy-filelength :(
-
+use super::ambiguity::TypeErrCtxtAmbiguityExt as _;
 use super::on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
 use super::suggestions::{get_explanation_based_on_obligation, TypeErrCtxtExt as _};
 use crate::error_reporting::traits::infer_ctxt_ext::InferCtxtExt;
 use crate::error_reporting::traits::overflow::TypeErrCtxtOverflowExt;
-use crate::error_reporting::traits::to_pretty_impl_header;
-use crate::error_reporting::traits::{ambiguity, ambiguity::CandidateSource::*};
 use crate::errors::{
     AsyncClosureNotFn, ClosureFnMutLabel, ClosureFnOnceLabel, ClosureKindMismatch,
 };
-use crate::infer::error_reporting::{TyCategory, TypeAnnotationNeeded as ErrorCode};
+use crate::infer::error_reporting::TyCategory;
 use crate::infer::InferCtxtExt as _;
 use crate::infer::{self, InferCtxt};
 use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -23,13 +20,13 @@ use core::ops::ControlFlow;
 use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
 use rustc_data_structures::unord::UnordSet;
 use rustc_errors::codes::*;
-use rustc_errors::{pluralize, struct_span_code_err, Applicability, MultiSpan, StringPart};
+use rustc_errors::{pluralize, struct_span_code_err, Applicability, StringPart};
 use rustc_errors::{Diag, ErrorGuaranteed, StashKey};
-use rustc_hir::def::{DefKind, Namespace, Res};
+use rustc_hir::def::Namespace;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::Visitor;
+use rustc_hir::Node;
 use rustc_hir::{self as hir, LangItem};
-use rustc_hir::{GenericParam, Item, Node};
 use rustc_infer::infer::error_reporting::TypeErrCtxt;
 use rustc_infer::infer::{InferOk, TypeTrace};
 use rustc_macros::extension;
@@ -43,8 +40,7 @@ use rustc_middle::ty::print::{
     PrintTraitRefExt as _,
 };
 use rustc_middle::ty::{
-    self, SubtypePredicate, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitable,
-    TypeVisitableExt, Upcast,
+    self, ToPolyTraitRef, TraitRef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, Upcast,
 };
 use rustc_middle::{bug, span_bug};
 use rustc_span::symbol::sym;
@@ -53,8 +49,7 @@ use std::borrow::Cow;
 use std::iter;
 
 use super::{
-    ArgKind, CandidateSimilarity, FindExprBySpan, FindTypeParam, GetSafeTransmuteErrorAndReason,
-    HasNumericInferVisitor, ImplCandidate, UnsatisfiedConst,
+    ArgKind, CandidateSimilarity, GetSafeTransmuteErrorAndReason, ImplCandidate, UnsatisfiedConst,
 };
 
 pub use rustc_infer::traits::error_reporting::*;
@@ -956,7 +951,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     }
 
     /// When the `E` of the resulting `Result<T, E>` in an expression `foo().bar().baz()?`,
-    /// identify thoe method chain sub-expressions that could or could not have been annotated
+    /// identify those method chain sub-expressions that could or could not have been annotated
     /// with `?`.
     fn try_conversion_context(
         &self,
@@ -2172,536 +2167,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         Obligation::new(self.tcx, ObligationCause::dummy(), param_env, trait_pred)
     }
 
-    #[instrument(skip(self), level = "debug")]
-    fn maybe_report_ambiguity(&self, obligation: &PredicateObligation<'tcx>) -> ErrorGuaranteed {
-        // Unable to successfully determine, probably means
-        // insufficient type information, but could mean
-        // ambiguous impls. The latter *ought* to be a
-        // coherence violation, so we don't report it here.
-
-        let predicate = self.resolve_vars_if_possible(obligation.predicate);
-        let span = obligation.cause.span;
-
-        debug!(?predicate, obligation.cause.code = ?obligation.cause.code());
-
-        // Ambiguity errors are often caused as fallout from earlier errors.
-        // We ignore them if this `infcx` is tainted in some cases below.
-
-        let bound_predicate = predicate.kind();
-        let mut err = match bound_predicate.skip_binder() {
-            ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => {
-                let trait_ref = bound_predicate.rebind(data.trait_ref);
-                debug!(?trait_ref);
-
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-
-                if let Err(guar) = self.tcx.ensure().coherent_trait(trait_ref.def_id()) {
-                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
-                    // other `Foo` impls are incoherent.
-                    return guar;
-                }
-
-                // This is kind of a hack: it frequently happens that some earlier
-                // error prevents types from being fully inferred, and then we get
-                // a bunch of uninteresting errors saying something like "<generic
-                // #0> doesn't implement Sized". It may even be true that we
-                // could just skip over all checks where the self-ty is an
-                // inference variable, but I was afraid that there might be an
-                // inference variable created, registered as an obligation, and
-                // then never forced by writeback, and hence by skipping here we'd
-                // be ignoring the fact that we don't KNOW the type works
-                // out. Though even that would probably be harmless, given that
-                // we're only talking about builtin traits, which are known to be
-                // inhabited. We used to check for `self.tcx.sess.has_errors()` to
-                // avoid inundating the user with unnecessary errors, but we now
-                // check upstream for type errors and don't add the obligations to
-                // begin with in those cases.
-                if self.tcx.is_lang_item(trait_ref.def_id(), LangItem::Sized) {
-                    match self.tainted_by_errors() {
-                        None => {
-                            let err = self.emit_inference_failure_err(
-                                obligation.cause.body_id,
-                                span,
-                                trait_ref.self_ty().skip_binder().into(),
-                                ErrorCode::E0282,
-                                false,
-                            );
-                            return err.stash(span, StashKey::MaybeForgetReturn).unwrap();
-                        }
-                        Some(e) => return e,
-                    }
-                }
-
-                // Typically, this ambiguity should only happen if
-                // there are unresolved type inference variables
-                // (otherwise it would suggest a coherence
-                // failure). But given #21974 that is not necessarily
-                // the case -- we can have multiple where clauses that
-                // are only distinguished by a region, which results
-                // in an ambiguity even when all types are fully
-                // known, since we don't dispatch based on region
-                // relationships.
-
-                // Pick the first generic parameter that still contains inference variables as the one
-                // we're going to emit an error for. If there are none (see above), fall back to
-                // a more general error.
-                let arg = data.trait_ref.args.iter().find(|s| s.has_non_region_infer());
-
-                let mut err = if let Some(arg) = arg {
-                    self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0283,
-                        true,
-                    )
-                } else {
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0283,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                };
-
-                let mut ambiguities = ambiguity::compute_applicable_impls_for_diagnostics(
-                    self.infcx,
-                    &obligation.with(self.tcx, trait_ref),
-                );
-                let has_non_region_infer =
-                    trait_ref.skip_binder().args.types().any(|t| !t.is_ty_or_numeric_infer());
-                // It doesn't make sense to talk about applicable impls if there are more than a
-                // handful of them. If there are a lot of them, but only a few of them have no type
-                // params, we only show those, as they are more likely to be useful/intended.
-                if ambiguities.len() > 5 {
-                    let infcx = self.infcx;
-                    if !ambiguities.iter().all(|option| match option {
-                        DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
-                        ParamEnv(_) => true,
-                    }) {
-                        // If not all are blanket impls, we filter blanked impls out.
-                        ambiguities.retain(|option| match option {
-                            DefId(did) => infcx.tcx.generics_of(*did).count() == 0,
-                            ParamEnv(_) => true,
-                        });
-                    }
-                }
-                if ambiguities.len() > 1 && ambiguities.len() < 10 && has_non_region_infer {
-                    if let Some(e) = self.tainted_by_errors()
-                        && arg.is_none()
-                    {
-                        // If `arg.is_none()`, then this is probably two param-env
-                        // candidates or impl candidates that are equal modulo lifetimes.
-                        // Therefore, if we've already emitted an error, just skip this
-                        // one, since it's not particularly actionable.
-                        err.cancel();
-                        return e;
-                    }
-                    self.annotate_source_of_ambiguity(&mut err, &ambiguities, predicate);
-                } else {
-                    if let Some(e) = self.tainted_by_errors() {
-                        err.cancel();
-                        return e;
-                    }
-                    err.note(format!("cannot satisfy `{predicate}`"));
-                    let impl_candidates =
-                        self.find_similar_impl_candidates(predicate.as_trait_clause().unwrap());
-                    if impl_candidates.len() < 40 {
-                        self.report_similar_impl_candidates(
-                            impl_candidates.as_slice(),
-                            trait_ref,
-                            obligation.cause.body_id,
-                            &mut err,
-                            false,
-                            obligation.param_env,
-                        );
-                    }
-                }
-
-                if let ObligationCauseCode::WhereClause(def_id, _)
-                | ObligationCauseCode::WhereClauseInExpr(def_id, ..) = *obligation.cause.code()
-                {
-                    self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id());
-                }
-
-                if let Some(ty::GenericArgKind::Type(_)) = arg.map(|arg| arg.unpack())
-                    && let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
-                {
-                    let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-                    expr_finder.visit_expr(&body.value);
-
-                    if let Some(hir::Expr {
-                        kind:
-                            hir::ExprKind::Call(
-                                hir::Expr {
-                                    kind: hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
-                                    ..
-                                },
-                                _,
-                            )
-                            | hir::ExprKind::Path(hir::QPath::Resolved(None, path)),
-                        ..
-                    }) = expr_finder.result
-                        && let [
-                            ..,
-                            trait_path_segment @ hir::PathSegment {
-                                res: Res::Def(DefKind::Trait, trait_id),
-                                ..
-                            },
-                            hir::PathSegment {
-                                ident: assoc_item_name,
-                                res: Res::Def(_, item_id),
-                                ..
-                            },
-                        ] = path.segments
-                        && data.trait_ref.def_id == *trait_id
-                        && self.tcx.trait_of_item(*item_id) == Some(*trait_id)
-                        && let None = self.tainted_by_errors()
-                    {
-                        let (verb, noun) = match self.tcx.associated_item(item_id).kind {
-                            ty::AssocKind::Const => ("refer to the", "constant"),
-                            ty::AssocKind::Fn => ("call", "function"),
-                            // This is already covered by E0223, but this following single match
-                            // arm doesn't hurt here.
-                            ty::AssocKind::Type => ("refer to the", "type"),
-                        };
-
-                        // Replace the more general E0283 with a more specific error
-                        err.cancel();
-                        err = self.dcx().struct_span_err(
-                            span,
-                            format!(
-                                "cannot {verb} associated {noun} on trait without specifying the \
-                                 corresponding `impl` type",
-                            ),
-                        );
-                        err.code(E0790);
-
-                        if let Some(local_def_id) = data.trait_ref.def_id.as_local()
-                            && let hir::Node::Item(hir::Item {
-                                ident: trait_name,
-                                kind: hir::ItemKind::Trait(_, _, _, _, trait_item_refs),
-                                ..
-                            }) = self.tcx.hir_node_by_def_id(local_def_id)
-                            && let Some(method_ref) = trait_item_refs
-                                .iter()
-                                .find(|item_ref| item_ref.ident == *assoc_item_name)
-                        {
-                            err.span_label(
-                                method_ref.span,
-                                format!("`{trait_name}::{assoc_item_name}` defined here"),
-                            );
-                        }
-
-                        err.span_label(span, format!("cannot {verb} associated {noun} of trait"));
-
-                        let trait_impls = self.tcx.trait_impls_of(data.trait_ref.def_id);
-
-                        if let Some(impl_def_id) =
-                            trait_impls.non_blanket_impls().values().flatten().next()
-                        {
-                            let non_blanket_impl_count =
-                                trait_impls.non_blanket_impls().values().flatten().count();
-                            // If there is only one implementation of the trait, suggest using it.
-                            // Otherwise, use a placeholder comment for the implementation.
-                            let (message, self_type) = if non_blanket_impl_count == 1 {
-                                (
-                                    "use the fully-qualified path to the only available \
-                                     implementation",
-                                    format!(
-                                        "{}",
-                                        self.tcx.type_of(impl_def_id).instantiate_identity()
-                                    ),
-                                )
-                            } else {
-                                (
-                                    "use a fully-qualified path to a specific available \
-                                     implementation",
-                                    "/* self type */".to_string(),
-                                )
-                            };
-                            let mut suggestions =
-                                vec![(path.span.shrink_to_lo(), format!("<{self_type} as "))];
-                            if let Some(generic_arg) = trait_path_segment.args {
-                                let between_span =
-                                    trait_path_segment.ident.span.between(generic_arg.span_ext);
-                                // get rid of :: between Trait and <type>
-                                // must be '::' between them, otherwise the parser won't accept the code
-                                suggestions.push((between_span, "".to_string()));
-                                suggestions
-                                    .push((generic_arg.span_ext.shrink_to_hi(), ">".to_string()));
-                            } else {
-                                suggestions.push((
-                                    trait_path_segment.ident.span.shrink_to_hi(),
-                                    ">".to_string(),
-                                ));
-                            }
-                            err.multipart_suggestion(
-                                message,
-                                suggestions,
-                                Applicability::MaybeIncorrect,
-                            );
-                        }
-                    }
-                };
-
-                err
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(arg)) => {
-                // Same hacky approach as above to avoid deluging user
-                // with error messages.
-
-                if let Err(e) = arg.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-
-                self.emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    arg,
-                    ErrorCode::E0282,
-                    false,
-                )
-            }
-
-            ty::PredicateKind::Subtype(data) => {
-                if let Err(e) = data.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                let SubtypePredicate { a_is_expected: _, a, b } = data;
-                // both must be type variables, or the other would've been instantiated
-                assert!(a.is_ty_var() && b.is_ty_var());
-                self.emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    a.into(),
-                    ErrorCode::E0282,
-                    true,
-                )
-            }
-            ty::PredicateKind::Clause(ty::ClauseKind::Projection(data)) => {
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-
-                if let Err(guar) =
-                    self.tcx.ensure().coherent_trait(self.tcx.parent(data.projection_term.def_id))
-                {
-                    // Avoid bogus "type annotations needed `Foo: Bar`" errors on `impl Bar for Foo` in case
-                    // other `Foo` impls are incoherent.
-                    return guar;
-                }
-                let arg = data
-                    .projection_term
-                    .args
-                    .iter()
-                    .chain(Some(data.term.into_arg()))
-                    .find(|g| g.has_non_region_infer());
-                if let Some(arg) = arg {
-                    self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0284,
-                        true,
-                    )
-                    .with_note(format!("cannot satisfy `{predicate}`"))
-                } else {
-                    // If we can't find a generic parameter, just print a generic error
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-                }
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(data)) => {
-                if let Err(e) = predicate.error_reported() {
-                    return e;
-                }
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                let arg = data.walk().find(|g| g.is_non_region_infer());
-                if let Some(arg) = arg {
-                    let err = self.emit_inference_failure_err(
-                        obligation.cause.body_id,
-                        span,
-                        arg,
-                        ErrorCode::E0284,
-                        true,
-                    );
-                    err
-                } else {
-                    // If we can't find a generic parameter, just print a generic error
-                    struct_span_code_err!(
-                        self.dcx(),
-                        span,
-                        E0284,
-                        "type annotations needed: cannot satisfy `{}`",
-                        predicate,
-                    )
-                    .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-                }
-            }
-
-            ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, ..)) => self
-                .emit_inference_failure_err(
-                    obligation.cause.body_id,
-                    span,
-                    ct.into(),
-                    ErrorCode::E0284,
-                    true,
-                ),
-            ty::PredicateKind::NormalizesTo(ty::NormalizesTo { alias, term })
-                if term.is_infer() =>
-            {
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                struct_span_code_err!(
-                    self.dcx(),
-                    span,
-                    E0284,
-                    "type annotations needed: cannot normalize `{alias}`",
-                )
-                .with_span_label(span, format!("cannot normalize `{alias}`"))
-            }
-
-            _ => {
-                if let Some(e) = self.tainted_by_errors() {
-                    return e;
-                }
-                struct_span_code_err!(
-                    self.dcx(),
-                    span,
-                    E0284,
-                    "type annotations needed: cannot satisfy `{}`",
-                    predicate,
-                )
-                .with_span_label(span, format!("cannot satisfy `{predicate}`"))
-            }
-        };
-        self.note_obligation_cause(&mut err, obligation);
-        err.emit()
-    }
-
-    fn annotate_source_of_ambiguity(
-        &self,
-        err: &mut Diag<'_>,
-        ambiguities: &[ambiguity::CandidateSource],
-        predicate: ty::Predicate<'tcx>,
-    ) {
-        let mut spans = vec![];
-        let mut crates = vec![];
-        let mut post = vec![];
-        let mut has_param_env = false;
-        for ambiguity in ambiguities {
-            match ambiguity {
-                ambiguity::CandidateSource::DefId(impl_def_id) => {
-                    match self.tcx.span_of_impl(*impl_def_id) {
-                        Ok(span) => spans.push(span),
-                        Err(name) => {
-                            crates.push(name);
-                            if let Some(header) = to_pretty_impl_header(self.tcx, *impl_def_id) {
-                                post.push(header);
-                            }
-                        }
-                    }
-                }
-                ambiguity::CandidateSource::ParamEnv(span) => {
-                    has_param_env = true;
-                    spans.push(*span);
-                }
-            }
-        }
-        let mut crate_names: Vec<_> = crates.iter().map(|n| format!("`{n}`")).collect();
-        crate_names.sort();
-        crate_names.dedup();
-        post.sort();
-        post.dedup();
-
-        if self.tainted_by_errors().is_some()
-            && (crate_names.len() == 1
-                && spans.len() == 0
-                && ["`core`", "`alloc`", "`std`"].contains(&crate_names[0].as_str())
-                || predicate.visit_with(&mut HasNumericInferVisitor).is_break())
-        {
-            // Avoid complaining about other inference issues for expressions like
-            // `42 >> 1`, where the types are still `{integer}`, but we want to
-            // Do we need `trait_ref.skip_binder().self_ty().is_numeric() &&` too?
-            // NOTE(eddyb) this was `.cancel()`, but `err`
-            // is borrowed, so we can't fully defuse it.
-            err.downgrade_to_delayed_bug();
-            return;
-        }
-
-        let msg = format!(
-            "multiple `impl`s{} satisfying `{}` found",
-            if has_param_env { " or `where` clauses" } else { "" },
-            predicate
-        );
-        let post = if post.len() > 1 || (post.len() == 1 && post[0].contains('\n')) {
-            format!(":\n{}", post.iter().map(|p| format!("- {p}")).collect::<Vec<_>>().join("\n"),)
-        } else if post.len() == 1 {
-            format!(": `{}`", post[0])
-        } else {
-            String::new()
-        };
-
-        match (spans.len(), crates.len(), crate_names.len()) {
-            (0, 0, 0) => {
-                err.note(format!("cannot satisfy `{predicate}`"));
-            }
-            (0, _, 1) => {
-                err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
-            }
-            (0, _, _) => {
-                err.note(format!(
-                    "{} in the following crates: {}{}",
-                    msg,
-                    crate_names.join(", "),
-                    post,
-                ));
-            }
-            (_, 0, 0) => {
-                let span: MultiSpan = spans.into();
-                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,));
-            }
-            _ => {
-                let span: MultiSpan = spans.into();
-                err.span_note(span, msg);
-                err.note(format!(
-                    "and more `impl`s found in the following crates: {}{}",
-                    crate_names.join(", "),
-                    post,
-                ));
-            }
-        }
-    }
-
     /// Returns `true` if the trait predicate may apply for *some* assignment
     /// to the type parameters.
     fn predicate_can_apply(
@@ -2769,136 +2234,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
     }
 
-    #[instrument(level = "debug", skip_all)]
-    fn suggest_unsized_bound_if_applicable(
-        &self,
-        err: &mut Diag<'_>,
-        obligation: &PredicateObligation<'tcx>,
-    ) {
-        let ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) =
-            obligation.predicate.kind().skip_binder()
-        else {
-            return;
-        };
-        let (ObligationCauseCode::WhereClause(item_def_id, span)
-        | ObligationCauseCode::WhereClauseInExpr(item_def_id, span, ..)) =
-            *obligation.cause.code().peel_derives()
-        else {
-            return;
-        };
-        if span.is_dummy() {
-            return;
-        }
-        debug!(?pred, ?item_def_id, ?span);
-
-        let (Some(node), true) = (
-            self.tcx.hir().get_if_local(item_def_id),
-            self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
-        ) else {
-            return;
-        };
-        self.maybe_suggest_unsized_generics(err, span, node);
-    }
-
-    #[instrument(level = "debug", skip_all)]
-    fn maybe_suggest_unsized_generics(&self, err: &mut Diag<'_>, span: Span, node: Node<'tcx>) {
-        let Some(generics) = node.generics() else {
-            return;
-        };
-        let sized_trait = self.tcx.lang_items().sized_trait();
-        debug!(?generics.params);
-        debug!(?generics.predicates);
-        let Some(param) = generics.params.iter().find(|param| param.span == span) else {
-            return;
-        };
-        // Check that none of the explicit trait bounds is `Sized`. Assume that an explicit
-        // `Sized` bound is there intentionally and we don't need to suggest relaxing it.
-        let explicitly_sized = generics
-            .bounds_for_param(param.def_id)
-            .flat_map(|bp| bp.bounds)
-            .any(|bound| bound.trait_ref().and_then(|tr| tr.trait_def_id()) == sized_trait);
-        if explicitly_sized {
-            return;
-        }
-        debug!(?param);
-        match node {
-            hir::Node::Item(
-                item @ hir::Item {
-                    // Only suggest indirection for uses of type parameters in ADTs.
-                    kind:
-                        hir::ItemKind::Enum(..) | hir::ItemKind::Struct(..) | hir::ItemKind::Union(..),
-                    ..
-                },
-            ) => {
-                if self.maybe_indirection_for_unsized(err, item, param) {
-                    return;
-                }
-            }
-            _ => {}
-        };
-
-        // Didn't add an indirection suggestion, so add a general suggestion to relax `Sized`.
-        let (span, separator, open_paren_sp) =
-            if let Some((s, open_paren_sp)) = generics.bounds_span_for_suggestions(param.def_id) {
-                (s, " +", open_paren_sp)
-            } else {
-                (param.name.ident().span.shrink_to_hi(), ":", None)
-            };
-
-        let mut suggs = vec![];
-        let suggestion = format!("{separator} ?Sized");
-
-        if let Some(open_paren_sp) = open_paren_sp {
-            suggs.push((open_paren_sp, "(".to_string()));
-            suggs.push((span, format!("){suggestion}")));
-        } else {
-            suggs.push((span, suggestion));
-        }
-
-        err.multipart_suggestion_verbose(
-            "consider relaxing the implicit `Sized` restriction",
-            suggs,
-            Applicability::MachineApplicable,
-        );
-    }
-
-    fn maybe_indirection_for_unsized(
-        &self,
-        err: &mut Diag<'_>,
-        item: &Item<'tcx>,
-        param: &GenericParam<'tcx>,
-    ) -> bool {
-        // Suggesting `T: ?Sized` is only valid in an ADT if `T` is only used in a
-        // borrow. `struct S<'a, T: ?Sized>(&'a T);` is valid, `struct S<T: ?Sized>(T);`
-        // is not. Look for invalid "bare" parameter uses, and suggest using indirection.
-        let mut visitor =
-            FindTypeParam { param: param.name.ident().name, invalid_spans: vec![], nested: false };
-        visitor.visit_item(item);
-        if visitor.invalid_spans.is_empty() {
-            return false;
-        }
-        let mut multispan: MultiSpan = param.span.into();
-        multispan.push_span_label(
-            param.span,
-            format!("this could be changed to `{}: ?Sized`...", param.name.ident()),
-        );
-        for sp in visitor.invalid_spans {
-            multispan.push_span_label(
-                sp,
-                format!("...if indirection were used here: `Box<{}>`", param.name.ident()),
-            );
-        }
-        err.span_help(
-            multispan,
-            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(),
-            ),
-        );
-        true
-    }
-
     fn is_recursive_obligation(
         &self,
         obligated_types: &mut Vec<Ty<'tcx>>,