about summary refs log tree commit diff
path: root/compiler/rustc_trait_selection
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_trait_selection')
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml3
-rw-r--r--compiler/rustc_trait_selection/messages.ftl8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs96
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs9
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs8
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs204
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs7
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs6
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs11
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/region.rs16
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs30
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs2
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs151
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs10
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs23
-rw-r--r--compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs62
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs37
-rw-r--r--compiler/rustc_trait_selection/src/errors/note_and_explain.rs5
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs1
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs128
-rw-r--r--compiler/rustc_trait_selection/src/solve/inspect/analyse.rs5
-rw-r--r--compiler/rustc_trait_selection/src/solve/select.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs26
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs69
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs58
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs62
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs92
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs3
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs4
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs72
36 files changed, 746 insertions, 488 deletions
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index b13a753c4ed..1c61e23362a 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -1,14 +1,13 @@
 [package]
 name = "rustc_trait_selection"
 version = "0.0.0"
-edition = "2021"
+edition = "2024"
 
 [dependencies]
 # tidy-alphabetical-start
 itertools = "0.12"
 rustc_abi = { path = "../rustc_abi" }
 rustc_ast = { path = "../rustc_ast" }
-rustc_ast_ir = { path = "../rustc_ast_ir" }
 rustc_attr_parsing = { path = "../rustc_attr_parsing" }
 rustc_data_structures = { path = "../rustc_data_structures" }
 rustc_errors = { path = "../rustc_errors" }
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 055a3edcc32..4db9d9915b1 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -225,14 +225,6 @@ trait_selection_mismatched_static_lifetime = incompatible lifetime on type
 trait_selection_missing_options_for_on_unimplemented_attr = missing options for `on_unimplemented` attribute
     .help = at least one of the `message`, `note` and `label` options are expected
 
-trait_selection_more_targeted = {$has_param_name ->
-    [true] `{$param_name}`
-    *[false] `fn` parameter
-} has {$has_lifetime ->
-    [true] lifetime `{$lifetime}`
-    *[false] an anonymous lifetime `'_`
-} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
-
 trait_selection_msl_introduces_static = introduces a `'static` lifetime requirement
 trait_selection_msl_unmet_req = because this has an unmet lifetime requirement
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
index 091773009e9..a618bae269f 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/mod.rs
@@ -1989,7 +1989,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         trace: &TypeTrace<'tcx>,
         span: Span,
     ) -> Option<TypeErrorAdditionalDiags> {
-        let hir = self.tcx.hir();
         let TypeError::ArraySize(sz) = terr else {
             return None;
         };
@@ -1997,7 +1996,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Fn { body: body_id, .. }, ..
             }) => {
-                let body = hir.body(*body_id);
+                let body = self.tcx.hir_body(*body_id);
                 struct LetVisitor {
                     span: Span,
                 }
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
index 99b70c87ccd..bed9734f389 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/need_type_info.rs
@@ -18,6 +18,7 @@ use rustc_middle::ty::{
     TypeFoldable, TypeFolder, TypeSuperFoldable, TypeckResults,
 };
 use rustc_span::{BytePos, DUMMY_SP, FileName, Ident, Span, sym};
+use rustc_type_ir::visit::TypeVisitableExt;
 use tracing::{debug, instrument, warn};
 
 use super::nice_region_error::placeholder_error::Highlighted;
@@ -155,27 +156,92 @@ impl UnderspecifiedArgKind {
     }
 }
 
-struct ClosureEraser<'tcx> {
-    tcx: TyCtxt<'tcx>,
+struct ClosureEraser<'a, 'tcx> {
+    infcx: &'a InferCtxt<'tcx>,
 }
 
-impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'tcx> {
+impl<'a, 'tcx> ClosureEraser<'a, 'tcx> {
+    fn new_infer(&mut self) -> Ty<'tcx> {
+        self.infcx.next_ty_var(DUMMY_SP)
+    }
+}
+
+impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for ClosureEraser<'a, 'tcx> {
     fn cx(&self) -> TyCtxt<'tcx> {
-        self.tcx
+        self.infcx.tcx
     }
 
     fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
         match ty.kind() {
             ty::Closure(_, args) => {
+                // For a closure type, we turn it into a function pointer so that it gets rendered
+                // as `fn(args) -> Ret`.
                 let closure_sig = args.as_closure().sig();
                 Ty::new_fn_ptr(
-                    self.tcx,
-                    self.tcx.signature_unclosure(closure_sig, hir::Safety::Safe),
+                    self.cx(),
+                    self.cx().signature_unclosure(closure_sig, hir::Safety::Safe),
                 )
             }
-            _ => ty.super_fold_with(self),
+            ty::Adt(_, args) if !args.iter().any(|a| a.has_infer()) => {
+                // We have a type that doesn't have any inference variables, so we replace
+                // the whole thing with `_`. The type system already knows about this type in
+                // its entirety and it is redundant to specify it for the user. The user only
+                // needs to specify the type parameters that we *couldn't* figure out.
+                self.new_infer()
+            }
+            ty::Adt(def, args) => {
+                let generics = self.cx().generics_of(def.did());
+                let generics: Vec<bool> = generics
+                    .own_params
+                    .iter()
+                    .map(|param| param.default_value(self.cx()).is_some())
+                    .collect();
+                let ty = Ty::new_adt(
+                    self.cx(),
+                    *def,
+                    self.cx().mk_args_from_iter(generics.into_iter().zip(args.iter()).map(
+                        |(has_default, arg)| {
+                            if arg.has_infer() {
+                                // This param has an unsubstituted type variable, meaning that this
+                                // type has a (potentially deeply nested) type parameter from the
+                                // corresponding type's definition. We have explicitly asked this
+                                // type to not be hidden. In either case, we keep the type and don't
+                                // substitute with `_` just yet.
+                                arg.fold_with(self)
+                            } else if has_default {
+                                // We have a type param that has a default type, like the allocator
+                                // in Vec. We decided to show `Vec` itself, because it hasn't yet
+                                // been replaced by an `_` `Infer`, but we want to ensure that the
+                                // type parameter with default types does *not* get replaced with
+                                // `_` because then we'd end up with `Vec<_, _>`, instead of
+                                // `Vec<_>`.
+                                arg
+                            } else if let GenericArgKind::Type(_) = arg.unpack() {
+                                // We don't replace lifetime or const params, only type params.
+                                self.new_infer().into()
+                            } else {
+                                arg.fold_with(self)
+                            }
+                        },
+                    )),
+                );
+                ty
+            }
+            _ if ty.has_infer() => {
+                // This type has a (potentially nested) type parameter that we couldn't figure out.
+                // We will print this depth of type, so at least the type name and at least one of
+                // its type parameters.
+                ty.super_fold_with(self)
+            }
+            // We don't have an unknown type parameter anywhere, replace with `_`.
+            _ => self.new_infer(),
         }
     }
+
+    fn fold_const(&mut self, c: ty::Const<'tcx>) -> ty::Const<'tcx> {
+        // Avoid accidentally erasing the type of the const.
+        c
+    }
 }
 
 fn fmt_printer<'a, 'tcx>(infcx: &'a InferCtxt<'tcx>, ns: Namespace) -> FmtPrinter<'a, 'tcx> {
@@ -219,9 +285,9 @@ fn ty_to_string<'tcx>(
 ) -> String {
     let mut printer = fmt_printer(infcx, Namespace::TypeNS);
     let ty = infcx.resolve_vars_if_possible(ty);
-    // We use `fn` ptr syntax for closures, but this only works when the closure
-    // does not capture anything.
-    let ty = ty.fold_with(&mut ClosureEraser { tcx: infcx.tcx });
+    // We use `fn` ptr syntax for closures, but this only works when the closure does not capture
+    // anything. We also remove all type parameters that are fully known to the type system.
+    let ty = ty.fold_with(&mut ClosureEraser { infcx });
 
     match (ty.kind(), called_method_def_id) {
         // We don't want the regular output for `fn`s because it includes its path in
@@ -422,7 +488,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         };
 
         let mut local_visitor = FindInferSourceVisitor::new(self, typeck_results, arg);
-        if let Some(body) = self.tcx.hir().maybe_body_owned_by(
+        if let Some(body) = self.tcx.hir_maybe_body_owned_by(
             self.tcx.typeck_root_def_id(body_def_id.to_def_id()).expect_local(),
         ) {
             let expr = body.value;
@@ -1008,7 +1074,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
         &self,
         path: &'tcx hir::Path<'tcx>,
         args: GenericArgsRef<'tcx>,
-    ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
+    ) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'tcx {
         let tcx = self.tecx.tcx;
         let have_turbofish = path.segments.iter().any(|segment| {
             segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const()))
@@ -1135,8 +1201,8 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
 impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tecx.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tecx.tcx
     }
 
     fn visit_local(&mut self, local: &'tcx LetStmt<'tcx>) {
@@ -1253,7 +1319,7 @@ impl<'a, 'tcx> Visitor<'tcx> for FindInferSourceVisitor<'a, 'tcx> {
             {
                 let output = args.as_closure().sig().output().skip_binder();
                 if self.generic_arg_contains_target(output.into()) {
-                    let body = self.tecx.tcx.hir().body(body);
+                    let body = self.tecx.tcx.hir_body(body);
                     let should_wrap_expr = if matches!(body.value.kind, ExprKind::Block(..)) {
                         None
                     } else {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
index b9f3abc2534..5a303c3cd03 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/find_anon_type.rs
@@ -3,7 +3,6 @@ use core::ops::ControlFlow;
 use rustc_hir::def_id::{DefId, LocalDefId};
 use rustc_hir::intravisit::{self, Visitor, VisitorExt};
 use rustc_hir::{self as hir, AmbigArg};
-use rustc_middle::hir::map::Map;
 use rustc_middle::hir::nested_filter;
 use rustc_middle::middle::resolve_bound_vars as rbv;
 use rustc_middle::ty::{self, Region, TyCtxt};
@@ -70,8 +69,8 @@ impl<'tcx> Visitor<'tcx> for FindNestedTypeVisitor<'tcx> {
     type Result = ControlFlow<&'tcx hir::Ty<'tcx>>;
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) -> Self::Result {
@@ -176,8 +175,8 @@ impl<'tcx> Visitor<'tcx> for TyPathVisitor<'tcx> {
     type Result = ControlFlow<()>;
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Map<'tcx> {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_lifetime(&mut self, lifetime: &hir::Lifetime) -> Self::Result {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
index 886581bc35f..0904177ea8b 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/mismatched_static_lifetime.rs
@@ -33,11 +33,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         };
         // If we added a "points at argument expression" obligation, we remove it here, we care
         // about the original obligation only.
-        let code = match cause.code() {
-            ObligationCauseCode::FunctionArg { parent_code, .. } => &*parent_code,
-            code => code,
-        };
-        let ObligationCauseCode::MatchImpl(parent, impl_def_id) = code else {
+        let ObligationCauseCode::MatchImpl(parent, impl_def_id) = cause.code() else {
             return None;
         };
         let (ObligationCauseCode::WhereClause(_, binding_span)
@@ -66,7 +62,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         );
         let mut impl_span = None;
         let mut implicit_static_lifetimes = Vec::new();
-        if let Some(impl_node) = self.tcx().hir().get_if_local(*impl_def_id) {
+        if let Some(impl_node) = self.tcx().hir_get_if_local(*impl_def_id) {
             // If an impl is local, then maybe this isn't what they want. Try to
             // be as helpful as possible with implicit lifetimes.
 
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
index 039e21cb556..083ce022238 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/static_impl_trait.rs
@@ -1,27 +1,21 @@
 //! Error Reporting for static impl Traits.
 
 use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::{Applicability, Diag, ErrorGuaranteed, MultiSpan, Subdiagnostic};
+use rustc_errors::{Applicability, Diag, ErrorGuaranteed};
 use rustc_hir::def_id::DefId;
 use rustc_hir::intravisit::{Visitor, VisitorExt, walk_ty};
 use rustc_hir::{
     self as hir, AmbigArg, GenericBound, GenericParam, GenericParamKind, Item, ItemKind, Lifetime,
     LifetimeName, LifetimeParamKind, MissingLifetimeKind, Node, TyKind,
 };
-use rustc_middle::ty::{
-    self, AssocItemContainer, StaticLifetimeVisitor, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor,
-};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
 use rustc_span::def_id::LocalDefId;
 use rustc_span::{Ident, Span};
 use tracing::debug;
 
 use crate::error_reporting::infer::nice_region_error::NiceRegionError;
-use crate::errors::{
-    ButCallingIntroduces, ButNeedsToSatisfy, DynTraitConstraintSuggestion, MoreTargeted,
-    ReqIntroducedLocations,
-};
-use crate::infer::{RegionResolutionError, SubregionOrigin, TypeTrace};
-use crate::traits::{ObligationCauseCode, UnifyReceiverContext};
+use crate::errors::ButNeedsToSatisfy;
+use crate::infer::{RegionResolutionError, SubregionOrigin};
 
 impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
     /// Print the error message for lifetime errors when the return type is a static `impl Trait`,
@@ -39,52 +33,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 sup_r,
                 spans,
             ) if sub_r.is_static() => (var_origin, sub_origin, sub_r, sup_origin, sup_r, spans),
-            RegionResolutionError::ConcreteFailure(
-                SubregionOrigin::Subtype(box TypeTrace { cause, .. }),
-                sub_r,
-                sup_r,
-            ) if sub_r.is_static() => {
-                // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`.
-                if let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code() {
-                    // This may have a closure and it would cause ICE
-                    // through `find_param_with_region` (#78262).
-                    let anon_reg_sup = tcx.is_suitable_region(self.generic_param_scope, *sup_r)?;
-                    let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope);
-                    if fn_returns.is_empty() {
-                        return None;
-                    }
-
-                    let param = self.find_param_with_region(*sup_r, *sub_r)?;
-                    let simple_ident = param.param.pat.simple_ident();
-
-                    let (has_impl_path, impl_path) = match ctxt.assoc_item.container {
-                        AssocItemContainer::Trait => {
-                            let id = ctxt.assoc_item.container_id(tcx);
-                            (true, tcx.def_path_str(id))
-                        }
-                        AssocItemContainer::Impl => (false, String::new()),
-                    };
-
-                    let mut err = self.tcx().dcx().create_err(ButCallingIntroduces {
-                        param_ty_span: param.param_ty_span,
-                        cause_span: cause.span,
-                        has_param_name: simple_ident.is_some(),
-                        param_name: simple_ident.map(|x| x.to_string()).unwrap_or_default(),
-                        has_lifetime: sup_r.has_name(),
-                        lifetime: sup_r.to_string(),
-                        assoc_item: ctxt.assoc_item.name,
-                        has_impl_path,
-                        impl_path,
-                    });
-                    if self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt) {
-                        let reported = err.emit();
-                        return Some(reported);
-                    } else {
-                        err.cancel()
-                    }
-                }
-                return None;
-            }
             _ => return None,
         };
         debug!(
@@ -140,39 +88,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             None
         };
 
-        let mut subdiag = None;
-
-        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = sub_origin {
-            if let ObligationCauseCode::ReturnValue(hir_id)
-            | ObligationCauseCode::BlockTailExpression(hir_id, ..) = cause.code()
-            {
-                let parent_id = tcx.hir().get_parent_item(*hir_id);
-                if let Some(fn_decl) = tcx.hir().fn_decl_by_hir_id(parent_id.into()) {
-                    let mut span: MultiSpan = fn_decl.output.span().into();
-                    let mut spans = Vec::new();
-                    let mut add_label = true;
-                    if let hir::FnRetTy::Return(ty) = fn_decl.output {
-                        let mut v = StaticLifetimeVisitor(vec![], tcx.hir());
-                        v.visit_ty_unambig(ty);
-                        if !v.0.is_empty() {
-                            span = v.0.clone().into();
-                            spans = v.0;
-                            add_label = false;
-                        }
-                    }
-                    let fn_decl_span = fn_decl.output.span();
-
-                    subdiag = Some(ReqIntroducedLocations {
-                        span,
-                        spans,
-                        fn_decl_span,
-                        cause_span: cause.span,
-                        add_label,
-                    });
-                }
-            }
-        }
-
         let diag = ButNeedsToSatisfy {
             sp,
             influencer_point,
@@ -183,7 +98,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             require_span_as_note: require_as_note.then_some(require_span),
             // We don't need a note, it's already at the end, it can be shown as a `span_label`.
             require_span_as_label: (!require_as_note).then_some(require_span),
-            req_introduces_loc: subdiag,
 
             has_lifetime: sup_r.has_name(),
             lifetime: lifetime_name.clone(),
@@ -197,45 +111,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
 
         let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.scope);
 
-        let mut override_error_code = None;
-        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sup_origin
-            && let ObligationCauseCode::UnifyReceiver(ctxt) = cause.code()
-            // Handle case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a
-            // `'static` lifetime when called as a method on a binding: `bar.qux()`.
-            && self.find_impl_on_dyn_trait(&mut err, param.param_ty, ctxt)
-        {
-            override_error_code = Some(ctxt.assoc_item.name);
-        }
-
-        if let SubregionOrigin::Subtype(box TypeTrace { cause, .. }) = &sub_origin
-            && let code = match cause.code() {
-                ObligationCauseCode::MatchImpl(parent, ..) => parent.code(),
-                _ => cause.code(),
-            }
-            && let (
-                &ObligationCauseCode::WhereClause(item_def_id, _)
-                | &ObligationCauseCode::WhereClauseInExpr(item_def_id, ..),
-                None,
-            ) = (code, override_error_code)
-        {
-            // Same case of `impl Foo for dyn Bar { fn qux(&self) {} }` introducing a `'static`
-            // lifetime as above, but called using a fully-qualified path to the method:
-            // `Foo::qux(bar)`.
-            let mut v = TraitObjectVisitor(FxIndexSet::default());
-            v.visit_ty(param.param_ty);
-            if let Some((ident, self_ty)) =
-                NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, item_def_id, &v.0)
-                && self.suggest_constrain_dyn_trait_in_impl(&mut err, &v.0, ident, self_ty)
-            {
-                override_error_code = Some(ident.name);
-            }
-        }
-        if let (Some(ident), true) = (override_error_code, fn_returns.is_empty()) {
-            // Provide a more targeted error code and description.
-            let retarget_subdiag = MoreTargeted { ident };
-            retarget_subdiag.add_to_diag(&mut err);
-        }
-
         let arg = match param.param.pat.simple_ident() {
             Some(simple_ident) => format!("argument `{simple_ident}`"),
             None => "the argument".to_string(),
@@ -318,7 +193,7 @@ pub fn suggest_new_region_bound(
                 } else {
                     // get a lifetime name of existing named lifetimes if any
                     let existing_lt_name = if let Some(id) = scope_def_id
-                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let Some(generics) = tcx.hir_get_generics(id)
                         && let named_lifetimes = generics
                             .params
                             .iter()
@@ -349,7 +224,7 @@ pub fn suggest_new_region_bound(
                     // if there are more than one elided lifetimes in inputs, the explicit `'_` lifetime cannot be used.
                     // introducing a new lifetime `'a` or making use of one from existing named lifetimes if any
                     if let Some(id) = scope_def_id
-                        && let Some(generics) = tcx.hir().get_generics(id)
+                        && let Some(generics) = tcx.hir_get_generics(id)
                         && let mut spans_suggs =
                             make_elided_region_spans_suggs(name, generics.params.iter())
                         && spans_suggs.len() > 1
@@ -470,9 +345,9 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         def_id: DefId,
         trait_objects: &FxIndexSet<DefId>,
     ) -> Option<(Ident, &'tcx hir::Ty<'tcx>)> {
-        match tcx.hir().get_if_local(def_id)? {
+        match tcx.hir_get_if_local(def_id)? {
             Node::ImplItem(impl_item) => {
-                let impl_did = tcx.hir().get_parent_item(impl_item.hir_id());
+                let impl_did = tcx.hir_get_parent_item(impl_item.hir_id());
                 if let hir::OwnerNode::Item(Item {
                     kind: ItemKind::Impl(hir::Impl { self_ty, .. }),
                     ..
@@ -484,19 +359,18 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
                 }
             }
             Node::TraitItem(trait_item) => {
-                let trait_id = tcx.hir().get_parent_item(trait_item.hir_id());
+                let trait_id = tcx.hir_get_parent_item(trait_item.hir_id());
                 debug_assert_eq!(tcx.def_kind(trait_id.def_id), hir::def::DefKind::Trait);
                 // The method being called is defined in the `trait`, but the `'static`
                 // obligation comes from the `impl`. Find that `impl` so that we can point
                 // at it in the suggestion.
                 let trait_did = trait_id.to_def_id();
-                tcx.hir().trait_impls(trait_did).iter().find_map(|&impl_did| {
+                tcx.hir_trait_impls(trait_did).iter().find_map(|&impl_did| {
                     if let Node::Item(Item {
                         kind: ItemKind::Impl(hir::Impl { self_ty, .. }), ..
                     }) = tcx.hir_node_by_def_id(impl_did)
                         && trait_objects.iter().all(|did| {
-                            // FIXME: we should check `self_ty` against the receiver
-                            // type in the `UnifyReceiver` context, but for now, use
+                            // FIXME: we should check `self_ty`, but for now, use
                             // this imperfect proxy. This will fail if there are
                             // multiple `impl`s for the same trait like
                             // `impl Foo for Box<dyn Bar>` and `impl Foo for dyn Bar`.
@@ -516,62 +390,6 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
             _ => None,
         }
     }
-
-    /// When we call a method coming from an `impl Foo for dyn Bar`, `dyn Bar` introduces a default
-    /// `'static` obligation. Suggest relaxing that implicit bound.
-    fn find_impl_on_dyn_trait(
-        &self,
-        err: &mut Diag<'_>,
-        ty: Ty<'_>,
-        ctxt: &UnifyReceiverContext<'tcx>,
-    ) -> bool {
-        let tcx = self.tcx();
-
-        // Find the method being called.
-        let Ok(Some(instance)) = ty::Instance::try_resolve(
-            tcx,
-            self.cx.typing_env(ctxt.param_env),
-            ctxt.assoc_item.def_id,
-            self.cx.resolve_vars_if_possible(ctxt.args),
-        ) else {
-            return false;
-        };
-
-        let mut v = TraitObjectVisitor(FxIndexSet::default());
-        v.visit_ty(ty);
-
-        // Get the `Ident` of the method being called and the corresponding `impl` (to point at
-        // `Bar` in `impl Foo for dyn Bar {}` and the definition of the method being called).
-        let Some((ident, self_ty)) =
-            NiceRegionError::get_impl_ident_and_self_ty_from_trait(tcx, instance.def_id(), &v.0)
-        else {
-            return false;
-        };
-
-        // Find the trait object types in the argument, so we point at *only* the trait object.
-        self.suggest_constrain_dyn_trait_in_impl(err, &v.0, ident, self_ty)
-    }
-
-    fn suggest_constrain_dyn_trait_in_impl(
-        &self,
-        err: &mut Diag<'_>,
-        found_dids: &FxIndexSet<DefId>,
-        ident: Ident,
-        self_ty: &hir::Ty<'_>,
-    ) -> bool {
-        let mut suggested = false;
-        for found_did in found_dids {
-            let mut traits = vec![];
-            let mut hir_v = HirTraitObjectVisitor(&mut traits, *found_did);
-            hir_v.visit_ty_unambig(self_ty);
-            for &span in &traits {
-                let subdiag = DynTraitConstraintSuggestion { span, ident };
-                subdiag.add_to_diag(err);
-                suggested = true;
-            }
-        }
-        suggested
-    }
 }
 
 /// Collect all the trait objects in a type that could have received an implicit `'static` lifetime.
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
index bbcd28c0835..cc2ab1c3432 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/trait_impl_difference.rs
@@ -99,11 +99,10 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
         let mut visitor = TypeParamSpanVisitor { tcx: self.tcx(), types: vec![] };
         match assoc_item.kind {
             ty::AssocKind::Fn => {
-                let hir = self.tcx().hir();
                 if let Some(hir_id) =
                     assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id))
                 {
-                    if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) {
+                    if let Some(decl) = self.tcx().hir_fn_decl_by_hir_id(hir_id) {
                         visitor.visit_fn_decl(decl);
                     }
                 }
@@ -133,8 +132,8 @@ struct TypeParamSpanVisitor<'tcx> {
 impl<'tcx> Visitor<'tcx> for TypeParamSpanVisitor<'tcx> {
     type NestedFilter = nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_ty(&mut self, arg: &'tcx hir::Ty<'tcx, AmbigArg>) {
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
index 445937ad169..245764c94ab 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/nice_region_error/util.rs
@@ -64,10 +64,10 @@ pub fn find_param_with_region<'tcx>(
         _ => {}
     }
 
-    let body = hir.maybe_body_owned_by(def_id)?;
+    let body = tcx.hir_maybe_body_owned_by(def_id)?;
 
-    let owner_id = hir.body_owner(body.id());
-    let fn_decl = hir.fn_decl_by_hir_id(owner_id)?;
+    let owner_id = tcx.hir_body_owner(body.id());
+    let fn_decl = tcx.hir_fn_decl_by_hir_id(owner_id)?;
     let poly_fn_sig = tcx.fn_sig(id).instantiate_identity();
 
     let fn_sig = tcx.liberate_late_bound_regions(id, poly_fn_sig);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
index e8d14b89d69..514615735a5 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/note_and_explain.rs
@@ -522,7 +522,8 @@ impl<T> Trait<T> for X {
                 }
             }
             TypeError::TargetFeatureCast(def_id) => {
-                let target_spans = tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span);
+                let target_spans =
+                    tcx.get_attrs(def_id, sym::target_feature).map(|attr| attr.span());
                 diag.note(
                     "functions with `#[target_feature]` can only be coerced to `unsafe` function pointers"
                 );
@@ -543,7 +544,7 @@ impl<T> Trait<T> for X {
         let tcx = self.tcx;
         let assoc = tcx.associated_item(proj_ty.def_id);
         let (trait_ref, assoc_args) = proj_ty.trait_ref_and_own_args(tcx);
-        let Some(item) = tcx.hir().get_if_local(body_owner_def_id) else {
+        let Some(item) = tcx.hir_get_if_local(body_owner_def_id) else {
             return false;
         };
         let Some(hir_generics) = item.generics() else {
@@ -586,7 +587,7 @@ impl<T> Trait<T> for X {
             hir::Node::TraitItem(item) => item.hir_id(),
             _ => return false,
         };
-        let parent = tcx.hir().get_parent_item(hir_id).def_id;
+        let parent = tcx.hir_get_parent_item(hir_id).def_id;
         self.suggest_constraint(diag, msg, parent.into(), proj_ty, ty)
     }
 
@@ -625,7 +626,7 @@ impl<T> Trait<T> for X {
             )
         };
 
-        let body_owner = tcx.hir().get_if_local(body_owner_def_id);
+        let body_owner = tcx.hir_get_if_local(body_owner_def_id);
         let current_method_ident = body_owner.and_then(|n| n.ident()).map(|i| i.name);
 
         // We don't want to suggest calling an assoc fn in a scope where that isn't feasible.
@@ -820,7 +821,7 @@ fn foo(&self) -> Self::T { String::new() }
         // When `body_owner` is an `impl` or `trait` item, look in its associated types for
         // `expected` and point at it.
         let hir_id = tcx.local_def_id_to_hir_id(def_id);
-        let parent_id = tcx.hir().get_parent_item(hir_id);
+        let parent_id = tcx.hir_get_parent_item(hir_id);
         let item = tcx.hir_node_by_def_id(parent_id.def_id);
 
         debug!("expected_projection parent item {:?}", item);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
index f35a5349ecb..fecb38ab597 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/region.rs
@@ -2,7 +2,7 @@ use std::iter;
 
 use rustc_data_structures::fx::FxIndexSet;
 use rustc_errors::{
-    Applicability, Diag, E0309, E0310, E0311, E0495, Subdiagnostic, struct_span_code_err,
+    Applicability, Diag, E0309, E0310, E0311, E0803, Subdiagnostic, struct_span_code_err,
 };
 use rustc_hir::def::DefKind;
 use rustc_hir::def_id::{DefId, LocalDefId};
@@ -487,7 +487,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     &format!("`{sup}: {sub}`"),
                 );
                 // We should only suggest rewriting the `where` clause if the predicate is within that `where` clause
-                if let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id)
+                if let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id)
                     && generics.where_clause_span.contains(span)
                 {
                     self.suggest_copy_trait_method_bounds(
@@ -590,7 +590,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             return;
         };
 
-        let Some(generics) = self.tcx.hir().get_generics(impl_item_def_id) else {
+        let Some(generics) = self.tcx.hir_get_generics(impl_item_def_id) else {
             return;
         };
 
@@ -763,7 +763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     // Get the `hir::Param` to verify whether it already has any bounds.
                     // We do this to avoid suggesting code that ends up as `T: 'a'b`,
                     // instead we suggest `T: 'a + 'b` in that case.
-                    let hir_generics = self.tcx.hir().get_generics(scope).unwrap();
+                    let hir_generics = self.tcx.hir_get_generics(scope).unwrap();
                     let sugg_span = match hir_generics.bounds_span_for_suggestions(def_id) {
                         Some((span, open_paren_sp)) => Some((span, true, open_paren_sp)),
                         // If `param` corresponds to `Self`, no usable suggestion span.
@@ -822,7 +822,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             {
                 // The lifetime found in the `impl` is longer than the one on the RPITIT.
                 // Do not suggest `<Type as Trait>::{opaque}: 'static`.
-            } else if let Some(generics) = self.tcx.hir().get_generics(suggestion_scope) {
+            } else if let Some(generics) = self.tcx.hir_get_generics(suggestion_scope) {
                 let pred = format!("{bound_kind}: {lt_name}");
                 let suggestion = format!("{} {}", generics.add_where_or_trailing_comma(), pred);
                 suggs.push((generics.tail_span_for_predicate_suggestion(), suggestion))
@@ -907,7 +907,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             hir::OwnerNode::Synthetic => unreachable!(),
         }
 
-        let ast_generics = self.tcx.hir().get_generics(lifetime_scope).unwrap();
+        let ast_generics = self.tcx.hir_get_generics(lifetime_scope).unwrap();
         let sugg = ast_generics
             .span_for_lifetime_suggestion()
             .map(|span| (span, format!("{new_lt}, ")))
@@ -1032,7 +1032,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         struct_span_code_err!(
             self.dcx(),
             var_origin.span(),
-            E0495,
+            E0803,
             "cannot infer an appropriate lifetime{} due to conflicting requirements",
             var_description
         )
@@ -1382,7 +1382,7 @@ fn suggest_precise_capturing<'tcx>(
                 new_params += name_as_bounds;
             }
 
-            let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
+            let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
                 // This shouldn't happen, but don't ICE.
                 return;
             };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
index 562000e28ac..a7e68e6419d 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/infer/suggest.rs
@@ -10,7 +10,6 @@ use rustc_hir::def::Res;
 use rustc_hir::{MatchSource, Node};
 use rustc_middle::traits::{
     IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
-    StatementAsExpression,
 };
 use rustc_middle::ty::error::TypeError;
 use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -26,8 +25,14 @@ use crate::errors::{
     SuggestTuplePatternMany, SuggestTuplePatternOne, TypeErrorAdditionalDiags,
 };
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+enum StatementAsExpression {
+    CorrectType,
+    NeedsBoxing,
+}
+
 #[derive(Clone, Copy)]
-pub enum SuggestAsRefKind {
+enum SuggestAsRefKind {
     Option,
     Result,
 }
@@ -232,7 +237,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     Some(ConsiderAddingAwait::FutureSugg { span: then_span.shrink_to_hi() })
                 }
                 ObligationCauseCode::MatchExpressionArm(box MatchExpressionArmCause {
-                    ref prior_non_diverging_arms,
+                    prior_non_diverging_arms,
                     ..
                 }) => Some({
                     ConsiderAddingAwait::FutureSuggMultiple {
@@ -382,7 +387,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    pub fn suggest_function_pointers_impl(
+    pub(crate) fn suggest_function_pointers_impl(
         &self,
         span: Option<Span>,
         exp_found: &ty::error::ExpectedFound<Ty<'tcx>>,
@@ -518,7 +523,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         }
     }
 
-    pub fn should_suggest_as_ref_kind(
+    fn should_suggest_as_ref_kind(
         &self,
         expected: Ty<'tcx>,
         found: Ty<'tcx>,
@@ -588,8 +593,8 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     ) -> Option<TypeErrorAdditionalDiags> {
         /// Find the if expression with given span
         struct IfVisitor {
-            pub found_if: bool,
-            pub err_span: Span,
+            found_if: bool,
+            err_span: Span,
         }
 
         impl<'v> Visitor<'v> for IfVisitor {
@@ -624,7 +629,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             }
         }
 
-        self.tcx.hir().maybe_body_owned_by(cause.body_id).and_then(|body| {
+        self.tcx.hir_maybe_body_owned_by(cause.body_id).and_then(|body| {
             IfVisitor { err_span: span, found_if: false }
                 .visit_body(&body)
                 .is_break()
@@ -649,7 +654,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
         else {
             return;
         };
-        let hir::Body { params, .. } = self.tcx.hir().body(*body);
+        let hir::Body { params, .. } = self.tcx.hir_body(*body);
 
         // 1. Get the args of the closure.
         // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
@@ -736,7 +741,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 impl<'tcx> TypeErrCtxt<'_, 'tcx> {
     /// Be helpful when the user wrote `{... expr; }` and taking the `;` off
     /// is enough to fix the error.
-    pub fn could_remove_semicolon(
+    fn could_remove_semicolon(
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected_ty: Ty<'tcx>,
@@ -816,7 +821,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
 
     /// Suggest returning a local binding with a compatible type if the block
     /// has no return expression.
-    pub fn consider_returning_binding_diag(
+    fn consider_returning_binding_diag(
         &self,
         blk: &'tcx hir::Block<'tcx>,
         expected_ty: Ty<'tcx>,
@@ -846,7 +851,6 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
             true
         };
 
-        let hir = self.tcx.hir();
         for stmt in blk.stmts.iter().rev() {
             let hir::StmtKind::Let(local) = &stmt.kind else {
                 continue;
@@ -871,7 +875,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
                     kind: hir::ExprKind::Closure(hir::Closure { body, .. }),
                     ..
                 }) => {
-                    for param in hir.body(*body).params {
+                    for param in self.tcx.hir_body(*body).params {
                         param.pat.walk(&mut find_compatible_candidates);
                     }
                 }
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 6beb108bc3a..f15f1b78b52 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/ambiguity.rs
@@ -316,7 +316,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 }
 
                 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 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);
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
index 1b43820bac0..596f794568c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/fulfillment_errors.rs
@@ -192,19 +192,38 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
 
                         let have_alt_message = message.is_some() || label.is_some();
                         let is_try_conversion = self.is_try_conversion(span, main_trait_predicate.def_id());
+                        let is_question_mark = matches!(
+                            root_obligation.cause.code().peel_derives(),
+                            ObligationCauseCode::QuestionMark,
+                        ) && !(
+                            self.tcx.is_diagnostic_item(sym::FromResidual, main_trait_predicate.def_id())
+                                || self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::Try)
+                        );
                         let is_unsize =
                             self.tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Unsize);
+                        let question_mark_message = "the question mark operation (`?`) implicitly \
+                                                     performs a conversion on the error value \
+                                                     using the `From` trait";
                         let (message, notes, append_const_msg) = if is_try_conversion {
+                            // We have a `-> Result<_, E1>` and `gives_E2()?`.
                             (
                                 Some(format!(
                                     "`?` couldn't convert the error to `{}`",
                                     main_trait_predicate.skip_binder().self_ty(),
                                 )),
-                                vec![
-                                    "the question mark operation (`?`) implicitly performs a \
-                                     conversion on the error value using the `From` trait"
-                                        .to_owned(),
-                                ],
+                                vec![question_mark_message.to_owned()],
+                                Some(AppendConstMessage::Default),
+                            )
+                        } else if is_question_mark {
+                            // Similar to the case above, but in this case the conversion is for a
+                            // trait object: `-> Result<_, Box<dyn Error>` and `gives_E()?` when
+                            // `E: Error` isn't met.
+                            (
+                                Some(format!(
+                                    "`?` couldn't convert the error: `{main_trait_predicate}` is \
+                                     not satisfied",
+                                )),
+                                vec![question_mark_message.to_owned()],
                                 Some(AppendConstMessage::Default),
                             )
                         } else {
@@ -220,8 +239,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             &mut long_ty_file,
                         );
 
-                        let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(main_trait_predicate.def_id(), LangItem::TransmuteTrait)
-                        {
+                        let (err_msg, safe_transmute_explanation) = if self.tcx.is_lang_item(
+                            main_trait_predicate.def_id(),
+                            LangItem::TransmuteTrait,
+                        ) {
                             // Recompute the safe transmute reason and use that for the error reporting
                             match self.get_safe_transmute_error_and_reason(
                                 obligation.clone(),
@@ -249,18 +270,22 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         *err.long_ty_path() = long_ty_file;
 
                         let mut suggested = false;
-                        if is_try_conversion {
+                        if is_try_conversion || is_question_mark {
                             suggested = self.try_conversion_context(&obligation, main_trait_predicate, &mut err);
                         }
 
-                        if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
-                            err.span_label(
-                                ret_span,
-                                format!(
-                                    "expected `{}` because of this",
-                                    main_trait_predicate.skip_binder().self_ty()
-                                ),
-                            );
+                        if let Some(ret_span) = self.return_type_span(&obligation) {
+                            if is_try_conversion {
+                                err.span_label(
+                                    ret_span,
+                                    format!(
+                                        "expected `{}` because of this",
+                                        main_trait_predicate.skip_binder().self_ty()
+                                    ),
+                                );
+                            } else if is_question_mark {
+                                err.span_label(ret_span, format!("required `{main_trait_predicate}` because of this"));
+                            }
                         }
 
                         if tcx.is_lang_item(leaf_trait_predicate.def_id(), LangItem::Tuple) {
@@ -302,10 +327,14 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             // If it has a custom `#[rustc_on_unimplemented]`
                             // error message, let's display it as the label!
                             err.span_label(span, s);
-                            if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_)) {
+                            if !matches!(leaf_trait_predicate.skip_binder().self_ty().kind(), ty::Param(_))
                                 // 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.
+                                && !self.tcx.is_diagnostic_item(sym::FromResidual, leaf_trait_predicate.def_id())
+                                    // Don't say "the trait `FromResidual<Option<Infallible>>` is
+                                    // not implemented for `Result<T, E>`".
+                            {
                                 err.help(explanation);
                             }
                         } else if let Some(custom_explanation) = safe_transmute_explanation {
@@ -367,7 +396,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                         (span.shrink_to_lo(), format!("(")),
                                         (span.shrink_to_hi(), format!(" as {})", cand.self_ty())),
                                     ]
-                                } else if let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) {
+                                } else if 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(expr) = expr_finder.result &&
@@ -585,6 +614,10 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(ty)) => {
                         let ty = self.resolve_vars_if_possible(ty);
                         if self.next_trait_solver() {
+                            if let Err(guar) = ty.error_reported() {
+                                return guar;
+                            }
+
                             // FIXME: we'll need a better message which takes into account
                             // which bounds actually failed to hold.
                             self.dcx().struct_span_err(
@@ -921,23 +954,19 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         let hir_id = self.tcx.local_def_id_to_hir_id(obligation.cause.body_id);
         let Some(body_id) = self.tcx.hir_node(hir_id).body_id() else { return false };
         let ControlFlow::Break(expr) =
-            (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir().body(body_id))
+            (FindMethodSubexprOfTry { search_span: span }).visit_body(self.tcx.hir_body(body_id))
         else {
             return false;
         };
         let Some(typeck) = &self.typeck_results else {
             return false;
         };
-        let Some((ObligationCauseCode::QuestionMark, Some(y))) =
-            obligation.cause.code().parent_with_predicate()
-        else {
+        let ObligationCauseCode::QuestionMark = obligation.cause.code().peel_derives() else {
             return false;
         };
-        if !self.tcx.is_diagnostic_item(sym::FromResidual, y.def_id()) {
-            return false;
-        }
         let self_ty = trait_pred.skip_binder().self_ty();
         let found_ty = trait_pred.skip_binder().trait_ref.args.get(1).and_then(|a| a.as_type());
+        self.note_missing_impl_for_question_mark(err, self_ty, found_ty, trait_pred);
 
         let mut prev_ty = self.resolve_vars_if_possible(
             typeck.expr_ty_adjusted_opt(expr).unwrap_or(Ty::new_misc_error(self.tcx)),
@@ -1008,7 +1037,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 && let [arg] = args
                 && let hir::ExprKind::Closure(closure) = arg.kind
                 // The closure has a block for its body with no tail expression
-                && let body = self.tcx.hir().body(closure.body)
+                && let body = self.tcx.hir_body(closure.body)
                 && let hir::ExprKind::Block(block, _) = body.value.kind
                 && let None = block.expr
                 // The last statement is of a type that can be converted to the return error type
@@ -1102,6 +1131,56 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         suggested
     }
 
+    fn note_missing_impl_for_question_mark(
+        &self,
+        err: &mut Diag<'_>,
+        self_ty: Ty<'_>,
+        found_ty: Option<Ty<'_>>,
+        trait_pred: ty::PolyTraitPredicate<'tcx>,
+    ) {
+        match (self_ty.kind(), found_ty) {
+            (ty::Adt(def, _), Some(ty))
+                if let ty::Adt(found, _) = ty.kind()
+                    && def.did().is_local()
+                    && found.did().is_local() =>
+            {
+                err.span_note(
+                    self.tcx.def_span(def.did()),
+                    format!("`{self_ty}` needs to implement `From<{ty}>`"),
+                );
+                err.span_note(
+                    self.tcx.def_span(found.did()),
+                    format!("alternatively, `{ty}` needs to implement `Into<{self_ty}>`"),
+                );
+            }
+            (ty::Adt(def, _), None) if def.did().is_local() => {
+                err.span_note(
+                    self.tcx.def_span(def.did()),
+                    format!(
+                        "`{self_ty}` needs to implement `{}`",
+                        trait_pred.skip_binder().trait_ref.print_only_trait_path(),
+                    ),
+                );
+            }
+            (ty::Adt(def, _), Some(ty)) if def.did().is_local() => {
+                err.span_note(
+                    self.tcx.def_span(def.did()),
+                    format!("`{self_ty}` needs to implement `From<{ty}>`"),
+                );
+            }
+            (_, Some(ty))
+                if let ty::Adt(def, _) = ty.kind()
+                    && def.did().is_local() =>
+            {
+                err.span_note(
+                    self.tcx.def_span(def.did()),
+                    format!("`{ty}` needs to implement `Into<{self_ty}>`"),
+                );
+            }
+            _ => {}
+        }
+    }
+
     fn report_const_param_not_wf(
         &self,
         ty: Ty<'tcx>,
@@ -1443,7 +1522,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
                     return None;
                 };
-                match self.tcx.hir().get_if_local(associated_item.def_id) {
+                match self.tcx.hir_get_if_local(associated_item.def_id) {
                     Some(
                         hir::Node::TraitItem(hir::TraitItem {
                             kind: hir::TraitItemKind::Type(_, Some(ty)),
@@ -1510,7 +1589,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         span = match fn_decl.output {
                             hir::FnRetTy::Return(ty) => ty.span,
                             hir::FnRetTy::DefaultReturn(_) => {
-                                let body = self.tcx.hir().body(id);
+                                let body = self.tcx.hir_body(id);
                                 match body.value.kind {
                                     hir::ExprKind::Block(
                                         hir::Block { expr: Some(expr), .. },
@@ -2031,6 +2110,11 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 return false;
             }
             if let &[cand] = &candidates[..] {
+                if self.tcx.is_diagnostic_item(sym::FromResidual, cand.def_id)
+                    && !self.tcx.features().enabled(sym::try_trait_v2)
+                {
+                    return false;
+                }
                 let (desc, mention_castable) =
                     match (cand.self_ty().kind(), trait_pred.self_ty().skip_binder().kind()) {
                         (ty::FnPtr(..), ty::FnDef(..)) => {
@@ -2353,7 +2437,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         obligated_types: &mut Vec<Ty<'tcx>>,
         cause_code: &ObligationCauseCode<'tcx>,
     ) -> bool {
-        if let ObligationCauseCode::BuiltinDerived(ref data) = cause_code {
+        if let ObligationCauseCode::BuiltinDerived(data) = cause_code {
             let parent_trait_ref = self.resolve_vars_if_possible(data.parent_trait_pred);
             let self_ty = parent_trait_ref.skip_binder().self_ty();
             if obligated_types.iter().any(|ot| ot == &self_ty) {
@@ -2846,7 +2930,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             _ => None,
         };
 
-        let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
+        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_signature_mismatch.borrow_mut().insert((span, found_span)) {
@@ -2892,7 +2976,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         if found.len() != expected.len() {
             let (closure_span, closure_arg_span, found) = found_did
                 .and_then(|did| {
-                    let node = self.tcx.hir().get_if_local(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))
                 })
@@ -2942,7 +3026,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             }) => (
                 fn_decl_span,
                 fn_arg_span,
-                hir.body(body)
+                self.tcx
+                    .hir_body(body)
                     .params
                     .iter()
                     .map(|arg| {
@@ -3204,7 +3289,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                 Some(obligation.cause.body_id)
                             };
                             if let Some(def_id) = def_id
-                                && let Some(generics) = self.tcx.hir().get_generics(def_id)
+                                && let Some(generics) = self.tcx.hir_get_generics(def_id)
                             {
                                 err.span_suggestion_verbose(
                                     generics.tail_span_for_predicate_suggestion(),
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 658fb4009d5..4d87a93be0c 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/mod.rs
@@ -68,8 +68,8 @@ impl<'hir> FindExprBySpan<'hir> {
 impl<'v> Visitor<'v> for FindExprBySpan<'v> {
     type NestedFilter = rustc_middle::hir::nested_filter::OnlyBodies;
 
-    fn nested_visit_map(&mut self) -> Self::Map {
-        self.tcx.hir()
+    fn maybe_tcx(&mut self) -> Self::MaybeTyCtxt {
+        self.tcx
     }
 
     fn visit_expr(&mut self, ex: &'v hir::Expr<'v>) {
@@ -172,8 +172,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             {
                 1
             }
-            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
             ty::PredicateKind::Coerce(_) => 2,
+            ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) => 3,
             _ => 0,
         });
 
@@ -418,7 +418,7 @@ pub fn report_dyn_incompatibility<'tcx>(
     violations: &[DynCompatibilityViolation],
 ) -> Diag<'tcx> {
     let trait_str = tcx.def_path_str(trait_def_id);
-    let trait_span = tcx.hir().get_if_local(trait_def_id).and_then(|node| match node {
+    let trait_span = tcx.hir_get_if_local(trait_def_id).and_then(|node| match node {
         hir::Node::Item(item) => Some(item.ident.span),
         _ => None,
     });
@@ -587,7 +587,7 @@ fn attempt_dyn_to_impl_suggestion(tcx: TyCtxt<'_>, hir_id: Option<hir::HirId>, e
     //   `type Alias = Box<dyn DynIncompatibleTrait>;` to
     //   `type Alias = Box<impl DynIncompatibleTrait>;`
     let Some((_id, first_non_type_parent_node)) =
-        tcx.hir().parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
+        tcx.hir_parent_iter(hir_id).find(|(_id, node)| !matches!(node, hir::Node::Ty(_)))
     else {
         return;
     };
diff --git a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
index 518323f6526..f0c6e51f2a4 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/on_unimplemented.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::fx::FxHashMap;
 use rustc_errors::codes::*;
 use rustc_errors::{ErrorGuaranteed, struct_span_code_err};
 use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::{AttrArgs, AttrKind, Attribute};
+use rustc_hir::{AttrArgs, Attribute};
 use rustc_macros::LintDiagnostic;
 use rustc_middle::bug;
 use rustc_middle::ty::print::PrintTraitRefExt as _;
@@ -622,7 +622,14 @@ impl<'tcx> OnUnimplementedDirective {
         item_def_id: DefId,
     ) -> Result<Option<Self>, ErrorGuaranteed> {
         let result = if let Some(items) = attr.meta_item_list() {
-            Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant)
+            Self::parse(
+                tcx,
+                item_def_id,
+                &items,
+                attr.span(),
+                true,
+                is_diagnostic_namespace_variant,
+            )
         } else if let Some(value) = attr.value_str() {
             if !is_diagnostic_namespace_variant {
                 Ok(Some(OnUnimplementedDirective {
@@ -633,7 +640,7 @@ impl<'tcx> OnUnimplementedDirective {
                         tcx,
                         item_def_id,
                         value,
-                        attr.span,
+                        attr.span(),
                         is_diagnostic_namespace_variant,
                     )?),
                     notes: Vec::new(),
@@ -659,14 +666,14 @@ impl<'tcx> OnUnimplementedDirective {
                 Ok(None)
             }
         } else if is_diagnostic_namespace_variant {
-            match &attr.kind {
-                AttrKind::Normal(p) if !matches!(p.args, AttrArgs::Empty) => {
+            match attr {
+                Attribute::Unparsed(p) if !matches!(p.args, AttrArgs::Empty) => {
                     if let Some(item_def_id) = item_def_id.as_local() {
                         tcx.emit_node_span_lint(
                             UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
-                            attr.span,
-                            MalformedOnUnimplementedAttrLint::new(attr.span),
+                            attr.span(),
+                            MalformedOnUnimplementedAttrLint::new(attr.span()),
                         );
                     }
                 }
@@ -675,7 +682,7 @@ impl<'tcx> OnUnimplementedDirective {
                         tcx.emit_node_span_lint(
                             UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES,
                             tcx.local_def_id_to_hir_id(item_def_id),
-                            attr.span,
+                            attr.span(),
                             MissingOptionsForOnUnimplementedAttr,
                         )
                     }
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 527d2e54e43..c7e71a626dc 100644
--- a/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/error_reporting/traits/suggestions.rs
@@ -790,8 +790,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         }
 
         // Get the name of the callable and the arguments to be used in the suggestion.
-        let hir = self.tcx.hir();
-
         let msg = match def_id_or_name {
             DefIdOrName::DefId(def_id) => match self.tcx.def_kind(def_id) {
                 DefKind::Ctor(CtorOf::Struct, _) => {
@@ -834,7 +832,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 Applicability::HasPlaceholders,
             );
         } else if let DefIdOrName::DefId(def_id) = def_id_or_name {
-            let name = match hir.get_if_local(def_id) {
+            let name = match self.tcx.hir_get_if_local(def_id) {
                 Some(hir::Node::Expr(hir::Expr {
                     kind: hir::ExprKind::Closure(hir::Closure { fn_decl_span, .. }),
                     ..
@@ -878,7 +876,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.remove_mark();
         }
         let mut expr_finder = FindExprBySpan::new(span, self.tcx);
-        let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
+        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
             return;
         };
         expr_finder.visit_expr(body.value);
@@ -950,7 +948,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
     ) -> bool {
         let self_ty = self.resolve_vars_if_possible(trait_pred.self_ty());
         self.enter_forall(self_ty, |ty: Ty<'_>| {
-            let Some(generics) = self.tcx.hir().get_generics(obligation.cause.body_id) else {
+            let Some(generics) = self.tcx.hir_get_generics(obligation.cause.body_id) else {
                 return false;
             };
             let ty::Ref(_, inner_ty, hir::Mutability::Not) = ty.kind() else { return false };
@@ -976,7 +974,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         hir::ExprKind::MethodCall(
                             hir::PathSegment { ident, .. },
                             _receiver,
-                            &[],
+                            [],
                             call_span,
                         ),
                     hir_id,
@@ -1349,8 +1347,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         // Issue #104961, we need to add parentheses properly for compound expressions
                         // for example, `x.starts_with("hi".to_string() + "you")`
                         // should be `x.starts_with(&("hi".to_string() + "you"))`
-                        let Some(body) =
-                            self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id)
+                        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id)
                         else {
                             return false;
                         };
@@ -1449,7 +1446,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             span.remove_mark();
         }
         let mut expr_finder = super::FindExprBySpan::new(span, self.tcx);
-        let Some(body) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else {
+        let Some(body) = self.tcx.hir_maybe_body_owned_by(obligation.cause.body_id) else {
             return false;
         };
         expr_finder.visit_expr(body.value);
@@ -1555,7 +1552,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         obligation: &PredicateObligation<'tcx>,
         err: &mut Diag<'_>,
     ) {
-        let hir = self.tcx.hir();
         if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives()
             && let hir::Node::Expr(expr) = self.tcx.hir_node(*hir_id)
         {
@@ -1565,7 +1561,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             // it is from the local crate.
 
             // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter`
-            if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1)
+            if let Some((_, hir::Node::Expr(await_expr))) = self.tcx.hir_parent_iter(*hir_id).nth(1)
                 && let Some(expr_span) = expr.span.find_ancestor_inside_same_ctxt(await_expr.span)
             {
                 let removal_span = self
@@ -1595,7 +1591,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     && let ty = typeck_results.expr_ty_adjusted(base)
                     && let ty::FnDef(def_id, _args) = ty.kind()
                     && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
-                        hir.get_if_local(*def_id)
+                        self.tcx.hir_get_if_local(*def_id)
                 {
                     let msg = format!("alternatively, consider making `fn {ident}` asynchronous");
                     if vis_span.is_empty() {
@@ -1703,10 +1699,9 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         span: Span,
         trait_pred: ty::PolyTraitPredicate<'tcx>,
     ) -> bool {
-        let hir = self.tcx.hir();
         let node = self.tcx.hir_node_by_def_id(obligation.cause.body_id);
         if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn {sig, body: body_id, .. }, .. }) = node
-            && let hir::ExprKind::Block(blk, _) = &hir.body(*body_id).value.kind
+            && let hir::ExprKind::Block(blk, _) = &self.tcx.hir_body(*body_id).value.kind
             && sig.decl.output.span().overlaps(span)
             && blk.expr.is_none()
             && trait_pred.self_ty().skip_binder().is_unit()
@@ -1769,7 +1764,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         err.children.clear();
 
         let span = obligation.cause.span;
-        let body = self.tcx.hir().body_owned_by(obligation.cause.body_id);
+        let body = self.tcx.hir_body_owned_by(obligation.cause.body_id);
 
         let mut visitor = ReturnsVisitor::default();
         visitor.visit_body(&body);
@@ -2303,7 +2298,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         );
 
         let coroutine_body =
-            coroutine_did.as_local().and_then(|def_id| hir.maybe_body_owned_by(def_id));
+            coroutine_did.as_local().and_then(|def_id| self.tcx.hir_maybe_body_owned_by(def_id));
         let mut visitor = AwaitsVisitor::default();
         if let Some(body) = coroutine_body {
             visitor.visit_body(&body);
@@ -2685,7 +2680,6 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
             | ObligationCauseCode::IntrinsicType
             | ObligationCauseCode::MethodReceiver
             | ObligationCauseCode::ReturnNoExpression
-            | ObligationCauseCode::UnifyReceiver(..)
             | ObligationCauseCode::Misc
             | ObligationCauseCode::WellFormed(..)
             | ObligationCauseCode::MatchImpl(..)
@@ -2790,7 +2784,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                                     generics,
                                     kind: hir::TraitItemKind::Type(bounds, None),
                                     ..
-                                })) = tcx.hir().get_if_local(item_def_id)
+                                })) = tcx.hir_get_if_local(item_def_id)
                                     // Do not suggest relaxing if there is an explicit `Sized` obligation.
                                     && !bounds.iter()
                                         .filter_map(|bound| bound.trait_ref())
@@ -3293,12 +3287,20 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                 let mut parent_trait_pred =
                     self.resolve_vars_if_possible(data.derived.parent_trait_pred);
                 let parent_def_id = parent_trait_pred.def_id();
+                if tcx.is_diagnostic_item(sym::FromResidual, parent_def_id)
+                    && !tcx.features().enabled(sym::try_trait_v2)
+                {
+                    // If `#![feature(try_trait_v2)]` is not enabled, then there's no point on
+                    // talking about `FromResidual<Result<A, B>>`, as the end user has nothing they
+                    // can do about it. As far as they are concerned, `?` is compiler magic.
+                    return;
+                }
                 let self_ty_str =
                     tcx.short_string(parent_trait_pred.skip_binder().self_ty(), err.long_ty_path());
                 let trait_name = parent_trait_pred.print_modifiers_and_trait_path().to_string();
                 let msg = format!("required for `{self_ty_str}` to implement `{trait_name}`");
                 let mut is_auto_trait = false;
-                match tcx.hir().get_if_local(data.impl_or_alias_def_id) {
+                match tcx.hir_get_if_local(data.impl_or_alias_def_id) {
                     Some(Node::Item(hir::Item {
                         kind: hir::ItemKind::Trait(is_auto, ..),
                         ident,
@@ -3423,7 +3425,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         .map_bound(|pred| pred.trait_ref)
                         .print_only_trait_path(),
                 );
-                match tcx.hir().get_if_local(data.impl_def_id) {
+                match tcx.hir_get_if_local(data.impl_def_id) {
                     Some(Node::Item(hir::Item {
                         kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
                         ..
@@ -3564,7 +3566,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     let expr = tcx.hir().expect_expr(hir_id);
                     (expr_ty, expr)
                 } else if let Some(body_id) = tcx.hir_node_by_def_id(body_id).body_id()
-                    && let body = tcx.hir().body(body_id)
+                    && let body = tcx.hir_body(body_id)
                     && let hir::ExprKind::Block(block, _) = body.value.kind
                     && let Some(expr) = block.expr
                     && let Some(expr_ty) = self
@@ -3841,7 +3843,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                             && let hir::ExprKind::Closure(hir::Closure {
                                 body, fn_decl_span, ..
                             }) = value.kind
-                            && let body = tcx.hir().body(*body)
+                            && let body = tcx.hir_body(*body)
                             && !matches!(body.value.kind, hir::ExprKind::Block(..))
                         {
                             // Check if the failed predicate was an expectation of a closure type
@@ -4068,7 +4070,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     && let [arg] = args
                     && let hir::ExprKind::Closure(closure) = arg.kind
                 {
-                    let body = tcx.hir().body(closure.body);
+                    let body = tcx.hir_body(closure.body);
                     if let hir::ExprKind::Block(block, None) = body.value.kind
                         && let None = block.expr
                         && let [.., stmt] = block.stmts
@@ -4114,8 +4116,8 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         let ty::Param(..) = ty.kind() else {
                             continue;
                         };
-                        let hir = tcx.hir();
-                        let node = tcx.hir_node_by_def_id(hir.get_parent_item(expr.hir_id).def_id);
+                        let node =
+                            tcx.hir_node_by_def_id(tcx.hir_get_parent_item(expr.hir_id).def_id);
 
                         let pred = ty::Binder::dummy(ty::TraitPredicate {
                             trait_ref: ty::TraitRef::new(
@@ -4133,7 +4135,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                         };
                         suggest_restriction(
                             tcx,
-                            hir.body_owner_def_id(body_id),
+                            tcx.hir_body_owner_def_id(body_id),
                             generics,
                             &format!("type parameter `{ty}`"),
                             err,
@@ -4355,7 +4357,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
                     term: ty.into(),
                 }),
             ));
-            let body_def_id = self.tcx.hir().enclosing_body_owner(body_id);
+            let body_def_id = self.tcx.hir_enclosing_body_owner(body_id);
             // Add `<ExprTy as Iterator>::Item = _` obligation.
             ocx.register_obligation(Obligation::misc(
                 self.tcx,
@@ -4761,7 +4763,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         {
             let mut sugg_spans =
                 vec![(ret_span, " -> Result<(), Box<dyn std::error::Error>>".to_string())];
-            let body = self.tcx.hir().body(body_id);
+            let body = self.tcx.hir_body(body_id);
             if let hir::ExprKind::Block(b, _) = body.value.kind
                 && b.expr.is_none()
             {
@@ -4807,7 +4809,7 @@ impl<'a, 'tcx> TypeErrCtxt<'a, 'tcx> {
         debug!(?pred, ?item_def_id, ?span);
 
         let (Some(node), true) = (
-            self.tcx.hir().get_if_local(item_def_id),
+            self.tcx.hir_get_if_local(item_def_id),
             self.tcx.is_lang_item(pred.def_id(), LangItem::Sized),
         ) else {
             return;
@@ -5248,7 +5250,7 @@ pub fn suggest_desugaring_async_fn_to_impl_future_in_trait<'tcx>(
 
     // If there's a body, we also need to wrap it in `async {}`
     if let hir::TraitFn::Provided(body) = body {
-        let body = tcx.hir().body(body);
+        let body = tcx.hir_body(body);
         let body_span = body.value.span;
         let body_span_without_braces =
             body_span.with_lo(body_span.lo() + BytePos(1)).with_hi(body_span.hi() - BytePos(1));
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index 62cac5b17bd..23aa3800660 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -509,21 +509,18 @@ impl Subdiagnostic for AddLifetimeParamsSuggestion<'_> {
             let node = self.tcx.hir_node_by_def_id(anon_reg.scope);
             let is_impl = matches!(&node, hir::Node::ImplItem(_));
             let (generics, parent_generics) = match node {
-                hir::Node::Item(&hir::Item {
-                    kind: hir::ItemKind::Fn { ref generics, .. },
-                    ..
-                })
-                | hir::Node::TraitItem(&hir::TraitItem { ref generics, .. })
-                | hir::Node::ImplItem(&hir::ImplItem { ref generics, .. }) => (
+                hir::Node::Item(hir::Item { kind: hir::ItemKind::Fn { generics, .. }, .. })
+                | hir::Node::TraitItem(hir::TraitItem { generics, .. })
+                | hir::Node::ImplItem(hir::ImplItem { generics, .. }) => (
                     generics,
                     match self.tcx.parent_hir_node(self.tcx.local_def_id_to_hir_id(anon_reg.scope))
                     {
                         hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Trait(_, _, ref generics, ..),
+                            kind: hir::ItemKind::Trait(_, _, generics, ..),
                             ..
                         })
                         | hir::Node::Item(hir::Item {
-                            kind: hir::ItemKind::Impl(hir::Impl { ref generics, .. }),
+                            kind: hir::ItemKind::Impl(hir::Impl { generics, .. }),
                             ..
                         }) => Some(generics),
                         _ => None,
@@ -1119,22 +1116,6 @@ impl Subdiagnostic for ReqIntroducedLocations {
     }
 }
 
-pub struct MoreTargeted {
-    pub ident: Symbol,
-}
-
-impl Subdiagnostic for MoreTargeted {
-    fn add_to_diag_with<G: EmissionGuarantee, F: SubdiagMessageOp<G>>(
-        self,
-        diag: &mut Diag<'_, G>,
-        _f: &F,
-    ) {
-        diag.code(E0772);
-        diag.primary_message(fluent::trait_selection_more_targeted);
-        diag.arg("ident", self.ident);
-    }
-}
-
 #[derive(Diagnostic)]
 #[diag(trait_selection_but_needs_to_satisfy, code = E0759)]
 pub struct ButNeedsToSatisfy {
@@ -1151,9 +1132,6 @@ pub struct ButNeedsToSatisfy {
     #[note(trait_selection_introduced_by_bound)]
     pub bound: Option<Span>,
 
-    #[subdiagnostic]
-    pub req_introduces_loc: Option<ReqIntroducedLocations>,
-
     pub has_param_name: bool,
     pub param_name: String,
     pub spans_empty: bool,
@@ -1857,7 +1835,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>(
             new_params += name_as_bounds;
         }
 
-        let Some(generics) = tcx.hir().get_generics(fn_def_id) else {
+        let Some(generics) = tcx.hir_get_generics(fn_def_id) else {
             // This shouldn't happen, but don't ICE.
             return None;
         };
@@ -1880,8 +1858,7 @@ pub fn impl_trait_overcapture_suggestion<'tcx>(
     let opaque_hir_id = tcx.local_def_id_to_hir_id(opaque_def_id);
     // FIXME: This is a bit too conservative, since it ignores parens already written in AST.
     let (lparen, rparen) = match tcx
-        .hir()
-        .parent_iter(opaque_hir_id)
+        .hir_parent_iter(opaque_hir_id)
         .nth(1)
         .expect("expected ty to have a parent always")
         .1
diff --git a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
index b752dbf3093..4601ddf678a 100644
--- a/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
+++ b/compiler/rustc_trait_selection/src/errors/note_and_explain.rs
@@ -26,7 +26,7 @@ impl<'a> DescriptionCtx<'a> {
                     .parent(tcx.generics_of(generic_param_scope).region_param(br, tcx).def_id)
                     .expect_local();
                 let span = if let Some(param) =
-                    tcx.hir().get_generics(scope).and_then(|generics| generics.get_named(br.name))
+                    tcx.hir_get_generics(scope).and_then(|generics| generics.get_named(br.name))
                 {
                     param.span
                 } else {
@@ -48,8 +48,7 @@ impl<'a> DescriptionCtx<'a> {
                     match fr.kind {
                         ty::LateParamRegionKind::Named(_, name) => {
                             let span = if let Some(param) = tcx
-                                .hir()
-                                .get_generics(scope)
+                                .hir_get_generics(scope)
                                 .and_then(|generics| generics.get_named(name))
                             {
                                 param.span
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index 1af383e9200..b235d0da83c 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -20,7 +20,6 @@
 #![feature(associated_type_defaults)]
 #![feature(box_patterns)]
 #![feature(cfg_version)]
-#![feature(extract_if)]
 #![feature(if_let_guard)]
 #![feature(iter_intersperse)]
 #![feature(iterator_try_reduce)]
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index c238e708ab8..704ba6e501d 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -67,7 +67,7 @@ impl<'tcx> ObligationStorage<'tcx> {
         obligations
     }
 
-    fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> {
+    fn unstalled_for_select(&mut self) -> impl Iterator<Item = PredicateObligation<'tcx>> + 'tcx {
         mem::take(&mut self.pending).into_iter()
     }
 
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
index 7364b4aa343..982782bc57c 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill/derive_errors.rs
@@ -7,7 +7,7 @@ use rustc_infer::traits::{
     PredicateObligation, SelectionError,
 };
 use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_middle::ty::{self, Ty, TyCtxt};
 use rustc_middle::{bug, span_bug};
 use rustc_next_trait_solver::solve::{GenerateProofTree, SolverDelegateEvalExt as _};
 use rustc_type_ir::solve::{Goal, NoSolution};
@@ -139,6 +139,7 @@ pub(super) fn fulfillment_error_for_overflow<'tcx>(
     }
 }
 
+#[instrument(level = "debug", skip(infcx), ret)]
 fn find_best_leaf_obligation<'tcx>(
     infcx: &InferCtxt<'tcx>,
     obligation: &PredicateObligation<'tcx>,
@@ -197,6 +198,9 @@ impl<'tcx> BestObligation<'tcx> {
                 candidates.retain(|candidate| candidate.result().is_ok());
             }
             false => {
+                // We always handle rigid alias candidates separately as we may not add them for
+                // aliases whose trait bound doesn't hold.
+                candidates.retain(|c| !matches!(c.kind(), inspect::ProbeKind::RigidAlias { .. }));
                 // If we have >1 candidate, one may still be due to "boring" reasons, like
                 // an alias-relate that failed to hold when deeply evaluated. We really
                 // don't care about reasons like this.
@@ -211,23 +215,12 @@ impl<'tcx> BestObligation<'tcx> {
                                             | GoalSource::AliasBoundConstCondition
                                             | GoalSource::InstantiateHigherRanked
                                             | GoalSource::AliasWellFormed
-                                    ) && match (self.consider_ambiguities, nested_goal.result()) {
-                                        (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity)))
-                                        | (false, Err(_)) => true,
-                                        _ => false,
-                                    }
+                                    ) && nested_goal.result().is_err()
                                 },
                             )
                         })
                     });
                 }
-
-                // Prefer a non-rigid candidate if there is one.
-                if candidates.len() > 1 {
-                    candidates.retain(|candidate| {
-                        !matches!(candidate.kind(), inspect::ProbeKind::RigidAlias { .. })
-                    });
-                }
             }
         }
 
@@ -266,6 +259,90 @@ impl<'tcx> BestObligation<'tcx> {
 
         ControlFlow::Break(self.obligation.clone())
     }
+
+    /// If a normalization of an associated item or a trait goal fails without trying any
+    /// candidates it's likely that normalizing its self type failed. We manually detect
+    /// such cases here.
+    fn detect_error_in_self_ty_normalization(
+        &mut self,
+        goal: &inspect::InspectGoal<'_, 'tcx>,
+        self_ty: Ty<'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        assert!(!self.consider_ambiguities);
+        let tcx = goal.infcx().tcx;
+        if let ty::Alias(..) = self_ty.kind() {
+            let infer_term = goal.infcx().next_ty_var(self.obligation.cause.span);
+            let pred = ty::PredicateKind::AliasRelate(
+                self_ty.into(),
+                infer_term.into(),
+                ty::AliasRelationDirection::Equate,
+            );
+            let obligation =
+                Obligation::new(tcx, self.obligation.cause.clone(), goal.goal().param_env, pred);
+            self.with_derived_obligation(obligation, |this| {
+                goal.infcx().visit_proof_tree_at_depth(
+                    goal.goal().with(tcx, pred),
+                    goal.depth() + 1,
+                    this,
+                )
+            })
+        } else {
+            ControlFlow::Continue(())
+        }
+    }
+
+    /// It is likely that `NormalizesTo` failed without any applicable candidates
+    /// because the alias is not well-formed.
+    ///
+    /// As we only enter `RigidAlias` candidates if the trait bound of the associated type
+    /// holds, we discard these candidates in `non_trivial_candidates` and always manually
+    /// check this here.
+    fn detect_non_well_formed_assoc_item(
+        &mut self,
+        goal: &inspect::InspectGoal<'_, 'tcx>,
+        alias: ty::AliasTerm<'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        let tcx = goal.infcx().tcx;
+        let obligation = Obligation::new(
+            tcx,
+            self.obligation.cause.clone(),
+            goal.goal().param_env,
+            alias.trait_ref(tcx),
+        );
+        self.with_derived_obligation(obligation, |this| {
+            goal.infcx().visit_proof_tree_at_depth(
+                goal.goal().with(tcx, alias.trait_ref(tcx)),
+                goal.depth() + 1,
+                this,
+            )
+        })
+    }
+
+    /// If we have no candidates, then it's likely that there is a
+    /// non-well-formed alias in the goal.
+    fn detect_error_from_empty_candidates(
+        &mut self,
+        goal: &inspect::InspectGoal<'_, 'tcx>,
+    ) -> ControlFlow<PredicateObligation<'tcx>> {
+        let tcx = goal.infcx().tcx;
+        let pred_kind = goal.goal().predicate.kind();
+
+        match pred_kind.no_bound_vars() {
+            Some(ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred))) => {
+                self.detect_error_in_self_ty_normalization(goal, pred.self_ty())?;
+            }
+            Some(ty::PredicateKind::NormalizesTo(pred))
+                if let ty::AliasTermKind::ProjectionTy | ty::AliasTermKind::ProjectionConst =
+                    pred.alias.kind(tcx) =>
+            {
+                self.detect_error_in_self_ty_normalization(goal, pred.alias.self_ty())?;
+                self.detect_non_well_formed_assoc_item(goal, pred.alias)?;
+            }
+            Some(_) | None => {}
+        }
+
+        ControlFlow::Break(self.obligation.clone())
+    }
 }
 
 impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
@@ -277,11 +354,19 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
 
     #[instrument(level = "trace", skip(self, goal), fields(goal = ?goal.goal()))]
     fn visit_goal(&mut self, goal: &inspect::InspectGoal<'_, 'tcx>) -> Self::Result {
-        let candidates = self.non_trivial_candidates(goal);
-        trace!(candidates = ?candidates.iter().map(|c| c.kind()).collect::<Vec<_>>());
+        let tcx = goal.infcx().tcx;
+        // Skip goals that aren't the *reason* for our goal's failure.
+        match (self.consider_ambiguities, goal.result()) {
+            (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
+            _ => return ControlFlow::Continue(()),
+        }
+        let pred_kind = goal.goal().predicate.kind();
 
-        let [candidate] = candidates.as_slice() else {
-            return ControlFlow::Break(self.obligation.clone());
+        let candidates = self.non_trivial_candidates(goal);
+        let candidate = match candidates.as_slice() {
+            [candidate] => candidate,
+            [] => return self.detect_error_from_empty_candidates(goal),
+            _ => return ControlFlow::Break(self.obligation.clone()),
         };
 
         // Don't walk into impls that have `do_not_recommend`.
@@ -291,13 +376,12 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
         } = candidate.kind()
             && goal.infcx().tcx.do_not_recommend_impl(impl_def_id)
         {
+            trace!("#[do_not_recommend] -> exit");
             return ControlFlow::Break(self.obligation.clone());
         }
 
-        let tcx = goal.infcx().tcx;
         // FIXME: Also, what about considering >1 layer up the stack? May be necessary
         // for normalizes-to.
-        let pred_kind = goal.goal().predicate.kind();
         let child_mode = match pred_kind.skip_binder() {
             ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => {
                 ChildMode::Trait(pred_kind.rebind(pred))
@@ -390,12 +474,6 @@ impl<'tcx> ProofTreeVisitor<'tcx> for BestObligation<'tcx> {
                 }
             }
 
-            // Skip nested goals that aren't the *reason* for our goal's failure.
-            match (self.consider_ambiguities, nested_goal.result()) {
-                (true, Ok(Certainty::Maybe(MaybeCause::Ambiguity))) | (false, Err(_)) => {}
-                _ => continue,
-            }
-
             self.with_derived_obligation(obligation, |this| nested_goal.visit_with(this))?;
         }
 
diff --git a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
index 9f4ee54bd4c..4b1bc316d5f 100644
--- a/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
+++ b/compiler/rustc_trait_selection/src/solve/inspect/analyse.rs
@@ -11,12 +11,11 @@
 
 use std::assert_matches::assert_matches;
 
-use rustc_ast_ir::try_visit;
-use rustc_ast_ir::visit::VisitorResult;
 use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
 use rustc_macros::extension;
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::solve::{Certainty, Goal, GoalSource, NoSolution, QueryResult};
+use rustc_middle::ty::visit::{VisitorResult, try_visit};
 use rustc_middle::ty::{TyCtxt, TypeFoldable};
 use rustc_middle::{bug, ty};
 use rustc_next_trait_solver::resolve::EagerResolver;
@@ -300,7 +299,6 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
                         inspect::ProbeKind::NormalizedSelfTyAssembly
                         | inspect::ProbeKind::UnsizeAssembly
                         | inspect::ProbeKind::Root { .. }
-                        | inspect::ProbeKind::TryNormalizeNonRigid { .. }
                         | inspect::ProbeKind::TraitCandidate { .. }
                         | inspect::ProbeKind::OpaqueTypeStorageLookup { .. }
                         | inspect::ProbeKind::RigidAlias { .. } => {
@@ -325,7 +323,6 @@ impl<'a, 'tcx> InspectGoal<'a, 'tcx> {
             // We add a candidate even for the root evaluation if there
             // is only one way to prove a given goal, e.g. for `WellFormed`.
             inspect::ProbeKind::Root { result }
-            | inspect::ProbeKind::TryNormalizeNonRigid { result }
             | inspect::ProbeKind::TraitCandidate { source: _, result }
             | inspect::ProbeKind::OpaqueTypeStorageLookup { result }
             | inspect::ProbeKind::RigidAlias { result } => {
diff --git a/compiler/rustc_trait_selection/src/solve/select.rs b/compiler/rustc_trait_selection/src/solve/select.rs
index b0b6274907d..4437fc5b029 100644
--- a/compiler/rustc_trait_selection/src/solve/select.rs
+++ b/compiler/rustc_trait_selection/src/solve/select.rs
@@ -175,8 +175,7 @@ fn to_selection<'tcx>(
                 span_bug!(span, "didn't expect to select an unknowable candidate")
             }
         },
-        ProbeKind::TryNormalizeNonRigid { result: _ }
-        | ProbeKind::NormalizedSelfTyAssembly
+        ProbeKind::NormalizedSelfTyAssembly
         | ProbeKind::UnsizeAssembly
         | ProbeKind::UpcastProjectionCompatibility
         | ProbeKind::OpaqueTypeStorageLookup { result: _ }
diff --git a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
index 617bc87a9d2..d4502be6ccf 100644
--- a/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
+++ b/compiler/rustc_trait_selection/src/traits/dyn_compatibility.rs
@@ -128,8 +128,7 @@ fn sized_trait_bound_spans<'tcx>(
 }
 
 fn get_sized_bounds(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
-    tcx.hir()
-        .get_if_local(trait_def_id)
+    tcx.hir_get_if_local(trait_def_id)
         .and_then(|node| match node {
             hir::Node::Item(hir::Item {
                 kind: hir::ItemKind::Trait(.., generics, bounds, _),
@@ -187,7 +186,10 @@ fn predicates_reference_self(
 fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span; 1]> {
     tcx.associated_items(trait_def_id)
         .in_definition_order()
+        // We're only looking at associated type bounds
         .filter(|item| item.kind == ty::AssocKind::Type)
+        // Ignore GATs with `Self: Sized`
+        .filter(|item| !tcx.generics_require_sized_self(item.def_id))
         .flat_map(|item| tcx.explicit_item_bounds(item.def_id).iter_identity_copied())
         .filter_map(|(clause, sp)| {
             // Item bounds *can* have self projections, since they never get
@@ -301,7 +303,7 @@ pub fn dyn_compatibility_violations_for_assoc_item(
         ty::AssocKind::Fn => virtual_call_violations_for_method(tcx, trait_def_id, item)
             .into_iter()
             .map(|v| {
-                let node = tcx.hir().get_if_local(item.def_id);
+                let node = tcx.hir_get_if_local(item.def_id);
                 // Get an accurate span depending on the violation.
                 let span = match (&v, node) {
                     (MethodViolationCode::ReferencesSelfInput(Some(span)), _) => *span,
@@ -346,7 +348,7 @@ fn virtual_call_violations_for_method<'tcx>(
             generics,
             kind: hir::TraitItemKind::Fn(sig, _),
             ..
-        })) = tcx.hir().get_if_local(method.def_id).as_ref()
+        })) = tcx.hir_get_if_local(method.def_id).as_ref()
         {
             let sm = tcx.sess.source_map();
             Some((
@@ -380,7 +382,7 @@ fn virtual_call_violations_for_method<'tcx>(
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(sig, _),
                 ..
-            })) = tcx.hir().get_if_local(method.def_id).as_ref()
+            })) = tcx.hir_get_if_local(method.def_id).as_ref()
             {
                 Some(sig.decl.inputs[i].span)
             } else {
@@ -418,7 +420,7 @@ fn virtual_call_violations_for_method<'tcx>(
             let span = if let Some(hir::Node::TraitItem(hir::TraitItem {
                 kind: hir::TraitItemKind::Fn(sig, _),
                 ..
-            })) = tcx.hir().get_if_local(method.def_id).as_ref()
+            })) = tcx.hir_get_if_local(method.def_id).as_ref()
             {
                 Some(sig.decl.inputs[0].span)
             } else {
@@ -536,10 +538,10 @@ fn receiver_for_self_ty<'tcx>(
 /// a pointer.
 ///
 /// In practice, we cannot use `dyn Trait` explicitly in the obligation because it would result in
-/// a new check that `Trait` is dyn-compatible, creating a cycle (until dyn_compatible_for_dispatch
-/// is stabilized, see tracking issue <https://github.com/rust-lang/rust/issues/43561>).
-/// Instead, we fudge a little by introducing a new type parameter `U` such that
+/// a new check that `Trait` is dyn-compatible, creating a cycle.
+/// Instead, we emulate a placeholder by introducing a new type parameter `U` such that
 /// `Self: Unsize<U>` and `U: Trait + ?Sized`, and use `U` in place of `dyn Trait`.
+///
 /// Written as a chalk-style query:
 /// ```ignore (not-rust)
 /// forall (U: Trait + ?Sized) {
@@ -570,8 +572,6 @@ fn receiver_is_dispatchable<'tcx>(
 
     // the type `U` in the query
     // use a bogus type parameter to mimic a forall(U) query using u32::MAX for now.
-    // FIXME(mikeyhew) this is a total hack. Once dyn_compatible_for_dispatch is stabilized, we can
-    // replace this with `dyn Trait`
     let unsized_self_ty: Ty<'tcx> =
         Ty::new_param(tcx, u32::MAX, rustc_span::sym::RustaceansAreAwesome);
 
@@ -696,11 +696,11 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for IllegalSelfTypeVisitor<'tcx> {
                     ControlFlow::Continue(())
                 }
             }
-            ty::Alias(ty::Projection, ref data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
+            ty::Alias(ty::Projection, data) if self.tcx.is_impl_trait_in_trait(data.def_id) => {
                 // We'll deny these later in their own pass
                 ControlFlow::Continue(())
             }
-            ty::Alias(ty::Projection, ref data) => {
+            ty::Alias(ty::Projection, data) => {
                 match self.allow_self_projections {
                     AllowSelfProjections::Yes => {
                         // This is a projected type `<Foo as SomeTrait>::X`.
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index f2d2dd2f3ce..e39f8e673db 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -1,6 +1,5 @@
 use std::marker::PhantomData;
 
-use rustc_data_structures::captures::Captures;
 use rustc_data_structures::obligation_forest::{
     Error, ForestObligation, ObligationForest, ObligationProcessor, Outcome, ProcessResult,
 };
@@ -900,10 +899,10 @@ impl<'a, 'tcx> FulfillProcessor<'a, 'tcx> {
 }
 
 /// Returns the set of inference variables contained in `args`.
-fn args_infer_vars<'a, 'tcx>(
-    selcx: &SelectionContext<'a, 'tcx>,
+fn args_infer_vars<'tcx>(
+    selcx: &SelectionContext<'_, 'tcx>,
     args: ty::Binder<'tcx, GenericArgsRef<'tcx>>,
-) -> impl Iterator<Item = TyOrConstInferVar> + Captures<'tcx> {
+) -> impl Iterator<Item = TyOrConstInferVar> {
     selcx
         .infcx
         .resolve_vars_if_possible(args)
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index 79e178150de..a4b6f330b9d 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -208,7 +208,7 @@ pub fn all_fields_implement_trait<'tcx>(
             }
 
             let field_span = tcx.def_span(field.did);
-            let field_ty_span = match tcx.hir().get_if_local(field.did) {
+            let field_ty_span = match tcx.hir_get_if_local(field.did) {
                 Some(hir::Node::Field(field_def)) => field_def.ty.span,
                 _ => field_span,
             };
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 92098e20448..f04a5feba30 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -2,12 +2,13 @@ use rustc_data_structures::fx::FxHashSet;
 use rustc_infer::traits::query::type_op::DropckOutlives;
 use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
 use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
-use rustc_span::{DUMMY_SP, Span};
+use rustc_span::Span;
 use tracing::{debug, instrument};
 
+use crate::solve::NextSolverError;
 use crate::traits::query::NoSolution;
 use crate::traits::query::normalize::QueryNormalizeExt;
-use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
+use crate::traits::{FromSolverError, Normalized, ObligationCause, ObligationCtxt};
 
 /// This returns true if the type `ty` is "trivial" for
 /// dropck-outlives -- that is, if it doesn't require any types to
@@ -93,6 +94,20 @@ pub fn compute_dropck_outlives_inner<'tcx>(
     goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
     span: Span,
 ) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
+    match compute_dropck_outlives_with_errors(ocx, goal, span) {
+        Ok(r) => Ok(r),
+        Err(_) => Err(NoSolution),
+    }
+}
+
+pub fn compute_dropck_outlives_with_errors<'tcx, E>(
+    ocx: &ObligationCtxt<'_, 'tcx, E>,
+    goal: ParamEnvAnd<'tcx, DropckOutlives<'tcx>>,
+    span: Span,
+) -> Result<DropckOutlivesResult<'tcx>, Vec<E>>
+where
+    E: FromSolverError<'tcx, NextSolverError<'tcx>>,
+{
     let tcx = ocx.infcx.tcx;
     let ParamEnvAnd { param_env, value: DropckOutlives { dropped_ty } } = goal;
 
@@ -149,11 +164,11 @@ pub fn compute_dropck_outlives_inner<'tcx>(
         dtorck_constraint_for_ty_inner(
             tcx,
             ocx.infcx.typing_env(param_env),
-            DUMMY_SP,
+            span,
             depth,
             ty,
             &mut constraints,
-        )?;
+        );
 
         // "outlives" represent types/regions that may be touched
         // by a destructor.
@@ -173,11 +188,20 @@ pub fn compute_dropck_outlives_inner<'tcx>(
         // do not themselves define a destructor", more or less. We have
         // to push them onto the stack to be expanded.
         for ty in constraints.dtorck_types.drain(..) {
-            let Normalized { value: ty, obligations } =
-                ocx.infcx.at(&cause, param_env).query_normalize(ty)?;
-            ocx.register_obligations(obligations);
+            let ty = if let Ok(Normalized { value: ty, obligations }) =
+                ocx.infcx.at(&cause, param_env).query_normalize(ty)
+            {
+                ocx.register_obligations(obligations);
+
+                debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+                ty
+            } else {
+                ocx.deeply_normalize(&cause, param_env, ty)?;
 
-            debug!("dropck_outlives: ty from dtorck_types = {:?}", ty);
+                let errors = ocx.select_where_possible();
+                debug!("normalize errors: {ty} ~> {errors:#?}");
+                return Err(errors);
+            };
 
             match ty.kind() {
                 // All parameters live for the duration of the
@@ -213,14 +237,14 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
     depth: usize,
     ty: Ty<'tcx>,
     constraints: &mut DropckConstraint<'tcx>,
-) -> Result<(), NoSolution> {
+) {
     if !tcx.recursion_limit().value_within_limit(depth) {
         constraints.overflows.push(ty);
-        return Ok(());
+        return;
     }
 
     if trivial_dropck_outlives(tcx, ty) {
-        return Ok(());
+        return;
     }
 
     match ty.kind() {
@@ -244,22 +268,20 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
             // single-element containers, behave like their element
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
                 dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, *ety, constraints)
-            })?;
+            });
         }
 
         ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
             for ty in tys.iter() {
-                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?;
+                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
             }
-            Ok::<_, NoSolution>(())
-        })?,
+        }),
 
         ty::Closure(_, args) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
             for ty in args.as_closure().upvar_tys() {
-                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints)?;
+                dtorck_constraint_for_ty_inner(tcx, typing_env, span, depth + 1, ty, constraints);
             }
-            Ok::<_, NoSolution>(())
-        })?,
+        }),
 
         ty::CoroutineClosure(_, args) => {
             rustc_data_structures::stack::ensure_sufficient_stack(|| {
@@ -271,10 +293,9 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
                         depth + 1,
                         ty,
                         constraints,
-                    )?;
+                    );
                 }
-                Ok::<_, NoSolution>(())
-            })?
+            })
         }
 
         ty::Coroutine(_, args) => {
@@ -313,7 +334,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
 
         ty::Adt(def, args) => {
             let DropckConstraint { dtorck_types, outlives, overflows } =
-                tcx.at(span).adt_dtorck_constraint(def.did())?;
+                tcx.at(span).adt_dtorck_constraint(def.did());
             // FIXME: we can try to recursively `dtorck_constraint_on_ty`
             // there, but that needs some way to handle cycles.
             constraints
@@ -346,9 +367,7 @@ pub fn dtorck_constraint_for_ty_inner<'tcx>(
         ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
             // By the time this code runs, all type variables ought to
             // be fully resolved.
-            return Err(NoSolution);
+            tcx.dcx().span_delayed_bug(span, format!("Unresolved type in dropck: {:?}.", ty));
         }
     }
-
-    Ok(())
 }
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index e8c2528aa6e..2f6bbd7f4cf 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -2,7 +2,7 @@ use std::fmt;
 
 use rustc_middle::traits::ObligationCause;
 use rustc_middle::traits::query::NoSolution;
-pub use rustc_middle::traits::query::type_op::Normalize;
+pub use rustc_middle::traits::query::type_op::{DeeplyNormalize, Normalize};
 use rustc_middle::ty::fold::TypeFoldable;
 use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
 use rustc_span::Span;
@@ -28,12 +28,53 @@ where
     }
 
     fn perform_locally_with_next_solver(
+        _ocx: &ObligationCtxt<'_, 'tcx>,
+        key: ParamEnvAnd<'tcx, Self>,
+        _span: Span,
+    ) -> Result<Self::QueryResponse, NoSolution> {
+        Ok(key.value.value)
+    }
+}
+
+impl<'tcx, T> super::QueryTypeOp<'tcx> for DeeplyNormalize<T>
+where
+    T: Normalizable<'tcx> + 'tcx,
+{
+    type QueryResponse = T;
+
+    fn try_fast_path(_tcx: TyCtxt<'tcx>, key: &ParamEnvAnd<'tcx, Self>) -> Option<T> {
+        if !key.value.value.has_aliases() { Some(key.value.value) } else { None }
+    }
+
+    fn perform_query(
+        tcx: TyCtxt<'tcx>,
+        canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Self>>,
+    ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
+        T::type_op_method(
+            tcx,
+            CanonicalQueryInput {
+                typing_mode: canonicalized.typing_mode,
+                canonical: canonicalized.canonical.unchecked_map(
+                    |ty::ParamEnvAnd { param_env, value }| ty::ParamEnvAnd {
+                        param_env,
+                        value: Normalize { value: value.value },
+                    },
+                ),
+            },
+        )
+    }
+
+    fn perform_locally_with_next_solver(
         ocx: &ObligationCtxt<'_, 'tcx>,
         key: ParamEnvAnd<'tcx, Self>,
         span: Span,
     ) -> Result<Self::QueryResponse, NoSolution> {
-        // FIXME(-Znext-solver): shouldn't be using old normalizer
-        Ok(ocx.normalize(&ObligationCause::dummy_with_span(span), key.param_env, key.value.value))
+        ocx.deeply_normalize(
+            &ObligationCause::dummy_with_span(span),
+            key.param_env,
+            key.value.value,
+        )
+        .map_err(|_| NoSolution)
     }
 }
 
@@ -81,3 +122,14 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
         tcx.type_op_normalize_fn_sig(canonicalized)
     }
 }
+
+/// This impl is not needed, since we never normalize type outlives predicates
+/// in the old solver, but is required by trait bounds to be happy.
+impl<'tcx> Normalizable<'tcx> for ty::PolyTypeOutlivesPredicate<'tcx> {
+    fn type_op_method(
+        _tcx: TyCtxt<'tcx>,
+        _canonicalized: CanonicalQueryInput<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
+    ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
+        unreachable!("we never normalize PolyTypeOutlivesPredicate")
+    }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index e495bdbf782..11b6b826efe 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -102,6 +102,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidate_for_tuple(obligation, &mut candidates);
             } else if tcx.is_lang_item(def_id, LangItem::FnPtrTrait) {
                 self.assemble_candidates_for_fn_ptr_trait(obligation, &mut candidates);
+            } else if tcx.is_lang_item(def_id, LangItem::BikeshedGuaranteedNoDrop) {
+                self.assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
+                    obligation,
+                    &mut candidates,
+                );
             } else {
                 if tcx.is_lang_item(def_id, LangItem::Clone) {
                     // Same builtin conditions as `Copy`, i.e., every type which has builtin support
@@ -854,13 +859,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                         }
 
                         if let Some(principal) = data.principal() {
-                            if !self.infcx.tcx.features().dyn_compatible_for_dispatch() {
-                                principal.with_self_ty(self.tcx(), self_ty)
-                            } else if self.tcx().is_dyn_compatible(principal.def_id()) {
-                                principal.with_self_ty(self.tcx(), self_ty)
-                            } else {
-                                return;
-                            }
+                            principal.with_self_ty(self.tcx(), self_ty)
                         } else {
                             // Only auto trait bounds exist.
                             return;
@@ -920,11 +919,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         //     T: Trait
         // so it seems ok if we (conservatively) fail to accept that `Unsize`
         // obligation above. Should be possible to extend this in the future.
-        let Some(source) = obligation.self_ty().no_bound_vars() else {
+        let Some(trait_pred) = obligation.predicate.no_bound_vars() else {
             // Don't add any candidates if there are bound regions.
             return;
         };
-        let target = obligation.predicate.skip_binder().trait_ref.args.type_at(1);
+        let source = trait_pred.self_ty();
+        let target = trait_pred.trait_ref.args.type_at(1);
 
         debug!(?source, ?target, "assemble_candidates_for_unsizing");
 
@@ -1183,4 +1183,48 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
         }
     }
+
+    fn assemble_candidates_for_bikeshed_guaranteed_no_drop_trait(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+        candidates: &mut SelectionCandidateSet<'tcx>,
+    ) {
+        match obligation.predicate.self_ty().skip_binder().kind() {
+            ty::Ref(..)
+            | ty::Adt(..)
+            | ty::Tuple(_)
+            | ty::Array(..)
+            | ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::Error(_)
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Pat(..)
+            | ty::Dynamic(..)
+            | ty::Str
+            | ty::Slice(_)
+            | ty::Foreign(..)
+            | ty::Alias(..)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
+            | ty::UnsafeBinder(_)
+            | ty::CoroutineWitness(..)
+            | ty::Bound(..) => {
+                candidates.vec.push(BikeshedGuaranteedNoDropCandidate);
+            }
+
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                candidates.ambiguous = true;
+            }
+        }
+    }
 }
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index eb4adde716a..32cbb97e314 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -20,6 +20,7 @@ use rustc_middle::ty::{self, GenericArgsRef, Ty, TyCtxt, Upcast};
 use rustc_middle::{bug, span_bug};
 use rustc_span::def_id::DefId;
 use rustc_type_ir::elaborate;
+use thin_vec::thin_vec;
 use tracing::{debug, instrument};
 
 use super::SelectionCandidate::{self, *};
@@ -130,6 +131,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             TraitUpcastingUnsizeCandidate(idx) => {
                 self.confirm_trait_upcasting_unsize_candidate(obligation, idx)?
             }
+
+            BikeshedGuaranteedNoDropCandidate => {
+                self.confirm_bikeshed_guaranteed_no_drop_candidate(obligation)
+            }
         };
 
         // The obligations returned by confirmation are recursively evaluated
@@ -1346,6 +1351,93 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             _ => bug!("source: {source}, target: {target}"),
         })
     }
+
+    fn confirm_bikeshed_guaranteed_no_drop_candidate(
+        &mut self,
+        obligation: &PolyTraitObligation<'tcx>,
+    ) -> ImplSource<'tcx, PredicateObligation<'tcx>> {
+        let mut obligations = thin_vec![];
+
+        let tcx = self.tcx();
+        let self_ty = obligation.predicate.self_ty();
+        match *self_ty.skip_binder().kind() {
+            // `&mut T` and `&T` always implement `BikeshedGuaranteedNoDrop`.
+            ty::Ref(..) => {}
+            // `ManuallyDrop<T>` always implements `BikeshedGuaranteedNoDrop`.
+            ty::Adt(def, _) if def.is_manually_drop() => {}
+            // Arrays and tuples implement `BikeshedGuaranteedNoDrop` only if
+            // their constituent types implement `BikeshedGuaranteedNoDrop`.
+            ty::Tuple(tys) => {
+                obligations.extend(tys.iter().map(|elem_ty| {
+                    obligation.with(
+                        tcx,
+                        self_ty.rebind(ty::TraitRef::new(
+                            tcx,
+                            obligation.predicate.def_id(),
+                            [elem_ty],
+                        )),
+                    )
+                }));
+            }
+            ty::Array(elem_ty, _) => {
+                obligations.push(obligation.with(
+                    tcx,
+                    self_ty.rebind(ty::TraitRef::new(
+                        tcx,
+                        obligation.predicate.def_id(),
+                        [elem_ty],
+                    )),
+                ));
+            }
+
+            // All other types implement `BikeshedGuaranteedNoDrop` only if
+            // they implement `Copy`. We could be smart here and short-circuit
+            // some trivially `Copy`/`!Copy` types, but there's no benefit.
+            ty::FnDef(..)
+            | ty::FnPtr(..)
+            | ty::Error(_)
+            | ty::Uint(_)
+            | ty::Int(_)
+            | ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+            | ty::Bool
+            | ty::Float(_)
+            | ty::Char
+            | ty::RawPtr(..)
+            | ty::Never
+            | ty::Pat(..)
+            | ty::Dynamic(..)
+            | ty::Str
+            | ty::Slice(_)
+            | ty::Foreign(..)
+            | ty::Adt(..)
+            | ty::Alias(..)
+            | ty::Param(_)
+            | ty::Placeholder(..)
+            | ty::Closure(..)
+            | ty::CoroutineClosure(..)
+            | ty::Coroutine(..)
+            | ty::UnsafeBinder(_)
+            | ty::CoroutineWitness(..)
+            | ty::Bound(..) => {
+                obligations.push(obligation.with(
+                    tcx,
+                    self_ty.map_bound(|ty| {
+                        ty::TraitRef::new(
+                            tcx,
+                            tcx.require_lang_item(LangItem::Copy, Some(obligation.cause.span)),
+                            [ty],
+                        )
+                    }),
+                ));
+            }
+
+            ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+                panic!("unexpected type `{self_ty:?}`")
+            }
+        }
+
+        ImplSource::Builtin(BuiltinImplSource::Misc, obligations)
+    }
 }
 
 /// Compute a goal that some RPITIT (right now, only RPITITs corresponding to Futures)
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6b1e1774f03..436ce3dddd9 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -1949,7 +1949,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
                 | TraitAliasCandidate
                 | TraitUpcastingUnsizeCandidate(_)
                 | BuiltinObjectCandidate
-                | BuiltinUnsizeCandidate => false,
+                | BuiltinUnsizeCandidate
+                | BikeshedGuaranteedNoDropCandidate => false,
                 // Non-global param candidates have already been handled, global
                 // where-bounds get ignored.
                 ParamCandidate(_) | ImplCandidate(_) => true,
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
index f39c611d19f..19d3561dd59 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs
@@ -200,15 +200,12 @@ impl<'tcx> Children {
     }
 }
 
-fn iter_children(children: &Children) -> impl Iterator<Item = DefId> + '_ {
+fn iter_children(children: &Children) -> impl Iterator<Item = DefId> {
     let nonblanket = children.non_blanket_impls.iter().flat_map(|(_, v)| v.iter());
     children.blanket_impls.iter().chain(nonblanket).cloned()
 }
 
-fn filtered_children(
-    children: &mut Children,
-    st: SimplifiedType,
-) -> impl Iterator<Item = DefId> + '_ {
+fn filtered_children(children: &mut Children, st: SimplifiedType) -> impl Iterator<Item = DefId> {
     let nonblanket = children.non_blanket_impls.entry(st).or_default().iter();
     children.blanket_impls.iter().chain(nonblanket).cloned()
 }
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index d30363ec158..15f5cf916a4 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -47,11 +47,11 @@ pub fn expand_trait_aliases<'tcx>(
                     queue.extend(
                         tcx.explicit_super_predicates_of(trait_pred.def_id())
                             .iter_identity_copied()
-                            .map(|(clause, span)| {
+                            .map(|(super_clause, span)| {
                                 let mut spans = spans.clone();
                                 spans.push(span);
                                 (
-                                    clause.instantiate_supertrait(
+                                    super_clause.instantiate_supertrait(
                                         tcx,
                                         clause.kind().rebind(trait_pred.trait_ref),
                                     ),
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index 0024316b877..165174c0bcc 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -196,7 +196,7 @@ fn own_existential_vtable_entries(tcx: TyCtxt<'_>, trait_def_id: DefId) -> &[Def
 fn own_existential_vtable_entries_iter(
     tcx: TyCtxt<'_>,
     trait_def_id: DefId,
-) -> impl Iterator<Item = DefId> + '_ {
+) -> impl Iterator<Item = DefId> {
     let trait_methods = tcx
         .associated_items(trait_def_id)
         .in_definition_order()
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 96051ad0aa5..18906a6a8ce 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -8,8 +8,9 @@ use rustc_middle::ty::{
     self, GenericArg, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeSuperVisitable,
     TypeVisitable, TypeVisitableExt, TypeVisitor,
 };
-use rustc_span::Span;
+use rustc_session::parse::feature_err;
 use rustc_span::def_id::{DefId, LocalDefId};
+use rustc_span::{Span, sym};
 use tracing::{debug, instrument, trace};
 
 use crate::infer::InferCtxt;
@@ -288,7 +289,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
             && let Some(impl_item) =
                 items.iter().find(|item| item.id.owner_id.to_def_id() == impl_item_id)
         {
-            Some(tcx.hir().impl_item(impl_item.id).expect_type().span)
+            Some(tcx.hir_impl_item(impl_item.id).expect_type().span)
         } else {
             None
         }
@@ -704,8 +705,47 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 ));
             }
 
-            ty::Pat(subty, _) => {
+            ty::Pat(subty, pat) => {
                 self.require_sized(subty, ObligationCauseCode::Misc);
+                match *pat {
+                    ty::PatternKind::Range { start, end, include_end: _ } => {
+                        let mut check = |c| {
+                            let cause = self.cause(ObligationCauseCode::Misc);
+                            self.out.push(traits::Obligation::with_depth(
+                                tcx,
+                                cause.clone(),
+                                self.recursion_depth,
+                                self.param_env,
+                                ty::Binder::dummy(ty::PredicateKind::Clause(
+                                    ty::ClauseKind::ConstArgHasType(c, subty),
+                                )),
+                            ));
+                            if !tcx.features().generic_pattern_types() {
+                                if c.has_param() {
+                                    if self.span.is_dummy() {
+                                        self.tcx().dcx().delayed_bug(
+                                            "feature error should be reported elsewhere, too",
+                                        );
+                                    } else {
+                                        feature_err(
+                                            &self.tcx().sess,
+                                            sym::generic_pattern_types,
+                                            self.span,
+                                            "wraparound pattern type ranges cause monomorphization time errors",
+                                        )
+                                        .emit();
+                                    }
+                                }
+                            }
+                        };
+                        if let Some(start) = start {
+                            check(start)
+                        }
+                        if let Some(end) = end {
+                            check(end)
+                        }
+                    }
+                }
             }
 
             ty::Tuple(tys) => {
@@ -841,7 +881,10 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                         ty.map_bound(|ty| {
                             ty::TraitRef::new(
                                 self.tcx(),
-                                self.tcx().require_lang_item(LangItem::Copy, Some(self.span)),
+                                self.tcx().require_lang_item(
+                                    LangItem::BikeshedGuaranteedNoDrop,
+                                    Some(self.span),
+                                ),
                                 [ty],
                             )
                         }),
@@ -861,19 +904,14 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for WfPredicates<'a, 'tcx> {
                 // FIXME(#27579) RFC also considers adding trait
                 // obligations that don't refer to Self and
                 // checking those
-
-                let defer_to_coercion = tcx.features().dyn_compatible_for_dispatch();
-
-                if !defer_to_coercion {
-                    if let Some(principal) = data.principal_def_id() {
-                        self.out.push(traits::Obligation::with_depth(
-                            tcx,
-                            self.cause(ObligationCauseCode::WellFormed(None)),
-                            self.recursion_depth,
-                            self.param_env,
-                            ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
-                        ));
-                    }
+                if let Some(principal) = data.principal_def_id() {
+                    self.out.push(traits::Obligation::with_depth(
+                        tcx,
+                        self.cause(ObligationCauseCode::WellFormed(None)),
+                        self.recursion_depth,
+                        self.param_env,
+                        ty::Binder::dummy(ty::PredicateKind::DynCompatible(principal)),
+                    ));
                 }
             }